Browse Source

Make bottom pagination its own view

pms
Thodoris Tyrovouzis 5 years ago
parent
commit
c6e7c00f93
  1. 7
      app/src/main/java/gr/thmmy/mthmmy/activities/create_pm/CreatePMActivity.java
  2. 11
      app/src/main/java/gr/thmmy/mthmmy/activities/inbox/InboxActivity.java
  3. 6
      app/src/main/java/gr/thmmy/mthmmy/activities/inbox/InboxAdapter.java
  4. 231
      app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicActivity.java
  5. 2
      app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java
  6. 3
      app/src/main/java/gr/thmmy/mthmmy/model/PM.java
  7. 263
      app/src/main/java/gr/thmmy/mthmmy/pagination/BottomPaginationView.java
  8. 59
      app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java
  9. 55
      app/src/main/res/layout/activity_topic.xml
  10. 54
      app/src/main/res/layout/pagination.xml
  11. 6
      build.gradle
  12. 4
      gradle/wrapper/gradle-wrapper.properties

7
app/src/main/java/gr/thmmy/mthmmy/activities/create_pm/CreatePMActivity.java

@ -30,6 +30,10 @@ public class CreatePMActivity extends BaseActivity implements ExternalAsyncTask.
private TextInputLayout subjectInput;
private EmojiKeyboard emojiKeyboard;
private String username, sendPmUrl;
/**
* Used for example in quotes to pre-populate the EditorView with quoted text
*/
private String defaultContent;
public static final String BUNDLE_SEND_PM_URL = "send-pm-url";
public static final String BUNDLE_PM_CONTENT = "pm-content";
@ -42,6 +46,7 @@ public class CreatePMActivity extends BaseActivity implements ExternalAsyncTask.
Intent callingIntent = getIntent();
username = callingIntent.getStringExtra(ProfileActivity.BUNDLE_PROFILE_USERNAME);
sendPmUrl = callingIntent.getStringExtra(BUNDLE_SEND_PM_URL);
defaultContent = callingIntent.getStringExtra(BUNDLE_PM_CONTENT);
//Initialize toolbar
toolbar = findViewById(R.id.toolbar);
@ -86,6 +91,8 @@ public class CreatePMActivity extends BaseActivity implements ExternalAsyncTask.
sendPMTask.execute(sendPmUrl, subjectInput.getEditText().getText().toString(),
contentEditor.getText().toString());
});
if (defaultContent != null)
contentEditor.setText(defaultContent);
}
@Override

11
app/src/main/java/gr/thmmy/mthmmy/activities/inbox/InboxActivity.java

@ -2,7 +2,12 @@ package gr.thmmy.mthmmy.activities.inbox;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageButton;
import android.widget.TextView;
import android.widget.Toast;
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.ViewModelProvider;
import androidx.lifecycle.ViewModelProviders;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
@ -46,7 +51,7 @@ public class InboxActivity extends BaseActivity {
inboxAdapter = new InboxAdapter(this);
pmRecyclerview.setAdapter(inboxAdapter);
inboxViewModel = ViewModelProviders.of(this).get(InboxViewModel.class);
inboxViewModel =new ViewModelProvider(this).get(InboxViewModel.class);
subscribeUI();
inboxViewModel.loadInbox();
@ -60,7 +65,9 @@ public class InboxActivity extends BaseActivity {
Timber.i("Successfully loaded inbox");
inboxAdapter.notifyDataSetChanged();
} else {
Timber.w("Failed to load inbox");
Toast.makeText(this, "Failed to load inbox", Toast.LENGTH_SHORT).show();
finish();
}
});
}

6
app/src/main/java/gr/thmmy/mthmmy/activities/inbox/InboxAdapter.java

@ -228,11 +228,7 @@ public class InboxAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
quoteButton.setCompoundDrawablesRelativeWithIntrinsicBounds(quoteDrawable, null, null, null);
quoteButton.setOnClickListener(v -> {
Toast.makeText(context, "TODO", Toast.LENGTH_SHORT).show();
// TODO: Create quote PM task
Intent sendPMIntent = new Intent(context, CreatePMActivity.class);
sendPMIntent.putExtra(CreatePMActivity.BUNDLE_SEND_PM_URL, currentPM.getQuoteUrl());
context.startActivity(sendPMIntent);
popUp.dismiss();
// TODO: Create delete PM task
});
final TextView replyButton = popupContent.findViewById(R.id.pm_reply_button);

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

@ -1,17 +1,14 @@
package gr.thmmy.mthmmy.activities.topic;
import android.annotation.SuppressLint;
import android.app.NotificationManager;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Rect;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.SpannableStringBuilder;
@ -21,10 +18,8 @@ import android.text.style.ForegroundColorSpan;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
@ -33,7 +28,7 @@ import android.widget.Toast;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.core.content.res.ResourcesCompat;
import androidx.lifecycle.ViewModelProviders;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
@ -54,6 +49,7 @@ 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.pagination.BottomPaginationView;
import gr.thmmy.mthmmy.utils.CustomLinearLayoutManager;
import gr.thmmy.mthmmy.utils.HTMLUtils;
import gr.thmmy.mthmmy.utils.NetworkResultCodes;
@ -93,35 +89,9 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo
//Reply related
private FloatingActionButton replyFAB;
//Topic's pages related
//Page select related
/**
* Used for handling bottom navigation bar's buttons long click user interactions
*/
private final Handler repeatUpdateHandler = new Handler();
/**
* Holds the initial time delay before a click on bottom navigation bar is considered long
*/
private final long INITIAL_DELAY = 500;
private boolean autoIncrement = false;
private boolean autoDecrement = false;
/**
* Holds the number of pages to be added or subtracted from current page on each step while a
* long click is held in either next or previous buttons
*/
private static final int SMALL_STEP = 1;
/**
* Holds the number of pages to be added or subtracted from current page on each step while a
* long click is held in either first or last buttons
*/
private static final int LARGE_STEP = 10;
//Bottom navigation bar graphics related
private LinearLayout bottomNavBar;
private ImageButton firstPage;
private ImageButton previousPage;
private TextView pageIndicator;
private ImageButton nextPage;
private ImageButton lastPage;
private BottomPaginationView bottomPagination;
private Snackbar snackbar;
private TopicViewModel viewModel;
private EmojiKeyboard emojiKeyboard;
@ -139,7 +109,7 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_topic);
// get TopicViewModel instance
viewModel = ViewModelProviders.of(this).get(TopicViewModel.class);
viewModel = new ViewModelProvider(this).get(TopicViewModel.class);
subscribeUI();
Bundle extras = getIntent().getExtras();
@ -191,7 +161,6 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo
replyFAB = findViewById(R.id.topic_fab);
replyFAB.hide();
replyFAB.setTag(false);
bottomNavBar = findViewById(R.id.bottom_navigation_bar);
if (!sessionManager.isLoggedIn()) {
replyFAB.hide();
replyFAB.setTag(false);
@ -204,18 +173,8 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo
}
//Sets bottom navigation bar
firstPage = findViewById(R.id.page_first_button);
previousPage = findViewById(R.id.page_previous_button);
pageIndicator = findViewById(R.id.page_indicator);
nextPage = findViewById(R.id.page_next_button);
lastPage = findViewById(R.id.page_last_button);
initDecrementButton(firstPage, LARGE_STEP);
initDecrementButton(previousPage, SMALL_STEP);
initIncrementButton(nextPage, SMALL_STEP);
initIncrementButton(lastPage, LARGE_STEP);
paginationEnabled(false);
bottomPagination = findViewById(R.id.bottom_pagination);
bottomPagination.setOnPageRequestedListener(viewModel);
Timber.i("Starting initial topic load");
viewModel.loadUrl(topicPageUrl);
@ -291,7 +250,7 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo
viewModel.setWritingReply(false);
replyFAB.show();
replyFAB.setTag(true);
bottomNavBar.setVisibility(View.VISIBLE);
bottomPagination.setVisibility(View.VISIBLE);
return;
} else if (viewModel.isEditingPost()) {
((Post) topicItems.get(viewModel.getPostBeingEditedPosition())).setPostType(Post.TYPE_POST);
@ -300,7 +259,7 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo
viewModel.setEditingPost(false);
replyFAB.show();
replyFAB.setTag(true);
bottomNavBar.setVisibility(View.VISIBLE);
bottomPagination.setVisibility(View.VISIBLE);
return;
}
super.onBackPressed();
@ -340,152 +299,6 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo
recyclerView.scrollToPosition(position);
}
//--------------------------------------BOTTOM NAV BAR METHODS----------------------------------
/**
* This class is used to implement the repetitive incrementPageRequestValue/decrementPageRequestValue
* of page value when long pressing one of the page navigation buttons.
*/
private class RepetitiveUpdater implements Runnable {
private final int step;
/**
* @param step number of pages to add/subtract on each repetition
*/
RepetitiveUpdater(int step) {
this.step = step;
}
public void run() {
long REPEAT_DELAY = 250;
if (autoIncrement) {
viewModel.incrementPageRequestValue(step, false);
repeatUpdateHandler.postDelayed(new RepetitiveUpdater(step), REPEAT_DELAY);
} else if (autoDecrement) {
viewModel.decrementPageRequestValue(step, false);
repeatUpdateHandler.postDelayed(new RepetitiveUpdater(step), REPEAT_DELAY);
}
}
}
private void paginationEnabled(boolean enabled) {
firstPage.setEnabled(enabled);
previousPage.setEnabled(enabled);
nextPage.setEnabled(enabled);
lastPage.setEnabled(enabled);
}
private void paginationDisable(View exception) {
if (exception == firstPage) {
previousPage.setEnabled(false);
nextPage.setEnabled(false);
lastPage.setEnabled(false);
} else if (exception == previousPage) {
firstPage.setEnabled(false);
nextPage.setEnabled(false);
lastPage.setEnabled(false);
} else if (exception == nextPage) {
firstPage.setEnabled(false);
previousPage.setEnabled(false);
lastPage.setEnabled(false);
} else if (exception == lastPage) {
firstPage.setEnabled(false);
previousPage.setEnabled(false);
nextPage.setEnabled(false);
} else {
paginationEnabled(false);
}
}
@SuppressLint("ClickableViewAccessibility")
private void initIncrementButton(ImageButton increment, final int step) {
// Increment once for a click
increment.setOnClickListener(v -> {
if (!autoIncrement && step == LARGE_STEP) {
viewModel.setPageIndicatorIndex(viewModel.getPageCount(), true);
} else if (!autoIncrement) {
viewModel.incrementPageRequestValue(step, true);
}
});
// Auto increment for a long click
increment.setOnLongClickListener(
arg0 -> {
paginationDisable(arg0);
autoIncrement = true;
repeatUpdateHandler.postDelayed(new RepetitiveUpdater(step), INITIAL_DELAY);
return false;
}
);
// When the button is released
increment.setOnTouchListener(new View.OnTouchListener() {
private Rect rect;
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
rect = new Rect(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
} else if (rect != null && event.getAction() == MotionEvent.ACTION_UP && autoIncrement) {
autoIncrement = false;
paginationEnabled(true);
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;
viewModel.setPageIndicatorIndex(viewModel.getCurrentPageIndex(), false);
paginationEnabled(true);
}
}
return false;
}
});
}
@SuppressLint("ClickableViewAccessibility")
private void initDecrementButton(ImageButton decrement, final int step) {
// Decrement once for a click
decrement.setOnClickListener(v -> {
if (!autoDecrement && step == LARGE_STEP) {
viewModel.setPageIndicatorIndex(1, true);
} else if (!autoDecrement) {
viewModel.decrementPageRequestValue(step, true);
}
});
// Auto decrement for a long click
decrement.setOnLongClickListener(
arg0 -> {
paginationDisable(arg0);
autoDecrement = true;
repeatUpdateHandler.postDelayed(new RepetitiveUpdater(step), INITIAL_DELAY);
return false;
}
);
// When the button is released
decrement.setOnTouchListener(new View.OnTouchListener() {
private Rect rect;
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
rect = new Rect(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
} else if (event.getAction() == MotionEvent.ACTION_UP && autoDecrement) {
autoDecrement = false;
paginationEnabled(true);
viewModel.loadPageIndicated();
} else if (event.getAction() == MotionEvent.ACTION_MOVE) {
if (rect != null &&
!rect.contains(v.getLeft() + (int) event.getX(), v.getTop() + (int) event.getY())) {
autoIncrement = false;
viewModel.setPageIndicatorIndex(viewModel.getCurrentPageIndex(), false);
paginationEnabled(true);
}
}
return false;
}
});
}
//------------------------------------BOTTOM NAV BAR METHODS END------------------------------------
/**
@ -538,7 +351,7 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo
Timber.i("Post reply successful");
replyFAB.show();
replyFAB.setTag(true);
bottomNavBar.setVisibility(View.VISIBLE);
bottomPagination.setVisibility(View.VISIBLE);
viewModel.setWritingReply(false);
SharedPreferences drafts = getSharedPreferences(getString(R.string.pref_topic_drafts_key),
@ -615,7 +428,7 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo
topicAdapter.notifyItemChanged(position);
replyFAB.show();
replyFAB.setTag(true);
bottomNavBar.setVisibility(View.VISIBLE);
bottomPagination.setVisibility(View.VISIBLE);
viewModel.setEditingPost(false);
viewModel.reloadPage();
} else {
@ -664,8 +477,11 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo
// observe the changes in data
viewModel.getPageIndicatorIndex().observe(this, pageIndicatorIndex -> {
if (pageIndicatorIndex == null) return;
pageIndicator.setText(String.valueOf(pageIndicatorIndex) + "/" +
String.valueOf(viewModel.getPageCount()));
bottomPagination.setIndicatedPageIndex(pageIndicatorIndex);
});
viewModel.getPageCount().observe(this, pageCount -> {
if (pageCount == null) return;
bottomPagination.setTotalPageCount(pageCount);
});
viewModel.getTopicTitle().observe(this, newTopicTitle -> {
if (newTopicTitle == null) return;
@ -674,7 +490,7 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo
});
viewModel.getPageTopicId().observe(this, pageTopicId -> {
if (pageTopicId == null) return;
if (viewModel.getCurrentPageIndex() == viewModel.getPageCount()) {
if (viewModel.getCurrentPageIndex() == viewModel.getPageCount().getValue()) {
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (notificationManager != null)
notificationManager.cancel(NEW_POST_TAG, pageTopicId);
@ -696,6 +512,7 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo
topicItems.addAll(postList);
topicAdapter.notifyDataSetChanged();
});
// Scroll to position does not work because WebView size is unknown initially
/*viewModel.getFocusedPostIndex().observe(this, focusedPostIndex -> {
if (focusedPostIndex == null) return;
recyclerView.scrollToPosition(focusedPostIndex);
@ -706,7 +523,7 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo
switch (resultCode) {
case SUCCESS:
Timber.i("Successfully loaded a topic");
paginationEnabled(true);
bottomPagination.setEnabled(true);
break;
case NETWORK_ERROR:
Timber.w("Network error on loaded page");
@ -731,7 +548,7 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo
});
} else {
// a page has already been loaded
viewModel.setPageIndicatorIndex(viewModel.getCurrentPageIndex(), false);
bottomPagination.setIndicatedPageIndex(viewModel.getCurrentPageIndex());
snackbar = Snackbar.make(findViewById(R.id.main_content),
R.string.generic_network_error, Snackbar.LENGTH_INDEFINITE);
snackbar.setAction(R.string.retry, view -> viewModel.reloadPage());
@ -773,7 +590,7 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo
recyclerView.scrollToPosition(topicItems.size() - 1);
replyFAB.hide();
replyFAB.setTag(false);
bottomNavBar.setVisibility(View.GONE);
bottomPagination.setVisibility(View.GONE);
} else {
Timber.i("Prepare for reply unsuccessful");
Snackbar.make(findViewById(R.id.main_content), getString(R.string.generic_network_error), Snackbar.LENGTH_SHORT).show();
@ -789,7 +606,7 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo
recyclerView.scrollToPosition(result.getPosition());
replyFAB.hide();
replyFAB.setTag(false);
bottomNavBar.setVisibility(View.GONE);
bottomPagination.setVisibility(View.GONE);
} else {
Timber.i("Prepare for edit unsuccessful");
Snackbar.make(findViewById(R.id.main_content), getString(R.string.generic_network_error), Snackbar.LENGTH_SHORT).show();
@ -797,9 +614,11 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo
});
}
/**This method sets a long click listener on the title of the topic. Once the
/**
* This method sets a long click listener on the title of the topic. Once the
* listener gets triggered, it copies the link url of the topic in the clipboard.
* This method is getting called on the onCreate() of the TopicActivity*/
* This method is getting called on the onCreate() of the TopicActivity
*/
void setToolbarOnLongClickListener(String url) {
toolbar.setOnLongClickListener(view -> {
//Try to set the clipboard text

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

@ -968,7 +968,7 @@ class TopicAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
//Checks if the page to be loaded is the one already shown
if (uriString.contains(StringUtils.getBaseURL(viewModel.getTopicUrl()))) {
if (uriString.contains("topicseen#new") || uriString.contains("#new")) {
if (viewModel.getCurrentPageIndex() == viewModel.getPageCount()) {
if (viewModel.getCurrentPageIndex() == viewModel.getPageCount().getValue()) {
//same page
postFocusListener.onPostFocusChange(getItemCount() - 1);
Timber.e("new");

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

@ -1,5 +1,8 @@
package gr.thmmy.mthmmy.model;
import gr.thmmy.mthmmy.utils.parsing.StringUtils;
import gr.thmmy.mthmmy.utils.parsing.ThmmyDateTimeParser;
public class PM {
private String thumbnailUrl;

263
app/src/main/java/gr/thmmy/mthmmy/pagination/BottomPaginationView.java

@ -0,0 +1,263 @@
package gr.thmmy.mthmmy.pagination;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Rect;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.Nullable;
import gr.thmmy.mthmmy.R;
public class BottomPaginationView extends LinearLayout {
/**
* Holds the initial time delay before a click on bottom navigation bar is considered long
*/
private final long INITIAL_DELAY = 500;
private boolean autoIncrement = false;
private boolean autoDecrement = false;
/**
* Holds the number of pages to be added or subtracted from current page on each step while a
* long click is held in either next or previous buttons
*/
private static final int SMALL_STEP = 1;
/**
* Holds the number of pages to be added or subtracted from current page on each step while a
* long click is held in either first or last buttons
*/
private static final int LARGE_STEP = 10;
/**
* Used for handling bottom navigation bar's buttons long click user interactions
*/
private final Handler repeatUpdateHandler = new Handler();
private ImageButton firstPage, previousPage, nextPage, lastPage;
private TextView pageIndicator;
private int onDownPageIndex, indicatorPageIndex, totalPageCount;
private OnPageRequestedListener onPageRequestedListener;
public interface OnPageRequestedListener {
void onPageRequested(int index);
}
public BottomPaginationView(Context context) {
this(context, null);
}
public BottomPaginationView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
LayoutInflater inflater = LayoutInflater.from(context);
inflater.inflate(R.layout.pagination, this, true);
firstPage = findViewById(R.id.page_first_button);
previousPage = findViewById(R.id.page_previous_button);
pageIndicator = findViewById(R.id.page_indicator);
nextPage = findViewById(R.id.page_next_button);
lastPage = findViewById(R.id.page_last_button);
initDecrementButton(firstPage, LARGE_STEP);
initDecrementButton(previousPage, SMALL_STEP);
initIncrementButton(nextPage, SMALL_STEP);
initIncrementButton(lastPage, LARGE_STEP);
}
public void setOnPageRequestedListener(OnPageRequestedListener onPageRequestedListener) {
this.onPageRequestedListener = onPageRequestedListener;
}
public boolean setIndicatedPageIndex(int index) {
if (index != indicatorPageIndex) {
this.indicatorPageIndex = index;
updateUI();
return true;
} else return false;
}
public void setTotalPageCount(int totalPageCount) {
this.totalPageCount = totalPageCount;
updateUI();
}
public void updateUI() {
pageIndicator.setText(indicatorPageIndex + "/" + totalPageCount);
}
/**
* This class is used to implement the repetitive incrementPageRequestValue/decrementPageRequestValue
* of page value when long pressing one of the page navigation buttons.
*/
private class RepetitiveUpdater implements Runnable {
private final int step;
/**
* @param step number of pages to add/subtract on each repetition
*/
RepetitiveUpdater(int step) {
this.step = step;
}
public void run() {
long REPEAT_DELAY = 250;
if (autoIncrement) {
setIndicatedPageIndex(indicatorPageIndex+step);
repeatUpdateHandler.postDelayed(new BottomPaginationView.RepetitiveUpdater(step), REPEAT_DELAY);
} else if (autoDecrement) {
setIndicatedPageIndex(indicatorPageIndex-step);
repeatUpdateHandler.postDelayed(new BottomPaginationView.RepetitiveUpdater(step), REPEAT_DELAY);
}
}
}
public boolean incrementPageIndicator(int step) {
int oldIndicatorIndex = indicatorPageIndex;
if (oldIndicatorIndex <= totalPageCount - step)
setIndicatedPageIndex(indicatorPageIndex + step);
else
setIndicatedPageIndex(totalPageCount);
return oldIndicatorIndex != indicatorPageIndex;
}
public boolean decrementPageIndicator(int step) {
int oldIndicatorIndex = indicatorPageIndex;
if (oldIndicatorIndex > step)
setIndicatedPageIndex(indicatorPageIndex - step);
else
setIndicatedPageIndex(1);
return oldIndicatorIndex != indicatorPageIndex;
}
@SuppressLint("ClickableViewAccessibility")
private void initIncrementButton(ImageButton increment, final int step) {
// Increment once for a click
increment.setOnClickListener(v -> {
if (!autoIncrement && step == LARGE_STEP) {
boolean indicatorChanged = setIndicatedPageIndex(totalPageCount);
if (indicatorChanged) onPageRequestedListener.onPageRequested(indicatorPageIndex);
} else if (!autoIncrement) {
boolean indicatorChanged = incrementPageIndicator(1);
if (indicatorChanged) onPageRequestedListener.onPageRequested(indicatorPageIndex);
}
});
// Auto increment for a long click
increment.setOnLongClickListener(
arg0 -> {
paginationDisable(arg0);
autoIncrement = true;
repeatUpdateHandler.postDelayed(new BottomPaginationView.RepetitiveUpdater(step), INITIAL_DELAY);
return false;
}
);
// When the button is released
increment.setOnTouchListener(new View.OnTouchListener() {
private Rect rect;
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
onDownPageIndex = indicatorPageIndex;
rect = new Rect(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
} else if (rect != null && event.getAction() == MotionEvent.ACTION_UP && autoIncrement) {
autoIncrement = false;
paginationEnabled(true);
onPageRequestedListener.onPageRequested(indicatorPageIndex);
} else if (rect != null && event.getAction() == MotionEvent.ACTION_MOVE) {
if (!rect.contains(v.getLeft() + (int) event.getX(), v.getTop() + (int) event.getY())) {
autoIncrement = false;
setIndicatedPageIndex(onDownPageIndex);
paginationEnabled(true);
}
}
return false;
}
});
}
@SuppressLint("ClickableViewAccessibility")
private void initDecrementButton(ImageButton decrement, final int step) {
// Decrement once for a click
decrement.setOnClickListener(v -> {
if (!autoDecrement && step == LARGE_STEP) {
boolean indicatorChanged = setIndicatedPageIndex(1);
if (indicatorChanged) onPageRequestedListener.onPageRequested(indicatorPageIndex);
} else if (!autoDecrement) {
boolean indicatorChanged = decrementPageIndicator(1);
if (indicatorChanged) onPageRequestedListener.onPageRequested(indicatorPageIndex);
}
});
// Auto decrement for a long click
decrement.setOnLongClickListener(
arg0 -> {
paginationDisable(arg0);
autoDecrement = true;
repeatUpdateHandler.postDelayed(new RepetitiveUpdater(step), INITIAL_DELAY);
return false;
}
);
// When the button is released
decrement.setOnTouchListener(new View.OnTouchListener() {
private Rect rect;
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
onDownPageIndex = indicatorPageIndex;
rect = new Rect(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
} else if (event.getAction() == MotionEvent.ACTION_UP && autoDecrement) {
autoDecrement = false;
paginationEnabled(true);
onPageRequestedListener.onPageRequested(indicatorPageIndex);
} else if (event.getAction() == MotionEvent.ACTION_MOVE) {
if (rect != null &&
!rect.contains(v.getLeft() + (int) event.getX(), v.getTop() + (int) event.getY())) {
autoIncrement = false;
setIndicatedPageIndex(onDownPageIndex);
paginationEnabled(true);
}
}
return false;
}
});
}
public void paginationDisable(View exception) {
if (exception == firstPage) {
previousPage.setEnabled(false);
nextPage.setEnabled(false);
lastPage.setEnabled(false);
} else if (exception == previousPage) {
firstPage.setEnabled(false);
nextPage.setEnabled(false);
lastPage.setEnabled(false);
} else if (exception == nextPage) {
firstPage.setEnabled(false);
previousPage.setEnabled(false);
lastPage.setEnabled(false);
} else if (exception == lastPage) {
firstPage.setEnabled(false);
previousPage.setEnabled(false);
nextPage.setEnabled(false);
} else {
paginationEnabled(false);
}
}
public void paginationEnabled(boolean enabled) {
firstPage.setEnabled(enabled);
previousPage.setEnabled(enabled);
nextPage.setEnabled(enabled);
lastPage.setEnabled(enabled);
}
}

59
app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java

@ -28,6 +28,7 @@ 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.pagination.BottomPaginationView;
import gr.thmmy.mthmmy.session.SessionManager;
import gr.thmmy.mthmmy.utils.ExternalAsyncTask;
import gr.thmmy.mthmmy.utils.NetworkTask;
@ -35,7 +36,8 @@ import gr.thmmy.mthmmy.utils.parsing.StringUtils;
import timber.log.Timber;
public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTaskCompleted,
PrepareForReplyTask.OnPrepareForReplyFinished, PrepareForEditTask.OnPrepareEditFinished {
PrepareForReplyTask.OnPrepareForReplyFinished, PrepareForEditTask.OnPrepareEditFinished,
BottomPaginationView.OnPageRequestedListener {
/**
* topic state
*/
@ -76,6 +78,7 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa
* navigation bar occurs, aka the value that the page indicator shows
*/
private MutableLiveData<Integer> pageIndicatorIndex = new MutableLiveData<>();
private MutableLiveData<Integer> pageCount = new MutableLiveData<>();
private MutableLiveData<String> replyPageUrl = new MutableLiveData<>();
private MutableLiveData<Integer> pageTopicId = new MutableLiveData<>();
@ -87,7 +90,6 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa
private MutableLiveData<String> topicViewers = new MutableLiveData<>();
private String topicUrl;
private int currentPageIndex;
private int pageCount;
private MutableLiveData<PrepareForReplyResult> prepareForReplyResult = new MutableLiveData<>();
private MutableLiveData<PrepareForEditResult> prepareForEditResult = new MutableLiveData<>();
@ -126,7 +128,13 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa
currentTopicTask.execute(StringUtils.getBaseURL(topicUrl) + "." + currentPageIndex * 15);
}
public void loadPageIndicated() {
@Override
public void onPageRequested(int index) {
pageIndicatorIndex.setValue(index);
loadPageIndicated();
}
private void loadPageIndicated() {
if (pageIndicatorIndex.getValue() == null)
throw new NullPointerException("No page has been loaded yet!");
int pageRequested = pageIndicatorIndex.getValue() - 1;
@ -172,10 +180,14 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa
}
public void prepareForReply() {
if (replyPageUrl.getValue() == null)
if (replyPageUrl.getValue() == null || pageCount.getValue() == null || pageIndicatorIndex.getValue() ==null)
throw new NullPointerException("Topic task has not finished yet!");
stopLoading();
setPageIndicatorIndex(pageCount, true);
// go to last page for reply
if (currentPageIndex != pageCount.getValue()) {
this.pageIndicatorIndex.setValue(pageCount.getValue());
loadPageIndicated();
}
Timber.i("Preparing for reply");
currentPrepareForReplyTask = new PrepareForReplyTask(prepareForReplyCallbacks, this,
replyPageUrl.getValue());
@ -252,9 +264,10 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa
// callbacks for viewmodel
@Override
public void onTopicTaskCompleted(TopicTaskResult result) {
//sets Data
if (result.getResultCode() == TopicTask.ResultCode.SUCCESS) {
currentPageIndex = result.getCurrentPageIndex();
pageCount = result.getPageCount();
pageCount.setValue(result.getPageCount());
topicTreeAndMods.setValue(result.getTopicTreeAndMods());
topicViewers.setValue(result.getTopicViewers());
pageTopicId.setValue(result.getLoadedPageTopicId());
@ -267,6 +280,7 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa
for (int i = 0; i < result.getNewPostsList().size(); i++)
isUserExtraInfoVisibile.add(false);
}
// see also callback in TopicActivity, sets UI
topicTaskResultCode.setValue(result.getResultCode());
}
@ -281,36 +295,6 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa
prepareForEditResult.setValue(result);
}
public void incrementPageRequestValue(int step, boolean changePage) {
if (pageIndicatorIndex.getValue() == null)
throw new NullPointerException("No page has been loaded yet!");
int oldIndicatorIndex = pageIndicatorIndex.getValue();
if (oldIndicatorIndex <= pageCount - step)
pageIndicatorIndex.setValue(pageIndicatorIndex.getValue() + step);
else
pageIndicatorIndex.setValue(pageCount);
if (changePage && oldIndicatorIndex != pageIndicatorIndex.getValue()) loadPageIndicated();
}
public void decrementPageRequestValue(int step, boolean changePage) {
if (pageIndicatorIndex.getValue() == null)
throw new NullPointerException("No page has been loaded yet!");
int oldIndicatorIndex = pageIndicatorIndex.getValue();
if (oldIndicatorIndex > step)
pageIndicatorIndex.setValue(pageIndicatorIndex.getValue() - step);
else
pageIndicatorIndex.setValue(1);
if (changePage && oldIndicatorIndex != pageIndicatorIndex.getValue()) loadPageIndicated();
}
public void setPageIndicatorIndex(int pageIndicatorIndex, boolean changePage) {
if (this.pageIndicatorIndex.getValue() == null)
throw new NullPointerException("No page has been loaded yet!");
int oldIndicatorIndex = this.pageIndicatorIndex.getValue();
this.pageIndicatorIndex.setValue(pageIndicatorIndex);
if (changePage && oldIndicatorIndex != this.pageIndicatorIndex.getValue()) loadPageIndicated();
}
// <-------------Just getters, setters and helper methods below here---------------->
public int getTopicId() {
@ -465,8 +449,7 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa
return currentPageIndex;
}
public int getPageCount() {
if (pageCount == 0) throw new NullPointerException("No page has been loaded yet!");
public MutableLiveData<Integer> getPageCount() {
return pageCount;
}

55
app/src/main/res/layout/activity_topic.xml

@ -71,63 +71,14 @@
android:visibility="gone" />
</RelativeLayout>
<LinearLayout
android:id="@+id/bottom_navigation_bar"
<gr.thmmy.mthmmy.pagination.BottomPaginationView
android:id="@+id/bottom_pagination"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_gravity="bottom|end"
android:background="@color/primary"
app:elevation="8dp"
app:layout_behavior="gr.thmmy.mthmmy.utils.ScrollAwareLinearBehavior">
<ImageButton
android:id="@+id/page_first_button"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="0.8"
android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/button_first"
app:srcCompat="@drawable/page_first" />
<ImageButton
android:id="@+id/page_previous_button"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="0.8"
android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/button_previous"
app:srcCompat="@drawable/page_previous" />
<TextView
android:id="@+id/page_indicator"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center"
android:layout_weight="1"
android:gravity="center"
android:hint="@string/button_page"
android:maxLines="1"
android:textColor="@color/white"
android:textSize="22sp" />
<ImageButton
android:id="@+id/page_next_button"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="0.8"
android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/button_next"
app:srcCompat="@drawable/page_next" />
<ImageButton
android:id="@+id/page_last_button"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="0.8"
android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/button_last"
app:srcCompat="@drawable/page_last" />
</LinearLayout>
app:layout_behavior="gr.thmmy.mthmmy.utils.ScrollAwareLinearBehavior"/>
<me.zhanghai.android.materialprogressbar.MaterialProgressBar
android:id="@+id/progressBar"

54
app/src/main/res/layout/pagination.xml

@ -0,0 +1,54 @@
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="@color/primary"
app:elevation="8dp"
app:layout_behavior="gr.thmmy.mthmmy.utils.ScrollAwareLinearBehavior">
<ImageButton
android:id="@+id/page_first_button"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="0.8"
android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/button_first"
app:srcCompat="@drawable/page_first" />
<ImageButton
android:id="@+id/page_previous_button"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="0.8"
android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/button_previous"
app:srcCompat="@drawable/page_previous" />
<TextView
android:id="@+id/page_indicator"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center"
android:layout_weight="1"
android:gravity="center"
android:hint="@string/button_page"
android:maxLines="1"
android:textColor="@color/white"
android:textSize="22sp" />
<ImageButton
android:id="@+id/page_next_button"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="0.8"
android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/button_next"
app:srcCompat="@drawable/page_next" />
<ImageButton
android:id="@+id/page_last_button"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="0.8"
android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/button_last"
app:srcCompat="@drawable/page_last" />
</merge>

6
build.gradle

@ -9,11 +9,7 @@ buildscript {
maven { url "https://jitpack.io" }
}
dependencies {
<<<<<<< HEAD
classpath 'com.android.tools.build:gradle:3.5.3'
=======
classpath 'com.android.tools.build:gradle:3.5.1'
>>>>>>> develop
classpath 'com.android.tools.build:gradle:3.6.1'
classpath 'com.google.gms:google-services:4.3.2'
classpath 'io.fabric.tools:gradle:1.29.0'
classpath 'org.ajoberstar.grgit:grgit-core:3.1.1' // Also change in app/gradle/grgit.gradle

4
gradle/wrapper/gradle-wrapper.properties

@ -1,6 +1,6 @@
#Tue Sep 17 12:32:34 EEST 2019
#Mon Mar 30 15:17:37 EEST 2020
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip

Loading…
Cancel
Save