Compare commits

..

16 Commits

Author SHA1 Message Date
Jason A. Donenfeld fbf32a6c29 Version bump
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2018-07-20 15:54:46 +02:00
Harsh Shandilya 3e37289b68 UI: use background color for navbar in dark mode
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2018-07-20 15:53:41 +02:00
Jason A. Donenfeld 2d6a45f824 fab: make icons always white
With the new shade of blue, perhaps this simply looks better.

I don't like hard coding the color away from the theme, however.

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2018-07-20 15:45:21 +02:00
Jason A. Donenfeld ed802336e6 theme: use less disgusting color
Harsh's "users" were offended by the dark theme. So, we change the
accent to that used by gboard's dark theme, which should be pretty
uncontroversial.

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2018-07-20 03:23:17 +02:00
Harsh Shandilya b1d1e3b436 TunnelListFragment: Allocate interpolators outside scroll listener
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2018-07-20 03:17:49 +02:00
Jason A. Donenfeld d33e322b67 TunnelEditorFragment: fix null pointer dereference
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2018-07-19 20:57:00 +02:00
Jason A. Donenfeld 60a6e29350 QuickTileService: fix null pointer dereference
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2018-07-19 20:57:00 +02:00
Jason A. Donenfeld 3b0e0c2f16 tools: bump version
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2018-07-18 21:54:14 +02:00
Jason A. Donenfeld ffb8bccbc5 Version bump
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2018-07-18 18:40:16 +02:00
Jason A. Donenfeld 08170f7e55 TunnelListFragment: setOnScrollListener is old, but we support API 21, so we have to use it
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2018-07-18 18:32:42 +02:00
Jason A. Donenfeld 28d47b3470 AppListDialogFragment: getArguments is null before onCreate
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2018-07-18 18:08:08 +02:00
Jason A. Donenfeld 8e3586328c fab: use auto calculated fling threshold
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2018-07-18 02:32:05 +02:00
Jason A. Donenfeld f315654d40 fab: add fab sized padding at bottom of recycler view
This way we can keep scrolling when there are exactly the right number
of items, so that the toggle switch becomes visible.

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2018-07-18 02:15:14 +02:00
Harsh Shandilya fdfab18d45 fab: make fab respond to recyclerview scroll events
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2018-07-18 02:15:06 +02:00
Harsh Shandilya d43e77867c fab: slide fab up when a snackbar shows
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2018-07-18 02:15:06 +02:00
Harsh Shandilya df03bdd7f9 android: QuickTileService: Do not use slashed icon on Android P
Android P features circle masked QS tiles which make use of colors
to denote STATE_ACTIVE/STATE_INACTIVE rather than a slash across
the drawable as seen on Android Oreo.

Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2018-07-16 17:31:14 +02:00
17 changed files with 154 additions and 56 deletions
+2 -2
View File
@@ -17,8 +17,8 @@ android {
applicationId 'com.wireguard.android'
minSdkVersion 21
targetSdkVersion 27
versionCode 433
versionName '0.0.20180716'
versionCode 435
versionName '0.0.20180720'
}
// If the keystore file exists
if (keystorePropertiesFile.exists()) {
@@ -55,20 +55,27 @@ public class QuickTileService extends TileService {
icon.setBounds(0, 0, c.getWidth(), c.getHeight());
icon.draw(c);
iconOn = Icon.createWithBitmap(b);
icon.setSlashed(true);
b = Bitmap.createBitmap(icon.getIntrinsicWidth(), icon.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
c = new Canvas(b);
icon.setBounds(0, 0, c.getWidth(), c.getHeight());
icon.draw(c);
iconOff = Icon.createWithBitmap(b);
/* TODO(msf): Change this to an explicit test for P when we start targetting SDK 28 */
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O_MR1) {
iconOff = iconOn;
} else {
icon.setSlashed(true);
b = Bitmap.createBitmap(icon.getIntrinsicWidth(), icon.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
c = new Canvas(b);
icon.setBounds(0, 0, c.getWidth(), c.getHeight());
icon.draw(c);
iconOff = Icon.createWithBitmap(b);
}
}
@Override
public void onClick() {
if (tunnel != null) {
final Tile tile = getQsTile();
tile.setIcon(tile.getIcon() == iconOn ? iconOff : iconOn);
tile.updateTile();
if (tile != null) {
tile.setIcon(tile.getIcon() == iconOn ? iconOff : iconOn);
tile.updateTile();
}
tunnel.setState(State.TOGGLE).whenComplete(this::onToggleFinished);
} else {
final Intent intent = new Intent(this, MainActivity.class);
@@ -18,37 +18,6 @@ import com.wireguard.android.Application;
import java.lang.reflect.Field;
public abstract class ThemeChangeAwareActivity extends AppCompatActivity implements SharedPreferences.OnSharedPreferenceChangeListener {
private static final String TAG = "WireGuard/" + ThemeChangeAwareActivity.class.getSimpleName();
@Nullable private static Resources lastResources;
private static boolean lastDarkMode;
private static synchronized void invalidateDrawableCache(final Resources resources, final boolean darkMode) {
if (resources == lastResources && darkMode == lastDarkMode)
return;
try {
Field f;
Object o = resources;
try {
f = o.getClass().getDeclaredField("mResourcesImpl");
f.setAccessible(true);
o = f.get(o);
} catch (final Exception ignored) { }
f = o.getClass().getDeclaredField("mDrawableCache");
f.setAccessible(true);
o = f.get(o);
try {
o.getClass().getMethod("onConfigurationChange", int.class).invoke(o, -1);
} catch (final Exception ignored) {
o.getClass().getMethod("clear").invoke(o);
}
} catch (final Exception e) {
Log.e(TAG, "Failed to flush drawable cache", e);
}
lastResources = resources;
lastDarkMode = darkMode;
}
@Override
@@ -66,12 +35,10 @@ public abstract class ThemeChangeAwareActivity extends AppCompatActivity impleme
@Override
public void onSharedPreferenceChanged(final SharedPreferences sharedPreferences, final String key) {
if ("dark_theme".equals(key)) {
final boolean darkMode = sharedPreferences.getBoolean(key, false);
AppCompatDelegate.setDefaultNightMode(
sharedPreferences.getBoolean(key, false) ?
AppCompatDelegate.MODE_NIGHT_YES :
AppCompatDelegate.MODE_NIGHT_NO);
invalidateDrawableCache(getResources(), darkMode);
recreate();
}
}
@@ -39,7 +39,7 @@ public class AppListDialogFragment extends DialogFragment {
private static final String KEY_EXCLUDED_APPS = "excludedApps";
private final List<String> currentlyExcludedApps = Arrays.asList(getArguments().getStringArray(KEY_EXCLUDED_APPS));
private List<String> currentlyExcludedApps;
private final ObservableKeyedList<String, ApplicationData> appData = new ObservableKeyedArrayList<>();
public static <T extends Fragment & AppExclusionListener> AppListDialogFragment newInstance(final String[] excludedApps, final T target) {
@@ -51,6 +51,13 @@ public class AppListDialogFragment extends DialogFragment {
return fragment;
}
@Override
public void onCreate(@Nullable final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
currentlyExcludedApps = Arrays.asList(getArguments().getStringArray(KEY_EXCLUDED_APPS));
}
@Override
public Dialog onCreateDialog(final Bundle savedInstanceState) {
final AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(getActivity());
@@ -96,11 +96,13 @@ public class TunnelEditorFragment extends BaseFragment implements AppExclusionLi
@Override
public void onItemRangeInserted(final ObservableList<Peer.Observable> sender, final int positionStart, final int itemCount) {
breakObjectOrientedLayeringHandler.onPropertyChanged(binding.getConfig(), BR.peers);
if (binding != null)
breakObjectOrientedLayeringHandler.onPropertyChanged(binding.getConfig(), BR.peers);
}
@Override
public void onItemRangeRemoved(final ObservableList<Peer.Observable> sender, final int positionStart, final int itemCount) {
breakObjectOrientedLayeringHandler.onPropertyChanged(binding.getConfig(), BR.peers);
if (binding != null)
breakObjectOrientedLayeringHandler.onPropertyChanged(binding.getConfig(), BR.peers);
}
};
@@ -6,6 +6,7 @@
package com.wireguard.android.fragment;
import android.animation.TimeInterpolator;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.ContentResolver;
@@ -26,6 +27,8 @@ import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import com.wireguard.android.Application;
import com.wireguard.android.R;
@@ -35,6 +38,7 @@ import com.wireguard.android.databinding.TunnelListFragmentBinding;
import com.wireguard.android.databinding.TunnelListItemBinding;
import com.wireguard.android.model.Tunnel;
import com.wireguard.android.util.ExceptionLoggers;
import com.wireguard.android.widget.CustomRecyclerViewScrollListener;
import com.wireguard.config.Config;
import java.io.BufferedReader;
@@ -58,6 +62,8 @@ import java9.util.stream.StreamSupport;
public class TunnelListFragment extends BaseFragment {
private static final int REQUEST_IMPORT = 1;
private static final String TAG = "WireGuard/" + TunnelListFragment.class.getSimpleName();
private static final TimeInterpolator FAB_SHOW_ANIMATION = new DecelerateInterpolator(2);
private static final TimeInterpolator FAB_HIDE_ANIMATION = new AccelerateInterpolator(2);
private final ActionModeListener actionModeListener = new ActionModeListener();
@Nullable private ActionMode actionMode;
@@ -176,6 +182,7 @@ public class TunnelListFragment extends BaseFragment {
}
}
@SuppressWarnings("deprecation")
@SuppressLint("ClickableViewAccessibility")
@Override
public View onCreateView(@NonNull final LayoutInflater inflater, @Nullable final ViewGroup container,
@@ -189,6 +196,23 @@ public class TunnelListFragment extends BaseFragment {
}
return false;
});
binding.tunnelList.setOnScrollListener(new CustomRecyclerViewScrollListener() {
@Override
public void show() {
binding.createMenu.animate()
.translationY(0)
.setInterpolator(FAB_SHOW_ANIMATION)
.start();
}
@Override
public void hide() {
binding.createMenu.animate()
.translationY(binding.createMenu.getHeight() + getResources().getDimension(R.dimen.fab_margin))
.setInterpolator(FAB_HIDE_ANIMATION)
.start();
}
});
binding.executePendingBindings();
return binding.getRoot();
}
@@ -0,0 +1,43 @@
/*
* Copyright © 2018 Harsh Shandilya <msfjarvis@gmail.com>
* Copyright © 2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.widget;
import android.support.v7.widget.RecyclerView;
import com.wireguard.android.R;
public abstract class CustomRecyclerViewScrollListener extends RecyclerView.OnScrollListener {
private int scrollDist;
private boolean isVisible = true;
private static int flingThreshold;
@Override
public void onScrolled(final RecyclerView recyclerView, final int dx, final int dy) {
super.onScrolled(recyclerView, dx, dy);
if (flingThreshold == 0)
flingThreshold = recyclerView.getResources().getDimensionPixelSize(R.dimen.design_fab_size_normal) / 2;
if (isVisible && scrollDist >= flingThreshold) {
hide();
scrollDist = 0;
isVisible = false;
} else if (!isVisible && scrollDist <= -flingThreshold) {
show();
scrollDist = 0;
isVisible = true;
}
if (isVisible ? dy > 0 : dy < 0) {
scrollDist += dy;
}
}
public abstract void show();
public abstract void hide();
}
@@ -0,0 +1,32 @@
/*
* Copyright © 2018 Harsh Shandilya <msfjarvis@gmail.com>
* Copyright © 2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.widget.fab;
import android.content.Context;
import android.support.design.widget.CoordinatorLayout;
import android.support.design.widget.Snackbar;
import android.util.AttributeSet;
import android.view.View;
public class FloatingActionButtonBehavior extends CoordinatorLayout.Behavior<FloatingActionsMenu> {
public FloatingActionButtonBehavior(final Context context, final AttributeSet attrs) { }
@Override
public boolean layoutDependsOn(final CoordinatorLayout parent, final FloatingActionsMenu child,
final View dependency) {
return dependency instanceof Snackbar.SnackbarLayout;
}
@Override
public boolean onDependentViewChanged(final CoordinatorLayout parent, final FloatingActionsMenu child,
final View dependency) {
final float translationY = Math.min(0, dependency.getTranslationY() - dependency.getHeight());
child.setTranslationY(translationY);
return true;
}
}
@@ -112,7 +112,7 @@ public class FloatingActionsMenu extends ViewGroup {
}
private void createAddButton(final Context context) {
final RotatingDrawable rotatingDrawable = new RotatingDrawable(ResourcesCompat.getDrawable(context.getResources(), R.drawable.ic_action_add_inverse, context.getTheme()));
final RotatingDrawable rotatingDrawable = new RotatingDrawable(ResourcesCompat.getDrawable(context.getResources(), R.drawable.ic_action_add_white, context.getTheme()));
mRotatingDrawable = rotatingDrawable;
final TimeInterpolator interpolator = new OvershootInterpolator();
@@ -4,6 +4,6 @@
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path
android:fillColor="?android:attr/colorBackground"
android:fillColor="#ffffff"
android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z" />
</vector>
@@ -4,6 +4,6 @@
android:viewportHeight="24"
android:viewportWidth="24">
<path
android:fillColor="?android:attr/colorBackground"
android:fillColor="#ffffff"
android:pathData="M3,17.25V21h3.75L17.81,9.94l-3.75,-3.75L3,17.25zM20.71,7.04c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83 3.75,3.75 1.83,-1.83z" />
</vector>
@@ -4,6 +4,6 @@
android:viewportHeight="24"
android:viewportWidth="24">
<path
android:fillColor="?android:attr/colorBackground"
android:fillColor="#ffffff"
android:pathData="M6,2c-1.1,0 -1.99,0.9 -1.99,2L4,20c0,1.1 0.89,2 1.99,2L18,22c1.1,0 2,-0.9 2,-2L20,8l-6,-6L6,2zM13,9L13,3.5L18.5,9L13,9z" />
</vector>
@@ -30,6 +30,8 @@
android:id="@+id/tunnel_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/design_fab_size_normal"
android:clipToPadding="false"
android:choiceMode="multipleChoiceModal"
app:items="@{tunnels}"
app:layout="@{@layout/tunnel_list_item}"
@@ -40,10 +42,11 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="16dp"
android:layout_margin="@dimen/fab_margin"
app:fab_labelStyle="@style/fab_label"
android:clipChildren="false"
app:fab_labelsPosition="left" >
app:fab_labelsPosition="left"
app:layout_behavior="com.wireguard.android.widget.fab.FloatingActionButtonBehavior" >
<com.wireguard.android.widget.fab.LabeledFloatingActionButton
android:id="@+id/create_empty"
@@ -51,7 +54,7 @@
android:layout_height="wrap_content"
android:onClick="@{fragment::onRequestCreateConfig}"
app:fabSize="mini"
app:srcCompat="@drawable/ic_action_edit_inverse"
app:srcCompat="@drawable/ic_action_edit_white"
app:fab_title="@string/create_empty" />
<com.wireguard.android.widget.fab.LabeledFloatingActionButton
@@ -59,7 +62,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="@{fragment::onRequestImportConfig}"
app:srcCompat="@drawable/ic_action_open_inverse"
app:srcCompat="@drawable/ic_action_open_white"
app:fabSize="mini"
app:fab_title="@string/create_from_file" />
</com.wireguard.android.widget.fab.FloatingActionsMenu>
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<style name="AppTheme" parent="Theme.AppCompat.DayNight.DarkActionBar">
<item name="colorAccent">@color/accent</item>
<item name="android:navigationBarColor">?android:attr/colorBackground</item>
</style>
</resources>
+1 -1
View File
@@ -6,5 +6,5 @@
<color name="fab_label_text_color">#000000</color>
<color name="fab_label_background_color">#bbbbbb</color>
<color name="accent">#BBDEFB</color>
<color name="accent">#5e97f6</color>
</resources>
+4
View File
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="fab_margin">16dp</dimen>
</resources>