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 TextInputLayout subjectInput;
private EmojiKeyboard emojiKeyboard; private EmojiKeyboard emojiKeyboard;
private String username, sendPmUrl; 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_SEND_PM_URL = "send-pm-url";
public static final String BUNDLE_PM_CONTENT = "pm-content"; public static final String BUNDLE_PM_CONTENT = "pm-content";
@ -42,6 +46,7 @@ public class CreatePMActivity extends BaseActivity implements ExternalAsyncTask.
Intent callingIntent = getIntent(); Intent callingIntent = getIntent();
username = callingIntent.getStringExtra(ProfileActivity.BUNDLE_PROFILE_USERNAME); username = callingIntent.getStringExtra(ProfileActivity.BUNDLE_PROFILE_USERNAME);
sendPmUrl = callingIntent.getStringExtra(BUNDLE_SEND_PM_URL); sendPmUrl = callingIntent.getStringExtra(BUNDLE_SEND_PM_URL);
defaultContent = callingIntent.getStringExtra(BUNDLE_PM_CONTENT);
//Initialize toolbar //Initialize toolbar
toolbar = findViewById(R.id.toolbar); toolbar = findViewById(R.id.toolbar);
@ -86,6 +91,8 @@ public class CreatePMActivity extends BaseActivity implements ExternalAsyncTask.
sendPMTask.execute(sendPmUrl, subjectInput.getEditText().getText().toString(), sendPMTask.execute(sendPmUrl, subjectInput.getEditText().getText().toString(),
contentEditor.getText().toString()); contentEditor.getText().toString());
}); });
if (defaultContent != null)
contentEditor.setText(defaultContent);
} }
@Override @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.os.Bundle;
import android.view.View; 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.lifecycle.ViewModelProviders;
import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
@ -46,7 +51,7 @@ public class InboxActivity extends BaseActivity {
inboxAdapter = new InboxAdapter(this); inboxAdapter = new InboxAdapter(this);
pmRecyclerview.setAdapter(inboxAdapter); pmRecyclerview.setAdapter(inboxAdapter);
inboxViewModel = ViewModelProviders.of(this).get(InboxViewModel.class); inboxViewModel =new ViewModelProvider(this).get(InboxViewModel.class);
subscribeUI(); subscribeUI();
inboxViewModel.loadInbox(); inboxViewModel.loadInbox();
@ -60,7 +65,9 @@ public class InboxActivity extends BaseActivity {
Timber.i("Successfully loaded inbox"); Timber.i("Successfully loaded inbox");
inboxAdapter.notifyDataSetChanged(); inboxAdapter.notifyDataSetChanged();
} else { } 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.setCompoundDrawablesRelativeWithIntrinsicBounds(quoteDrawable, null, null, null);
quoteButton.setOnClickListener(v -> { quoteButton.setOnClickListener(v -> {
Toast.makeText(context, "TODO", Toast.LENGTH_SHORT).show(); Toast.makeText(context, "TODO", Toast.LENGTH_SHORT).show();
// TODO: Create quote PM task // TODO: Create delete PM task
Intent sendPMIntent = new Intent(context, CreatePMActivity.class);
sendPMIntent.putExtra(CreatePMActivity.BUNDLE_SEND_PM_URL, currentPM.getQuoteUrl());
context.startActivity(sendPMIntent);
popUp.dismiss();
}); });
final TextView replyButton = popupContent.findViewById(R.id.pm_reply_button); 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; package gr.thmmy.mthmmy.activities.topic;
import android.annotation.SuppressLint;
import android.app.NotificationManager; import android.app.NotificationManager;
import android.content.ClipData; import android.content.ClipData;
import android.content.ClipboardManager; import android.content.ClipboardManager;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.graphics.Rect;
import android.net.Uri; import android.net.Uri;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler;
import android.text.Spannable; import android.text.Spannable;
import android.text.SpannableString; import android.text.SpannableString;
import android.text.SpannableStringBuilder; import android.text.SpannableStringBuilder;
@ -21,10 +18,8 @@ import android.text.style.ForegroundColorSpan;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View; import android.view.View;
import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.InputMethodManager;
import android.widget.ImageButton;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.ProgressBar; import android.widget.ProgressBar;
import android.widget.TextView; import android.widget.TextView;
@ -33,7 +28,7 @@ import android.widget.Toast;
import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatDelegate; import androidx.appcompat.app.AppCompatDelegate;
import androidx.core.content.res.ResourcesCompat; import androidx.core.content.res.ResourcesCompat;
import androidx.lifecycle.ViewModelProviders; import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.floatingactionbutton.FloatingActionButton; 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.Post;
import gr.thmmy.mthmmy.model.ThmmyPage; import gr.thmmy.mthmmy.model.ThmmyPage;
import gr.thmmy.mthmmy.model.TopicItem; import gr.thmmy.mthmmy.model.TopicItem;
import gr.thmmy.mthmmy.pagination.BottomPaginationView;
import gr.thmmy.mthmmy.utils.CustomLinearLayoutManager; import gr.thmmy.mthmmy.utils.CustomLinearLayoutManager;
import gr.thmmy.mthmmy.utils.HTMLUtils; import gr.thmmy.mthmmy.utils.HTMLUtils;
import gr.thmmy.mthmmy.utils.NetworkResultCodes; import gr.thmmy.mthmmy.utils.NetworkResultCodes;
@ -93,35 +89,9 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo
//Reply related //Reply related
private FloatingActionButton replyFAB; private FloatingActionButton replyFAB;
//Topic's pages related //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 //Bottom navigation bar graphics related
private LinearLayout bottomNavBar; private BottomPaginationView bottomPagination;
private ImageButton firstPage;
private ImageButton previousPage;
private TextView pageIndicator;
private ImageButton nextPage;
private ImageButton lastPage;
private Snackbar snackbar; private Snackbar snackbar;
private TopicViewModel viewModel; private TopicViewModel viewModel;
private EmojiKeyboard emojiKeyboard; private EmojiKeyboard emojiKeyboard;
@ -139,7 +109,7 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_topic); setContentView(R.layout.activity_topic);
// get TopicViewModel instance // get TopicViewModel instance
viewModel = ViewModelProviders.of(this).get(TopicViewModel.class); viewModel = new ViewModelProvider(this).get(TopicViewModel.class);
subscribeUI(); subscribeUI();
Bundle extras = getIntent().getExtras(); Bundle extras = getIntent().getExtras();
@ -191,7 +161,6 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo
replyFAB = findViewById(R.id.topic_fab); replyFAB = findViewById(R.id.topic_fab);
replyFAB.hide(); replyFAB.hide();
replyFAB.setTag(false); replyFAB.setTag(false);
bottomNavBar = findViewById(R.id.bottom_navigation_bar);
if (!sessionManager.isLoggedIn()) { if (!sessionManager.isLoggedIn()) {
replyFAB.hide(); replyFAB.hide();
replyFAB.setTag(false); replyFAB.setTag(false);
@ -204,18 +173,8 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo
} }
//Sets bottom navigation bar //Sets bottom navigation bar
firstPage = findViewById(R.id.page_first_button); bottomPagination = findViewById(R.id.bottom_pagination);
previousPage = findViewById(R.id.page_previous_button); bottomPagination.setOnPageRequestedListener(viewModel);
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);
Timber.i("Starting initial topic load"); Timber.i("Starting initial topic load");
viewModel.loadUrl(topicPageUrl); viewModel.loadUrl(topicPageUrl);
@ -291,7 +250,7 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo
viewModel.setWritingReply(false); viewModel.setWritingReply(false);
replyFAB.show(); replyFAB.show();
replyFAB.setTag(true); replyFAB.setTag(true);
bottomNavBar.setVisibility(View.VISIBLE); bottomPagination.setVisibility(View.VISIBLE);
return; return;
} else if (viewModel.isEditingPost()) { } else if (viewModel.isEditingPost()) {
((Post) topicItems.get(viewModel.getPostBeingEditedPosition())).setPostType(Post.TYPE_POST); ((Post) topicItems.get(viewModel.getPostBeingEditedPosition())).setPostType(Post.TYPE_POST);
@ -300,7 +259,7 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo
viewModel.setEditingPost(false); viewModel.setEditingPost(false);
replyFAB.show(); replyFAB.show();
replyFAB.setTag(true); replyFAB.setTag(true);
bottomNavBar.setVisibility(View.VISIBLE); bottomPagination.setVisibility(View.VISIBLE);
return; return;
} }
super.onBackPressed(); super.onBackPressed();
@ -340,152 +299,6 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo
recyclerView.scrollToPosition(position); 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------------------------------------ //------------------------------------BOTTOM NAV BAR METHODS END------------------------------------
/** /**
@ -538,7 +351,7 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo
Timber.i("Post reply successful"); Timber.i("Post reply successful");
replyFAB.show(); replyFAB.show();
replyFAB.setTag(true); replyFAB.setTag(true);
bottomNavBar.setVisibility(View.VISIBLE); bottomPagination.setVisibility(View.VISIBLE);
viewModel.setWritingReply(false); viewModel.setWritingReply(false);
SharedPreferences drafts = getSharedPreferences(getString(R.string.pref_topic_drafts_key), 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); topicAdapter.notifyItemChanged(position);
replyFAB.show(); replyFAB.show();
replyFAB.setTag(true); replyFAB.setTag(true);
bottomNavBar.setVisibility(View.VISIBLE); bottomPagination.setVisibility(View.VISIBLE);
viewModel.setEditingPost(false); viewModel.setEditingPost(false);
viewModel.reloadPage(); viewModel.reloadPage();
} else { } else {
@ -664,8 +477,11 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo
// observe the changes in data // observe the changes in data
viewModel.getPageIndicatorIndex().observe(this, pageIndicatorIndex -> { viewModel.getPageIndicatorIndex().observe(this, pageIndicatorIndex -> {
if (pageIndicatorIndex == null) return; if (pageIndicatorIndex == null) return;
pageIndicator.setText(String.valueOf(pageIndicatorIndex) + "/" + bottomPagination.setIndicatedPageIndex(pageIndicatorIndex);
String.valueOf(viewModel.getPageCount())); });
viewModel.getPageCount().observe(this, pageCount -> {
if (pageCount == null) return;
bottomPagination.setTotalPageCount(pageCount);
}); });
viewModel.getTopicTitle().observe(this, newTopicTitle -> { viewModel.getTopicTitle().observe(this, newTopicTitle -> {
if (newTopicTitle == null) return; if (newTopicTitle == null) return;
@ -674,7 +490,7 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo
}); });
viewModel.getPageTopicId().observe(this, pageTopicId -> { viewModel.getPageTopicId().observe(this, pageTopicId -> {
if (pageTopicId == null) return; if (pageTopicId == null) return;
if (viewModel.getCurrentPageIndex() == viewModel.getPageCount()) { if (viewModel.getCurrentPageIndex() == viewModel.getPageCount().getValue()) {
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (notificationManager != null) if (notificationManager != null)
notificationManager.cancel(NEW_POST_TAG, pageTopicId); notificationManager.cancel(NEW_POST_TAG, pageTopicId);
@ -696,6 +512,7 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo
topicItems.addAll(postList); topicItems.addAll(postList);
topicAdapter.notifyDataSetChanged(); topicAdapter.notifyDataSetChanged();
}); });
// Scroll to position does not work because WebView size is unknown initially
/*viewModel.getFocusedPostIndex().observe(this, focusedPostIndex -> { /*viewModel.getFocusedPostIndex().observe(this, focusedPostIndex -> {
if (focusedPostIndex == null) return; if (focusedPostIndex == null) return;
recyclerView.scrollToPosition(focusedPostIndex); recyclerView.scrollToPosition(focusedPostIndex);
@ -706,7 +523,7 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo
switch (resultCode) { switch (resultCode) {
case SUCCESS: case SUCCESS:
Timber.i("Successfully loaded a topic"); Timber.i("Successfully loaded a topic");
paginationEnabled(true); bottomPagination.setEnabled(true);
break; break;
case NETWORK_ERROR: case NETWORK_ERROR:
Timber.w("Network error on loaded page"); Timber.w("Network error on loaded page");
@ -731,7 +548,7 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo
}); });
} else { } else {
// a page has already been loaded // a page has already been loaded
viewModel.setPageIndicatorIndex(viewModel.getCurrentPageIndex(), false); bottomPagination.setIndicatedPageIndex(viewModel.getCurrentPageIndex());
snackbar = Snackbar.make(findViewById(R.id.main_content), snackbar = Snackbar.make(findViewById(R.id.main_content),
R.string.generic_network_error, Snackbar.LENGTH_INDEFINITE); R.string.generic_network_error, Snackbar.LENGTH_INDEFINITE);
snackbar.setAction(R.string.retry, view -> viewModel.reloadPage()); 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); recyclerView.scrollToPosition(topicItems.size() - 1);
replyFAB.hide(); replyFAB.hide();
replyFAB.setTag(false); replyFAB.setTag(false);
bottomNavBar.setVisibility(View.GONE); bottomPagination.setVisibility(View.GONE);
} else { } else {
Timber.i("Prepare for reply unsuccessful"); Timber.i("Prepare for reply unsuccessful");
Snackbar.make(findViewById(R.id.main_content), getString(R.string.generic_network_error), Snackbar.LENGTH_SHORT).show(); 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()); recyclerView.scrollToPosition(result.getPosition());
replyFAB.hide(); replyFAB.hide();
replyFAB.setTag(false); replyFAB.setTag(false);
bottomNavBar.setVisibility(View.GONE); bottomPagination.setVisibility(View.GONE);
} else { } else {
Timber.i("Prepare for edit unsuccessful"); Timber.i("Prepare for edit unsuccessful");
Snackbar.make(findViewById(R.id.main_content), getString(R.string.generic_network_error), Snackbar.LENGTH_SHORT).show(); 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. * 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) { void setToolbarOnLongClickListener(String url) {
toolbar.setOnLongClickListener(view -> { toolbar.setOnLongClickListener(view -> {
//Try to set the clipboard text //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 //Checks if the page to be loaded is the one already shown
if (uriString.contains(StringUtils.getBaseURL(viewModel.getTopicUrl()))) { if (uriString.contains(StringUtils.getBaseURL(viewModel.getTopicUrl()))) {
if (uriString.contains("topicseen#new") || uriString.contains("#new")) { if (uriString.contains("topicseen#new") || uriString.contains("#new")) {
if (viewModel.getCurrentPageIndex() == viewModel.getPageCount()) { if (viewModel.getCurrentPageIndex() == viewModel.getPageCount().getValue()) {
//same page //same page
postFocusListener.onPostFocusChange(getItemCount() - 1); postFocusListener.onPostFocusChange(getItemCount() - 1);
Timber.e("new"); Timber.e("new");

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

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

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

@ -71,63 +71,14 @@
android:visibility="gone" /> android:visibility="gone" />
</RelativeLayout> </RelativeLayout>
<LinearLayout <gr.thmmy.mthmmy.pagination.BottomPaginationView
android:id="@+id/bottom_navigation_bar" android:id="@+id/bottom_pagination"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="50dp" android:layout_height="50dp"
android:layout_gravity="bottom|end" android:layout_gravity="bottom|end"
android:background="@color/primary" android:background="@color/primary"
app:elevation="8dp" app:elevation="8dp"
app:layout_behavior="gr.thmmy.mthmmy.utils.ScrollAwareLinearBehavior"> 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>
<me.zhanghai.android.materialprogressbar.MaterialProgressBar <me.zhanghai.android.materialprogressbar.MaterialProgressBar
android:id="@+id/progressBar" 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" } maven { url "https://jitpack.io" }
} }
dependencies { dependencies {
<<<<<<< HEAD classpath 'com.android.tools.build:gradle:3.6.1'
classpath 'com.android.tools.build:gradle:3.5.3'
=======
classpath 'com.android.tools.build:gradle:3.5.1'
>>>>>>> develop
classpath 'com.google.gms:google-services:4.3.2' classpath 'com.google.gms:google-services:4.3.2'
classpath 'io.fabric.tools:gradle:1.29.0' classpath 'io.fabric.tools:gradle:1.29.0'
classpath 'org.ajoberstar.grgit:grgit-core:3.1.1' // Also change in app/gradle/grgit.gradle 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 distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists 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