added swiperefresh to metrics page, bug fix, code cleanup

This commit is contained in:
nuclearfog 2022-09-06 18:43:37 +02:00
parent 72943bd8c4
commit eaba87a689
No known key found for this signature in database
GPG Key ID: AA0271FBE406DB98
11 changed files with 202 additions and 142 deletions

View File

@ -39,6 +39,7 @@ import androidx.appcompat.content.res.AppCompatResources;
import androidx.appcompat.widget.Toolbar;
import androidx.cardview.widget.CardView;
import androidx.core.content.res.ResourcesCompat;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import androidx.viewpager.widget.ViewPager;
import com.google.android.material.tabs.TabLayout;
@ -335,6 +336,14 @@ public final class AppStyles {
button.setTextColor(invColor);
}
/**
* sets {@link SwipeRefreshLayout} theme
*/
public static void setSwipeRefreshColor(SwipeRefreshLayout reload, GlobalSettings settings) {
reload.setProgressBackgroundColorSchemeColor(settings.getHighlightColor());
reload.setColorSchemeColors(settings.getIconColor());
}
/**
* parsing all views from a sub ViewGroup recursively and set all colors and fonts
*

View File

@ -0,0 +1,34 @@
package org.nuclearfog.twidda.backend.utils;
import java.lang.ref.WeakReference;
/**
* memory leak save runnable class used to enable delayed swiperefresh animation
*
* @author nuclearfog
*/
public class RefreshDelay implements Runnable {
private WeakReference<RefreshCallback> callback;
public RefreshDelay(RefreshCallback callback) {
this.callback = new WeakReference<>(callback);
}
@Override
public void run() {
RefreshCallback callback = this.callback.get();
if (callback != null) {
callback.onRefreshDelayed();
}
}
/**
* callback to enable swiperefresh
*/
public interface RefreshCallback {
void onRefreshDelayed();
}
}

View File

@ -14,13 +14,14 @@ import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout.OnRefreshListener;
import com.squareup.picasso.Picasso;
@ -33,6 +34,8 @@ import org.nuclearfog.twidda.backend.async.MetricsLoader;
import org.nuclearfog.twidda.backend.utils.AppStyles;
import org.nuclearfog.twidda.backend.utils.ErrorHandler;
import org.nuclearfog.twidda.backend.utils.PicassoBuilder;
import org.nuclearfog.twidda.backend.utils.RefreshDelay;
import org.nuclearfog.twidda.backend.utils.RefreshDelay.RefreshCallback;
import org.nuclearfog.twidda.backend.utils.StringTools;
import org.nuclearfog.twidda.database.GlobalSettings;
import org.nuclearfog.twidda.model.Metrics;
@ -50,7 +53,7 @@ import jp.wasabeef.picasso.transformations.RoundedCornersTransformation;
*
* @author nuclearfog
*/
public class MetricsActivity extends AppCompatActivity implements OnClickListener, OnTagClickListener {
public class MetricsActivity extends AppCompatActivity implements OnClickListener, OnTagClickListener, OnRefreshListener, RefreshCallback {
/**
* key used for tweet information
@ -58,11 +61,16 @@ public class MetricsActivity extends AppCompatActivity implements OnClickListene
*/
public static final String KEY_METRICS_TWEET = "metrics_tweet";
/**
* delay to enable SwipeRefreshLayout
*/
private static final int REFRESH_DELAY_MS = 1000;
private static final NumberFormat NUM_FORMAT = NumberFormat.getIntegerInstance();
private MetricsLoader metricsAsync;
private ProgressBar loading;
private SwipeRefreshLayout reload;
private TextView impressionCount;
private TextView linkClicks;
private TextView profileClicks;
@ -74,6 +82,7 @@ public class MetricsActivity extends AppCompatActivity implements OnClickListene
@Nullable
private Tweet tweet;
private boolean isRefreshing = false;
@Override
protected void onCreate(Bundle savedInst) {
@ -95,7 +104,7 @@ public class MetricsActivity extends AppCompatActivity implements OnClickListene
replycount = findViewById(R.id.metrics_replies);
quoteCount = findViewById(R.id.metrics_quotes);
videoViews = findViewById(R.id.metrics_video_clicks);
loading = findViewById(R.id.metrics_loading);
reload = findViewById(R.id.metrics_refresh);
Picasso picasso = PicassoBuilder.get(this);
GlobalSettings settings = GlobalSettings.getInstance(this);
@ -113,7 +122,7 @@ public class MetricsActivity extends AppCompatActivity implements OnClickListene
favoriteCount.setCompoundDrawablesWithIntrinsicBounds(R.drawable.favorite, 0, 0, 0);
}
AppStyles.setTheme(root, settings.getBackgroundColor());
AppStyles.setProgressColor(loading, settings.getHighlightColor());
AppStyles.setSwipeRefreshColor(reload, settings);
tweetText.setMovementMethod(LinkAndScrollMovement.getInstance());
toolbar.setTitle(R.string.title_metrics);
@ -144,6 +153,7 @@ public class MetricsActivity extends AppCompatActivity implements OnClickListene
created.setText(StringTools.formatCreationTime(getResources(), tweet.getTimestamp()));
}
profile.setOnClickListener(this);
reload.setOnRefreshListener(this);
}
@ -153,6 +163,7 @@ public class MetricsActivity extends AppCompatActivity implements OnClickListene
if (metricsAsync == null && tweet != null) {
metricsAsync = new MetricsLoader(this);
metricsAsync.execute(tweet.getId());
setRefresh(true);
}
}
@ -169,6 +180,15 @@ public class MetricsActivity extends AppCompatActivity implements OnClickListene
}
@Override
public void onRefresh() {
if (tweet != null) {
metricsAsync = new MetricsLoader(this);
metricsAsync.execute(tweet.getId());
}
}
@Override
public void onTagClick(String tag) {
Intent intent = new Intent(this, SearchActivity.class);
@ -199,6 +219,16 @@ public class MetricsActivity extends AppCompatActivity implements OnClickListene
}
}
/**
*
*/
@Override
public void onRefreshDelayed() {
if (isRefreshing && !reload.isRefreshing()) {
reload.setRefreshing(true);
}
}
/**
* called from {@link MetricsLoader} if metrics was loaded sucessfully
*
@ -235,7 +265,7 @@ public class MetricsActivity extends AppCompatActivity implements OnClickListene
videoViews.setText(NUM_FORMAT.format(metrics.getVideoViews()));
videoViews.setVisibility(View.VISIBLE);
}
loading.setVisibility(View.GONE);
setRefresh(false);
}
/**
@ -243,6 +273,18 @@ public class MetricsActivity extends AppCompatActivity implements OnClickListene
*/
public void onError(@Nullable TwitterException exception) {
ErrorHandler.handleFailure(this, exception);
loading.setVisibility(View.GONE);
setRefresh(false);
}
/**
*
*/
private void setRefresh(boolean enable) {
isRefreshing = enable;
if (enable) {
reload.postDelayed(new RefreshDelay(this), REFRESH_DELAY_MS);
} else {
reload.setRefreshing(false);
}
}
}

View File

@ -69,8 +69,7 @@ public class AccountFragment extends ListFragment implements OnAccountClickListe
@Override
protected void onReload() {
if (loginTask == null || loginTask.getStatus() != RUNNING)
loginTask = new AccountLoader(this);
loginTask = new AccountLoader(this);
loginTask.execute();
}

View File

@ -15,17 +15,18 @@ import androidx.recyclerview.widget.RecyclerView.ViewHolder;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout.OnRefreshListener;
import org.nuclearfog.twidda.backend.utils.AppStyles;
import org.nuclearfog.twidda.backend.utils.RefreshDelay;
import org.nuclearfog.twidda.backend.utils.RefreshDelay.RefreshCallback;
import org.nuclearfog.twidda.database.GlobalSettings;
import java.lang.ref.WeakReference;
/**
* this fragment class hosts a list view inside a swipe view
* superclass for all list fragments
*
* @author nuclearfog
*/
public abstract class ListFragment extends Fragment implements OnRefreshListener {
public abstract class ListFragment extends Fragment implements OnRefreshListener, RefreshCallback {
/**
* delay to enable SwipeRefreshLayout
@ -41,15 +42,14 @@ public abstract class ListFragment extends Fragment implements OnRefreshListener
@Override
public final View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup parent, @Nullable Bundle b) {
settings = GlobalSettings.getInstance(requireContext());
list = new RecyclerView(requireContext());
list.setLayoutManager(new LinearLayoutManager(requireContext()));
reload = new SwipeRefreshLayout(requireContext());
reload.setProgressBackgroundColorSchemeColor(settings.getHighlightColor());
reload.setColorSchemeColors(settings.getIconColor());
reload.setOnRefreshListener(this);
reload.addView(list);
settings = GlobalSettings.getInstance(requireContext());
AppStyles.setSwipeRefreshColor(reload, settings);
return reload;
}
@ -59,6 +59,14 @@ public abstract class ListFragment extends Fragment implements OnRefreshListener
onReload();
}
@Override
public void onRefreshDelayed() {
if (isRefreshing && !reload.isRefreshing()) {
reload.setRefreshing(true);
}
}
/**
* enables or disables swipe layout
*
@ -98,10 +106,9 @@ public abstract class ListFragment extends Fragment implements OnRefreshListener
*/
public void reset() {
// check if fragment is initialized
if (reload != null && list != null) {
if (reload != null && list != null && settings != null) {
// reset colors
reload.setProgressBackgroundColorSchemeColor(settings.getHighlightColor());
reload.setColorSchemeColors(settings.getIconColor());
AppStyles.setSwipeRefreshColor(reload, settings);
// force redrawing list to apply colors
list.setAdapter(list.getAdapter());
onReset();
@ -126,24 +133,4 @@ public abstract class ListFragment extends Fragment implements OnRefreshListener
* called to reset all data
*/
protected abstract void onReset();
/**
* runnable class to delay swiperefreshlayout
*/
private static class RefreshDelay implements Runnable {
private WeakReference<ListFragment> callback;
private RefreshDelay(ListFragment fragment) {
callback = new WeakReference<>(fragment);
}
@Override
public void run() {
ListFragment fragment = callback.get();
if (fragment != null && fragment.isRefreshing && !fragment.reload.isRefreshing()) {
fragment.reload.setRefreshing(true);
}
}
}
}

View File

@ -88,9 +88,7 @@ public class MessageFragment extends ListFragment implements OnMessageClickListe
@Override
protected void onReload() {
if (messageTask != null && messageTask.getStatus() != RUNNING) {
load(MessageLoader.LOAD, null);
}
load(MessageLoader.LOAD, null);
}

View File

@ -67,9 +67,7 @@ public class TrendFragment extends ListFragment implements TrendClickListener {
@Override
protected void onReload() {
if (trendTask != null && trendTask.getStatus() != RUNNING) {
load();
}
load();
}

View File

@ -173,12 +173,10 @@ public class TweetFragment extends ListFragment implements TweetClickListener {
@Override
protected void onReload() {
if (tweetTask != null && tweetTask.getStatus() != RUNNING) {
long sinceId = 0;
if (!adapter.isEmpty())
sinceId = adapter.getItemId(0);
load(sinceId, 0, 0);
}
long sinceId = 0;
if (!adapter.isEmpty())
sinceId = adapter.getItemId(0);
load(sinceId, 0, 0);
}

View File

@ -213,9 +213,7 @@ public class UserFragment extends ListFragment implements UserClickListener, OnC
@Override
protected void onReload() {
if (userTask != null && userTask.getStatus() != RUNNING) {
load(NO_CURSOR);
}
load(NO_CURSOR);
}

View File

@ -137,9 +137,7 @@ public class UserListFragment extends ListFragment implements ListClickListener
@Override
protected void onReload() {
if (listTask != null && listTask.getStatus() != RUNNING) {
load(NO_CURSOR);
}
load(NO_CURSOR);
}

View File

@ -20,6 +20,7 @@
android:layout_height="@dimen/metrics_profile"
android:layout_marginStart="@dimen/metrics_profileimage_margin"
android:layout_marginTop="@dimen/metrics_profileimage_margin"
android:contentDescription="@string/profile_image"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/metrics_toolbar" />
@ -79,8 +80,8 @@
app:layout_constraintTop_toBottomOf="@id/metrics_tweet_barrier"
app:layout_constraintEnd_toEndOf="parent" />
<ScrollView
android:id="@+id/metrics_scroll"
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/metrics_refresh"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintStart_toStartOf="parent"
@ -88,102 +89,100 @@
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent">
<LinearLayout
<ScrollView
android:id="@+id/metrics_scroll"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
android:layout_height="match_parent">
<TextView
android:id="@+id/metrics_impression"
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
android:drawablePadding="@dimen/metrics_padding_drawable_big"
android:layout_margin="@dimen/metrics_item_margin"
android:textSize="@dimen/metrics_textsize_big"
android:gravity="end" />
android:orientation="vertical">
<TextView
android:id="@+id/metrics_retweets"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
android:drawablePadding="@dimen/metrics_padding_drawable_big"
android:layout_margin="@dimen/metrics_item_margin"
android:textSize="@dimen/metrics_textsize_big"
android:gravity="end" />
<TextView
android:id="@+id/metrics_impression"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
android:drawablePadding="@dimen/metrics_padding_drawable_big"
android:layout_margin="@dimen/metrics_item_margin"
android:textSize="@dimen/metrics_textsize_big"
android:gravity="end" />
<TextView
android:id="@+id/metrics_favorits"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
android:drawablePadding="@dimen/metrics_padding_drawable_big"
android:layout_margin="@dimen/metrics_item_margin"
android:textSize="@dimen/metrics_textsize_big"
android:gravity="end" />
<TextView
android:id="@+id/metrics_retweets"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
android:drawablePadding="@dimen/metrics_padding_drawable_big"
android:layout_margin="@dimen/metrics_item_margin"
android:textSize="@dimen/metrics_textsize_big"
android:gravity="end" />
<TextView
android:id="@+id/metrics_replies"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
android:drawablePadding="@dimen/metrics_padding_drawable_big"
android:layout_margin="@dimen/metrics_item_margin"
android:textSize="@dimen/metrics_textsize_big"
android:gravity="end" />
<TextView
android:id="@+id/metrics_favorits"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
android:drawablePadding="@dimen/metrics_padding_drawable_big"
android:layout_margin="@dimen/metrics_item_margin"
android:textSize="@dimen/metrics_textsize_big"
android:gravity="end" />
<TextView
android:id="@+id/metrics_quotes"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
android:drawablePadding="@dimen/metrics_padding_drawable_big"
android:layout_margin="@dimen/metrics_item_margin"
android:textSize="@dimen/metrics_textsize_big"
android:gravity="end" />
<TextView
android:id="@+id/metrics_replies"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
android:drawablePadding="@dimen/metrics_padding_drawable_big"
android:layout_margin="@dimen/metrics_item_margin"
android:textSize="@dimen/metrics_textsize_big"
android:gravity="end" />
<TextView
android:id="@+id/metrics_link_count"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
android:drawablePadding="@dimen/metrics_padding_drawable_big"
android:layout_margin="@dimen/metrics_item_margin"
android:textSize="@dimen/metrics_textsize_big"
android:gravity="end" />
<TextView
android:id="@+id/metrics_quotes"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
android:drawablePadding="@dimen/metrics_padding_drawable_big"
android:layout_margin="@dimen/metrics_item_margin"
android:textSize="@dimen/metrics_textsize_big"
android:gravity="end" />
<TextView
android:id="@+id/metrics_profile_count"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
android:drawablePadding="@dimen/metrics_padding_drawable_big"
android:layout_margin="@dimen/metrics_item_margin"
android:textSize="@dimen/metrics_textsize_big"
android:gravity="end" />
<TextView
android:id="@+id/metrics_link_count"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
android:drawablePadding="@dimen/metrics_padding_drawable_big"
android:layout_margin="@dimen/metrics_item_margin"
android:textSize="@dimen/metrics_textsize_big"
android:gravity="end" />
<TextView
android:id="@+id/metrics_video_clicks"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
android:drawablePadding="@dimen/metrics_padding_drawable_big"
android:layout_margin="@dimen/metrics_item_margin"
android:textSize="@dimen/metrics_textsize_big"
android:gravity="end" />
<TextView
android:id="@+id/metrics_profile_count"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
android:drawablePadding="@dimen/metrics_padding_drawable_big"
android:layout_margin="@dimen/metrics_item_margin"
android:textSize="@dimen/metrics_textsize_big"
android:gravity="end" />
</LinearLayout>
<TextView
android:id="@+id/metrics_video_clicks"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
android:drawablePadding="@dimen/metrics_padding_drawable_big"
android:layout_margin="@dimen/metrics_item_margin"
android:textSize="@dimen/metrics_textsize_big"
android:gravity="end" />
</ScrollView>
</LinearLayout>
<ProgressBar
android:id="@+id/metrics_loading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="@id/metrics_scroll"
app:layout_constraintTop_toTopOf="@id/metrics_scroll"
app:layout_constraintBottom_toBottomOf="@id/metrics_scroll"
app:layout_constraintEnd_toEndOf="@id/metrics_scroll" />
</ScrollView>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</androidx.constraintlayout.widget.ConstraintLayout>