diff --git a/app/src/main/java/com/zulip/android/activities/ZulipActivity.java b/app/src/main/java/com/zulip/android/activities/ZulipActivity.java index 092f9de5f..266d17f8f 100644 --- a/app/src/main/java/com/zulip/android/activities/ZulipActivity.java +++ b/app/src/main/java/com/zulip/android/activities/ZulipActivity.java @@ -28,6 +28,8 @@ import android.graphics.Bitmap; import android.graphics.PorterDuff; import android.graphics.drawable.Drawable; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; import android.net.Uri; import android.os.Build; import android.os.Bundle; @@ -183,6 +185,7 @@ public class ZulipActivity extends BaseActivity implements private SimpleCursorAdapter emailActvAdapter; private AppBarLayout appBarLayout; private MutedTopics mMutedTopics; + private BroadcastReceiver networkStateReceiver; private BroadcastReceiver onGcmMessage = new BroadcastReceiver() { public void onReceive(Context contenxt, Intent intent) { // Block the event before it propagates to show a notification. @@ -553,6 +556,7 @@ public Cursor runQuery(CharSequence charSequence) { handleOnFragmentChange(); calendar = Calendar.getInstance(); setupSnackBar(); + setupNetworkBroadcastReceiver(); } /** @@ -1976,6 +1980,7 @@ protected void onPause() { Log.i("status", "suspend"); unregisterReceiver(onGcmMessage); + unregisterReceiver(networkStateReceiver); if (event_poll != null) { event_poll.abort(); @@ -1997,6 +2002,9 @@ protected void onResume() { filter.setPriority(2); registerReceiver(onGcmMessage, filter); + // Registering network state broadcast receiver + setupNetworkBroadcastReceiver(); + homeList.onActivityResume(); if (narrowedList != null) { narrowedList.onActivityResume(); @@ -2141,4 +2149,33 @@ public void onClick(View view) { public enum Flag { RESET_DATABASE, } + public void setupNetworkBroadcastReceiver() + { + networkStateReceiver = new BroadcastReceiver() { + final CoordinatorLayout coordinatorLayout = (CoordinatorLayout) findViewById(R.id.coordinatorLayout); + @Override + public void onReceive(Context context, Intent intent) { + Log.d("Network Listener", "Network Type Changed"); + if(!isNetworkAvailable()){ + //Remove chatBox when network connectivity is lost + displayChatBox(false); + Snackbar.make(coordinatorLayout,R.string.no_connection,Snackbar.LENGTH_INDEFINITE).show(); + Log.d("Network Listener", "No Internet"); + } + else{ + Snackbar.make(coordinatorLayout,R.string.connection_established,Snackbar.LENGTH_SHORT).show(); + Log.d("Network Listener", "Internet"); + } + } + }; + + IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION); + registerReceiver(networkStateReceiver, filter); + } + private boolean isNetworkAvailable() { + ConnectivityManager connectivityManager + = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo(); + return activeNetworkInfo != null && activeNetworkInfo.isConnected(); + } } diff --git a/app/src/main/java/com/zulip/android/util/RemoveFabOnScroll.java b/app/src/main/java/com/zulip/android/util/RemoveFabOnScroll.java new file mode 100644 index 000000000..6e3639ca4 --- /dev/null +++ b/app/src/main/java/com/zulip/android/util/RemoveFabOnScroll.java @@ -0,0 +1,166 @@ +package com.zulip.android.util; + +import android.animation.Animator; +import android.annotation.SuppressLint; +import android.content.Context; +import android.support.design.widget.AppBarLayout; +import android.support.design.widget.CoordinatorLayout; +import android.support.design.widget.FloatingActionButton; +import android.support.design.widget.Snackbar; +import android.support.v4.view.ViewCompat; +import android.support.v4.view.animation.FastOutSlowInInterpolator; +import android.util.AttributeSet; +import android.util.TypedValue; +import android.view.View; +import android.view.ViewPropertyAnimator; +import android.view.animation.Interpolator; + +import com.zulip.android.R; + +import java.util.List; + +/** + * This hides the {@link AppBarLayout} and {@link android.support.design.widget.FloatingActionButton} when the + * recyclerView is scrolled, used in here {@link com.zulip.android.R.layout#main} as a behaviour. + */ +public class RemoveFabOnScroll extends CoordinatorLayout.Behavior { + private static final Interpolator FAST_OUT_SLOW_IN_INTERPOLATOR = new FastOutSlowInInterpolator(); + private static float toolbarHeight; + private int changeInYDir; + private boolean mIsShowing; + private boolean isViewHidden; + private View chatBox; + + public RemoveFabOnScroll(Context context, AttributeSet attrs) { + super(context, attrs); + TypedValue tv = new TypedValue(); + if (context.getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true)) + toolbarHeight = TypedValue.complexToDimensionPixelSize(tv.data, context.getResources().getDisplayMetrics()); + } + + @Override + public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, FloatingActionButton child, View directTargetChild, View target, int nestedScrollAxes) { + return (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0; + } + + @SuppressLint("NewApi") + @Override + public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, FloatingActionButton child, View target, int dx, int dy, int[] consumed) { + if (dy > 0 && changeInYDir < 0 || dy < 0 && changeInYDir > 0) { + child.animate().cancel(); + changeInYDir = 0; + } + + changeInYDir += dy; + if (changeInYDir > toolbarHeight && child.getVisibility() == View.VISIBLE && !isViewHidden) + hideView(child); + else if (changeInYDir < 0 && child.getVisibility() == View.GONE && !mIsShowing) { + if (child instanceof FloatingActionButton) { + if (chatBox == null) + chatBox = coordinatorLayout.findViewById(R.id.messageBoxContainer); + if (chatBox.getVisibility() == View.VISIBLE) { + return; + } + } + showView(child); + } + + } + + @SuppressLint("NewApi") + private void hideView(final View view) { + isViewHidden = true; + ViewPropertyAnimator animator = view.animate() + .translationY((view instanceof AppBarLayout) ? -1 * view.getHeight() : view.getHeight()) + .setInterpolator(FAST_OUT_SLOW_IN_INTERPOLATOR) + .setDuration(200); + + animator.setListener(new Animator.AnimatorListener() { + @Override + public void onAnimationStart(Animator animator) { + } + + @Override + public void onAnimationEnd(Animator animator) { + isViewHidden = false; + view.setVisibility(View.GONE); + } + + @Override + public void onAnimationCancel(Animator animator) { + isViewHidden = false; + if (!mIsShowing) + showView(view); + } + + @Override + public void onAnimationRepeat(Animator animator) { + } + }); + animator.start(); + } + + @SuppressLint("NewApi") + private void showView(final View view) { + mIsShowing = true; + ViewPropertyAnimator animator = view.animate() + .translationY(0) + .setInterpolator(FAST_OUT_SLOW_IN_INTERPOLATOR) + .setDuration(200); + + animator.setListener(new Animator.AnimatorListener() { + @Override + public void onAnimationStart(Animator animator) { + view.setVisibility(View.VISIBLE); + } + + @Override + public void onAnimationEnd(Animator animator) { + mIsShowing = false; + } + + @Override + public void onAnimationCancel(Animator animator) { + mIsShowing = false; + if (!isViewHidden) + hideView(view); + } + + @Override + public void onAnimationRepeat(Animator animator) { + } + }); + animator.start(); + } + + @Override + public boolean layoutDependsOn(CoordinatorLayout parent, FloatingActionButton child, View dependency) { + return dependency instanceof Snackbar.SnackbarLayout; + } + + @Override + public boolean onDependentViewChanged(CoordinatorLayout parent, FloatingActionButton child, View dependency) { + float translationY = getFabTranslationYForSnackbar(parent, child); + float percentComplete = -translationY / dependency.getHeight(); + float scaleFactor = 1 - percentComplete; + + child.setScaleX(scaleFactor); + child.setScaleY(scaleFactor); + return false; + } + + private float getFabTranslationYForSnackbar(CoordinatorLayout parent, + FloatingActionButton fab) { + float minOffset = 0; + final List dependencies = parent.getDependencies(fab); + for (int i = 0, z = dependencies.size(); i < z; i++) { + final View view = dependencies.get(i); + if (view instanceof Snackbar.SnackbarLayout && parent.doViewsOverlap(fab, view)) { + minOffset = Math.min(minOffset, + ViewCompat.getTranslationY(view) - view.getHeight()); + } + } + + return minOffset; + } +} diff --git a/app/src/main/res/layout/main.xml b/app/src/main/res/layout/main.xml index f07ad0ab3..be5f9ac4d 100644 --- a/app/src/main/res/layout/main.xml +++ b/app/src/main/res/layout/main.xml @@ -53,7 +53,7 @@ android:src="@drawable/ic_mode_edit_24dp" app:backgroundTint="@color/colorPrimary" app:borderWidth="0dp" - app:layout_behavior="com.zulip.android.util.RemoveViewsOnScroll" /> + app:layout_behavior="com.zulip.android.util.RemoveFabOnScroll" /> %d new message %d new messages + No Connection! + Connection Established