From aad7f2be6a673d27f1a843c453fd13ee12f517c6 Mon Sep 17 00:00:00 2001 From: George Venios Date: Mon, 21 Sep 2015 23:49:11 +0100 Subject: [PATCH] Updated device details styling. Made actionmode bar overlay the toolbar. Updated UI for device edit/create fragment to match the folder one. Refactored FolderFragment to match DeviceFragment. Improvements for Details styles and item heights. --- .../test/activities/MainActivityTest.java | 4 +- src/main/AndroidManifest.xml | 3 +- .../activities/MainActivity.java | 38 +- .../activities/SettingsActivity.java | 19 +- .../fragments/DeviceFragment.java | 425 ++++++++++++++++++ ...sFragment.java => DeviceListFragment.java} | 4 +- .../fragments/DeviceSettingsFragment.java | 330 -------------- .../fragments/FolderFragment.java | 135 +++--- .../syncthingandroid/util/Compression.java | 57 +++ .../util/TextWatcherAdapter.java | 16 + .../widget/EnhancedEditText.java | 50 +++ .../ic_cellphone_black_24dp_active.png | Bin 0 -> 137 bytes .../ic_cellphone_black_24dp_inactive.png | Bin 0 -> 136 bytes .../ic_info_black_24dp_active.png | Bin 0 -> 308 bytes .../ic_info_black_24dp_inactive.png | Bin 0 -> 286 bytes .../ic_link_black_24dp_active.png | Bin 0 -> 294 bytes .../ic_link_black_24dp_inactive.png | Bin 0 -> 268 bytes .../ic_phonelink_black_24dp_active.png | Bin 0 -> 150 bytes .../ic_phonelink_black_24dp_inactive.png | Bin 0 -> 148 bytes src/main/res/drawable-hdpi/ic_qrcode.png | Bin 942 -> 0 bytes .../ic_qrcode_black_24dp_active.png | Bin 0 -> 367 bytes .../ic_qrcode_black_24dp_inactive.png | Bin 0 -> 329 bytes .../ic_tag_text_outline_black_24dp_active.png | Bin 0 -> 308 bytes ...c_tag_text_outline_black_24dp_inactive.png | Bin 0 -> 295 bytes .../ic_zip_box_black_24dp_active.png | Bin 0 -> 182 bytes .../ic_zip_box_black_24dp_inactive.png | Bin 0 -> 178 bytes src/main/res/drawable-mdpi/ic_qrcode.png | Bin 857 -> 0 bytes .../ic_cellphone_black_24dp_active.png | Bin 0 -> 161 bytes .../ic_cellphone_black_24dp_inactive.png | Bin 0 -> 161 bytes .../ic_info_black_24dp_active.png | Bin 0 -> 383 bytes .../ic_info_black_24dp_inactive.png | Bin 0 -> 358 bytes .../ic_link_black_24dp_active.png | Bin 0 -> 333 bytes .../ic_link_black_24dp_inactive.png | Bin 0 -> 274 bytes .../ic_phonelink_black_24dp_active.png | Bin 0 -> 164 bytes .../ic_phonelink_black_24dp_inactive.png | Bin 0 -> 163 bytes src/main/res/drawable-xhdpi/ic_qrcode.png | Bin 1233 -> 0 bytes .../ic_qrcode_black_24dp_active.png | Bin 0 -> 137 bytes .../ic_qrcode_black_24dp_inactive.png | Bin 0 -> 139 bytes .../ic_tag_text_outline_black_24dp_active.png | Bin 0 -> 320 bytes ...c_tag_text_outline_black_24dp_inactive.png | Bin 0 -> 306 bytes .../ic_zip_box_black_24dp_active.png | Bin 0 -> 169 bytes .../ic_zip_box_black_24dp_inactive.png | Bin 0 -> 168 bytes .../ic_cellphone_black_24dp_active.png | Bin 0 -> 204 bytes .../ic_cellphone_black_24dp_inactive.png | Bin 0 -> 195 bytes .../ic_info_black_24dp_active.png | Bin 0 -> 547 bytes .../ic_info_black_24dp_inactive.png | Bin 0 -> 508 bytes .../ic_link_black_24dp_active.png | Bin 0 -> 519 bytes .../ic_link_black_24dp_inactive.png | Bin 0 -> 445 bytes .../ic_phonelink_black_24dp_active.png | Bin 0 -> 213 bytes .../ic_phonelink_black_24dp_inactive.png | Bin 0 -> 205 bytes src/main/res/drawable-xxhdpi/ic_qrcode.png | Bin 2606 -> 0 bytes .../ic_qrcode_black_24dp_active.png | Bin 0 -> 156 bytes .../ic_qrcode_black_24dp_inactive.png | Bin 0 -> 156 bytes .../ic_tag_text_outline_black_24dp_active.png | Bin 0 -> 459 bytes ...c_tag_text_outline_black_24dp_inactive.png | Bin 0 -> 443 bytes .../ic_zip_box_black_24dp_active.png | Bin 0 -> 206 bytes .../ic_zip_box_black_24dp_inactive.png | Bin 0 -> 197 bytes .../ic_cellphone_black_24dp_active.png | Bin 0 -> 277 bytes .../ic_cellphone_black_24dp_inactive.png | Bin 0 -> 255 bytes .../ic_info_black_24dp_active.png | Bin 0 -> 721 bytes .../ic_info_black_24dp_inactive.png | Bin 0 -> 670 bytes .../ic_link_black_24dp_active.png | Bin 0 -> 674 bytes .../ic_link_black_24dp_inactive.png | Bin 0 -> 561 bytes .../ic_phonelink_black_24dp_active.png | Bin 0 -> 263 bytes .../ic_phonelink_black_24dp_inactive.png | Bin 0 -> 254 bytes .../ic_qrcode_black_24dp_active.png | Bin 0 -> 155 bytes .../ic_qrcode_black_24dp_inactive.png | Bin 0 -> 155 bytes .../ic_tag_text_outline_black_24dp_active.png | Bin 0 -> 685 bytes ...c_tag_text_outline_black_24dp_inactive.png | Bin 0 -> 570 bytes .../ic_zip_box_black_24dp_active.png | Bin 0 -> 270 bytes .../ic_zip_box_black_24dp_inactive.png | Bin 0 -> 259 bytes .../res/drawable/ic_cellphone_black_24dp.xml | 5 + src/main/res/drawable/ic_info_black_24dp.xml | 5 + src/main/res/drawable/ic_link_black_24dp.xml | 5 + .../res/drawable/ic_phonelink_black_24dp.xml | 5 + .../res/drawable/ic_qrcode_black_24dp.xml | 5 + .../ic_tag_text_outline_black_24dp.xml | 5 + src/main/res/drawable/ic_transparent_24dp.xml | 8 + .../res/drawable/ic_zip_box_black_24dp.xml | 5 + src/main/res/layout/fragment_device.xml | 133 ++++++ src/main/res/layout/fragment_folder.xml | 31 +- src/main/res/layout/item_device_form.xml | 8 +- .../res/layout/pref_widget_scan_qr_code.xml | 6 +- src/main/res/values/styles.xml | 12 +- src/main/res/values/themes.xml | 1 + src/main/res/xml/device_settings_create.xml | 32 -- src/main/res/xml/device_settings_edit.xml | 43 -- 87 files changed, 840 insertions(+), 550 deletions(-) create mode 100644 src/main/java/com/nutomic/syncthingandroid/fragments/DeviceFragment.java rename src/main/java/com/nutomic/syncthingandroid/fragments/{DevicesFragment.java => DeviceListFragment.java} (95%) delete mode 100644 src/main/java/com/nutomic/syncthingandroid/fragments/DeviceSettingsFragment.java create mode 100644 src/main/java/com/nutomic/syncthingandroid/util/Compression.java create mode 100644 src/main/java/com/nutomic/syncthingandroid/util/TextWatcherAdapter.java create mode 100644 src/main/java/com/nutomic/syncthingandroid/widget/EnhancedEditText.java create mode 100644 src/main/res/drawable-hdpi/ic_cellphone_black_24dp_active.png create mode 100644 src/main/res/drawable-hdpi/ic_cellphone_black_24dp_inactive.png create mode 100644 src/main/res/drawable-hdpi/ic_info_black_24dp_active.png create mode 100644 src/main/res/drawable-hdpi/ic_info_black_24dp_inactive.png create mode 100644 src/main/res/drawable-hdpi/ic_link_black_24dp_active.png create mode 100644 src/main/res/drawable-hdpi/ic_link_black_24dp_inactive.png create mode 100644 src/main/res/drawable-hdpi/ic_phonelink_black_24dp_active.png create mode 100644 src/main/res/drawable-hdpi/ic_phonelink_black_24dp_inactive.png delete mode 100644 src/main/res/drawable-hdpi/ic_qrcode.png create mode 100644 src/main/res/drawable-hdpi/ic_qrcode_black_24dp_active.png create mode 100644 src/main/res/drawable-hdpi/ic_qrcode_black_24dp_inactive.png create mode 100644 src/main/res/drawable-hdpi/ic_tag_text_outline_black_24dp_active.png create mode 100644 src/main/res/drawable-hdpi/ic_tag_text_outline_black_24dp_inactive.png create mode 100644 src/main/res/drawable-hdpi/ic_zip_box_black_24dp_active.png create mode 100644 src/main/res/drawable-hdpi/ic_zip_box_black_24dp_inactive.png delete mode 100644 src/main/res/drawable-mdpi/ic_qrcode.png create mode 100644 src/main/res/drawable-xhdpi/ic_cellphone_black_24dp_active.png create mode 100644 src/main/res/drawable-xhdpi/ic_cellphone_black_24dp_inactive.png create mode 100644 src/main/res/drawable-xhdpi/ic_info_black_24dp_active.png create mode 100644 src/main/res/drawable-xhdpi/ic_info_black_24dp_inactive.png create mode 100644 src/main/res/drawable-xhdpi/ic_link_black_24dp_active.png create mode 100644 src/main/res/drawable-xhdpi/ic_link_black_24dp_inactive.png create mode 100644 src/main/res/drawable-xhdpi/ic_phonelink_black_24dp_active.png create mode 100644 src/main/res/drawable-xhdpi/ic_phonelink_black_24dp_inactive.png delete mode 100644 src/main/res/drawable-xhdpi/ic_qrcode.png create mode 100644 src/main/res/drawable-xhdpi/ic_qrcode_black_24dp_active.png create mode 100644 src/main/res/drawable-xhdpi/ic_qrcode_black_24dp_inactive.png create mode 100644 src/main/res/drawable-xhdpi/ic_tag_text_outline_black_24dp_active.png create mode 100644 src/main/res/drawable-xhdpi/ic_tag_text_outline_black_24dp_inactive.png create mode 100644 src/main/res/drawable-xhdpi/ic_zip_box_black_24dp_active.png create mode 100644 src/main/res/drawable-xhdpi/ic_zip_box_black_24dp_inactive.png create mode 100644 src/main/res/drawable-xxhdpi/ic_cellphone_black_24dp_active.png create mode 100644 src/main/res/drawable-xxhdpi/ic_cellphone_black_24dp_inactive.png create mode 100644 src/main/res/drawable-xxhdpi/ic_info_black_24dp_active.png create mode 100644 src/main/res/drawable-xxhdpi/ic_info_black_24dp_inactive.png create mode 100644 src/main/res/drawable-xxhdpi/ic_link_black_24dp_active.png create mode 100644 src/main/res/drawable-xxhdpi/ic_link_black_24dp_inactive.png create mode 100644 src/main/res/drawable-xxhdpi/ic_phonelink_black_24dp_active.png create mode 100644 src/main/res/drawable-xxhdpi/ic_phonelink_black_24dp_inactive.png delete mode 100644 src/main/res/drawable-xxhdpi/ic_qrcode.png create mode 100644 src/main/res/drawable-xxhdpi/ic_qrcode_black_24dp_active.png create mode 100644 src/main/res/drawable-xxhdpi/ic_qrcode_black_24dp_inactive.png create mode 100644 src/main/res/drawable-xxhdpi/ic_tag_text_outline_black_24dp_active.png create mode 100644 src/main/res/drawable-xxhdpi/ic_tag_text_outline_black_24dp_inactive.png create mode 100644 src/main/res/drawable-xxhdpi/ic_zip_box_black_24dp_active.png create mode 100644 src/main/res/drawable-xxhdpi/ic_zip_box_black_24dp_inactive.png create mode 100644 src/main/res/drawable-xxxhdpi/ic_cellphone_black_24dp_active.png create mode 100644 src/main/res/drawable-xxxhdpi/ic_cellphone_black_24dp_inactive.png create mode 100644 src/main/res/drawable-xxxhdpi/ic_info_black_24dp_active.png create mode 100644 src/main/res/drawable-xxxhdpi/ic_info_black_24dp_inactive.png create mode 100644 src/main/res/drawable-xxxhdpi/ic_link_black_24dp_active.png create mode 100644 src/main/res/drawable-xxxhdpi/ic_link_black_24dp_inactive.png create mode 100644 src/main/res/drawable-xxxhdpi/ic_phonelink_black_24dp_active.png create mode 100644 src/main/res/drawable-xxxhdpi/ic_phonelink_black_24dp_inactive.png create mode 100644 src/main/res/drawable-xxxhdpi/ic_qrcode_black_24dp_active.png create mode 100644 src/main/res/drawable-xxxhdpi/ic_qrcode_black_24dp_inactive.png create mode 100644 src/main/res/drawable-xxxhdpi/ic_tag_text_outline_black_24dp_active.png create mode 100644 src/main/res/drawable-xxxhdpi/ic_tag_text_outline_black_24dp_inactive.png create mode 100644 src/main/res/drawable-xxxhdpi/ic_zip_box_black_24dp_active.png create mode 100644 src/main/res/drawable-xxxhdpi/ic_zip_box_black_24dp_inactive.png create mode 100644 src/main/res/drawable/ic_cellphone_black_24dp.xml create mode 100644 src/main/res/drawable/ic_info_black_24dp.xml create mode 100644 src/main/res/drawable/ic_link_black_24dp.xml create mode 100644 src/main/res/drawable/ic_phonelink_black_24dp.xml create mode 100644 src/main/res/drawable/ic_qrcode_black_24dp.xml create mode 100644 src/main/res/drawable/ic_tag_text_outline_black_24dp.xml create mode 100644 src/main/res/drawable/ic_transparent_24dp.xml create mode 100644 src/main/res/drawable/ic_zip_box_black_24dp.xml create mode 100644 src/main/res/layout/fragment_device.xml delete mode 100644 src/main/res/xml/device_settings_create.xml delete mode 100644 src/main/res/xml/device_settings_edit.xml diff --git a/src/androidTest/java/com/nutomic/syncthingandroid/test/activities/MainActivityTest.java b/src/androidTest/java/com/nutomic/syncthingandroid/test/activities/MainActivityTest.java index 18b075ff..5d29ed43 100644 --- a/src/androidTest/java/com/nutomic/syncthingandroid/test/activities/MainActivityTest.java +++ b/src/androidTest/java/com/nutomic/syncthingandroid/test/activities/MainActivityTest.java @@ -3,7 +3,7 @@ package com.nutomic.syncthingandroid.test.activities; import android.test.ActivityInstrumentationTestCase2; import com.nutomic.syncthingandroid.activities.MainActivity; -import com.nutomic.syncthingandroid.fragments.DevicesFragment; +import com.nutomic.syncthingandroid.fragments.DeviceListFragment; import com.nutomic.syncthingandroid.fragments.FolderListFragment; import com.nutomic.syncthingandroid.syncthing.SyncthingServiceBinder; import com.nutomic.syncthingandroid.test.MockSyncthingService; @@ -20,7 +20,7 @@ public class MainActivityTest extends ActivityInstrumentationTestCase2 + android:theme="@style/Theme.Syncthing.Translucent" + android:launchMode="singleTop"/> diff --git a/src/main/java/com/nutomic/syncthingandroid/activities/MainActivity.java b/src/main/java/com/nutomic/syncthingandroid/activities/MainActivity.java index d725b289..37b37689 100644 --- a/src/main/java/com/nutomic/syncthingandroid/activities/MainActivity.java +++ b/src/main/java/com/nutomic/syncthingandroid/activities/MainActivity.java @@ -33,7 +33,7 @@ import android.view.ViewGroup; import android.widget.TextView; import com.nutomic.syncthingandroid.R; -import com.nutomic.syncthingandroid.fragments.DevicesFragment; +import com.nutomic.syncthingandroid.fragments.DeviceListFragment; import com.nutomic.syncthingandroid.fragments.DrawerFragment; import com.nutomic.syncthingandroid.fragments.FolderListFragment; import com.nutomic.syncthingandroid.syncthing.RestApi; @@ -45,8 +45,8 @@ import static java.lang.Math.min; /** * Shows {@link FolderListFragment} and - * {@link com.nutomic.syncthingandroid.fragments.DevicesFragment} in different tabs, and - * {@link com.nutomic.syncthingandroid.fragments.DrawerFragment} in the navigation drawer. + * {@link DeviceListFragment} in different tabs, and + * {@link DrawerFragment} in the navigation drawer. */ public class MainActivity extends SyncthingActivity implements SyncthingService.OnApiChangeListener { @@ -161,9 +161,9 @@ public class MainActivity extends SyncthingActivity public Fragment getItem(int position) { switch (position) { case 0: - return mFolderFragment; + return mFolderListFragment; case 1: - return mDevicesFragment; + return mDeviceListFragment; default: return null; } @@ -187,9 +187,9 @@ public class MainActivity extends SyncthingActivity } }; - private FolderListFragment mFolderFragment; + private FolderListFragment mFolderListFragment; - private DevicesFragment mDevicesFragment; + private DeviceListFragment mDeviceListFragment; private DrawerFragment mDrawerFragment; @@ -216,16 +216,16 @@ public class MainActivity extends SyncthingActivity if (savedInstanceState != null) { FragmentManager fm = getSupportFragmentManager(); - mFolderFragment = (FolderListFragment) fm.getFragment( + mFolderListFragment = (FolderListFragment) fm.getFragment( savedInstanceState, FolderListFragment.class.getName()); - mDevicesFragment = (DevicesFragment) fm.getFragment( - savedInstanceState, DevicesFragment.class.getName()); + mDeviceListFragment = (DeviceListFragment) fm.getFragment( + savedInstanceState, DeviceListFragment.class.getName()); mDrawerFragment = (DrawerFragment) fm.getFragment( savedInstanceState, DrawerFragment.class.getName()); mViewPager.setCurrentItem(savedInstanceState.getInt("currentTab")); } else { - mFolderFragment = new FolderListFragment(); - mDevicesFragment = new DevicesFragment(); + mFolderListFragment = new FolderListFragment(); + mDeviceListFragment = new DeviceListFragment(); mDrawerFragment = new DrawerFragment(); } @@ -247,8 +247,8 @@ public class MainActivity extends SyncthingActivity } if (getService() != null) { getService().unregisterOnApiChangeListener(this); - getService().unregisterOnApiChangeListener(mFolderFragment); - getService().unregisterOnApiChangeListener(mDevicesFragment); + getService().unregisterOnApiChangeListener(mFolderListFragment); + getService().unregisterOnApiChangeListener(mDeviceListFragment); } } @@ -256,8 +256,8 @@ public class MainActivity extends SyncthingActivity public void onServiceConnected(ComponentName componentName, IBinder iBinder) { super.onServiceConnected(componentName, iBinder); getService().registerOnApiChangeListener(this); - getService().registerOnApiChangeListener(mFolderFragment); - getService().registerOnApiChangeListener(mDevicesFragment); + getService().registerOnApiChangeListener(mFolderListFragment); + getService().registerOnApiChangeListener(mDeviceListFragment); } /** @@ -267,10 +267,10 @@ public class MainActivity extends SyncthingActivity protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); // Avoid crash if called during startup. - if (mFolderFragment != null && mDevicesFragment != null && mDrawerFragment != null) { + if (mFolderListFragment != null && mDeviceListFragment != null && mDrawerFragment != null) { FragmentManager fm = getSupportFragmentManager(); - fm.putFragment(outState, FolderListFragment.class.getName(), mFolderFragment); - fm.putFragment(outState, DevicesFragment.class.getName(), mDevicesFragment); + fm.putFragment(outState, FolderListFragment.class.getName(), mFolderListFragment); + fm.putFragment(outState, DeviceListFragment.class.getName(), mDeviceListFragment); fm.putFragment(outState, DrawerFragment.class.getName(), mDrawerFragment); outState.putInt("currentTab", mViewPager.getCurrentItem()); } diff --git a/src/main/java/com/nutomic/syncthingandroid/activities/SettingsActivity.java b/src/main/java/com/nutomic/syncthingandroid/activities/SettingsActivity.java index 17892e81..a1129f6f 100644 --- a/src/main/java/com/nutomic/syncthingandroid/activities/SettingsActivity.java +++ b/src/main/java/com/nutomic/syncthingandroid/activities/SettingsActivity.java @@ -3,10 +3,9 @@ package com.nutomic.syncthingandroid.activities; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; -import android.view.View; import com.nutomic.syncthingandroid.R; -import com.nutomic.syncthingandroid.fragments.DeviceSettingsFragment; +import com.nutomic.syncthingandroid.fragments.DeviceFragment; import com.nutomic.syncthingandroid.fragments.FolderFragment; import com.nutomic.syncthingandroid.fragments.SettingsFragment; @@ -27,7 +26,7 @@ public class SettingsActivity extends SyncthingActivity { * edited or a new one created. *

* If this is false, {@link FolderFragment#EXTRA_REPO_ID} or - * {@link com.nutomic.syncthingandroid.fragments.DeviceSettingsFragment#EXTRA_NODE_ID} must be set (according to the selected fragment). + * {@link DeviceFragment#EXTRA_NODE_ID} must be set (according to the selected fragment). */ public static final String EXTRA_IS_CREATE = "create"; @@ -50,7 +49,7 @@ public class SettingsActivity extends SyncthingActivity { mFragment = new SettingsFragment(); break; case ACTION_NODE_SETTINGS_FRAGMENT: - mFragment = new DeviceSettingsFragment(); + mFragment = new DeviceFragment(); if (!getIntent().hasExtra(EXTRA_IS_CREATE)) { throw new IllegalArgumentException("EXTRA_IS_CREATE must be set"); } @@ -87,16 +86,4 @@ public class SettingsActivity extends SyncthingActivity { public boolean getIsCreate() { return getIntent().getBooleanExtra(EXTRA_IS_CREATE, false); } - - /** - * Used for the QR code scanner in DeviceSettingsFragment. - * - * Instead of the cast, an interface could be used (if there are multiple fragments using this). - */ - public void onClick(View view) { - if (mFragment instanceof DeviceSettingsFragment) { - ((DeviceSettingsFragment) mFragment).onClick(view); - } - } - } diff --git a/src/main/java/com/nutomic/syncthingandroid/fragments/DeviceFragment.java b/src/main/java/com/nutomic/syncthingandroid/fragments/DeviceFragment.java new file mode 100644 index 00000000..b4e64483 --- /dev/null +++ b/src/main/java/com/nutomic/syncthingandroid/fragments/DeviceFragment.java @@ -0,0 +1,425 @@ +package com.nutomic.syncthingandroid.fragments; + +import android.content.DialogInterface; +import android.content.Intent; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.support.v7.app.AlertDialog; +import android.support.v7.widget.SwitchCompat; +import android.text.Editable; +import android.text.TextWatcher; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.CompoundButton; +import android.widget.EditText; +import android.widget.TextView; +import android.widget.Toast; + +import com.nutomic.syncthingandroid.R; +import com.nutomic.syncthingandroid.activities.SettingsActivity; +import com.nutomic.syncthingandroid.activities.SyncthingActivity; +import com.nutomic.syncthingandroid.syncthing.RestApi; +import com.nutomic.syncthingandroid.syncthing.SyncthingService; +import com.nutomic.syncthingandroid.util.BarcodeIntentIntegrator; +import com.nutomic.syncthingandroid.util.BarcodeIntentResult; +import com.nutomic.syncthingandroid.util.Compression; +import com.nutomic.syncthingandroid.util.TextWatcherAdapter; + +import java.util.List; +import java.util.Map; + +import static android.text.TextUtils.isEmpty; +import static android.view.View.GONE; +import static android.view.View.VISIBLE; +import static android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN; +import static com.nutomic.syncthingandroid.syncthing.SyncthingService.State.ACTIVE; +import static com.nutomic.syncthingandroid.util.Compression.METADATA; + +/** + * Shows device details and allows changing them. + */ +public class DeviceFragment extends Fragment implements + SyncthingActivity.OnServiceConnectedListener, RestApi.OnReceiveConnectionsListener, + SyncthingService.OnApiChangeListener, RestApi.OnDeviceIdNormalizedListener, + View.OnClickListener { + + public static final String EXTRA_NODE_ID = "device_id"; + + private static final String TAG = "DeviceSettingsFragment"; + + private static final String DYNAMIC_ADDRESSES = "dynamic"; + + private SyncthingService mSyncthingService; + + private RestApi.Device mDevice; + + private View mIdContainer; + + private EditText mIdView; + + private View mQrButton; + + private EditText mNameView; + + private EditText mAddressesView; + + private TextView mCurrentAddressView; + + private TextView mCompressionValueView; + + private SwitchCompat mIntroducerView; + + private TextView mSyncthingVersionView; + + private View mCompressionContainer; + + private boolean mIsCreateMode; + + private boolean mDeviceNeedsToUpdate; + + private DialogInterface.OnClickListener mCompressionEntrySelectedListener = new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + dialog.dismiss(); + + Compression compression = Compression.fromIndex(which); + // Don't pop the restart dialog unless the value is actually different. + if (compression != Compression.fromValue(getActivity(), mDevice.compression)) { + mDeviceNeedsToUpdate = true; + + mDevice.compression = compression.getValue(getActivity()); + mCompressionValueView.setText(compression.getTitle(getActivity())); + } + } + }; + + private TextWatcher mIdTextWatcher = new TextWatcherAdapter() { + @Override + public void afterTextChanged(Editable s) { + if (!s.toString().equals(mDevice.deviceID)) { + mDeviceNeedsToUpdate = true; + + mDevice.deviceID = s.toString(); + } + } + }; + + private TextWatcher mNameTextWatcher = new TextWatcherAdapter() { + @Override + public void afterTextChanged(Editable s) { + if (!s.toString().equals(mDevice.name)) { + mDeviceNeedsToUpdate = true; + + mDevice.name = s.toString(); + } + } + }; + + private TextWatcher mAddressesTextWatcher = new TextWatcherAdapter() { + @Override + public void afterTextChanged(Editable s) { + if (!s.toString().equals(mDevice.addresses)) { + mDeviceNeedsToUpdate = true; + + mDevice.addresses = persistableAddresses(s); + } + } + }; + + private CompoundButton.OnCheckedChangeListener mIntroducerCheckedChangeListener = new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + if (mDevice.introducer != isChecked) { + mDeviceNeedsToUpdate = true; + + mDevice.introducer = isChecked; + } + } + }; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + SettingsActivity activity = (SettingsActivity) getActivity(); + mIsCreateMode = activity.getIsCreate(); + activity.registerOnServiceConnectedListener(this); + activity.setTitle(mIsCreateMode ? R.string.add_device : R.string.edit_device); + setHasOptionsMenu(true); + + if (mIsCreateMode) { + if (savedInstanceState != null) { + mDevice = (RestApi.Device) savedInstanceState.getSerializable("device"); + } + if (mDevice == null) { + initDevice(); + } + } + } + + @Override + public void onDestroy() { + super.onDestroy(); + if (mSyncthingService != null) { + mSyncthingService.unregisterOnApiChangeListener(this); + } + } + + @Override + public void onPause() { + super.onPause(); + + // We don't want to update every time a TextView's character changes, + // so we hold off until the view stops being visible to the user. + if (mDeviceNeedsToUpdate) { + updateDevice(); + } + } + + /** + * Save current settings in case we are in create mode and they aren't yet stored in the config. + */ + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + outState.putSerializable("device", mDevice); + } + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + return inflater.inflate(R.layout.fragment_device, container, false); + } + + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + + mIdContainer = view.findViewById(R.id.idContainer); + mIdView = (EditText) view.findViewById(R.id.id); + mQrButton = view.findViewById(R.id.qrButton); + mNameView = (EditText) view.findViewById(R.id.name); + mAddressesView = (EditText) view.findViewById(R.id.addresses); + mCurrentAddressView = (TextView) view.findViewById(R.id.currentAddress); + mCompressionContainer = view.findViewById(R.id.compressionContainer); + mCompressionValueView = (TextView) view.findViewById(R.id.compressionValue); + mIntroducerView = (SwitchCompat) view.findViewById(R.id.introducer); + mSyncthingVersionView = (TextView) view.findViewById(R.id.syncthingVersion); + + mQrButton.setOnClickListener(this); + mCompressionContainer.setOnClickListener(this); + + if (!mIsCreateMode) { + prepareEditMode(); + } + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + + mIdView.removeTextChangedListener(mIdTextWatcher); + mNameView.removeTextChangedListener(mNameTextWatcher); + mAddressesView.removeTextChangedListener(mAddressesTextWatcher); + } + + @Override + public void onServiceConnected() { + mSyncthingService = ((SyncthingActivity) getActivity()).getService(); + mSyncthingService.registerOnApiChangeListener(this); + } + + /** + * Sets version and current address of the device. + *

+ * NOTE: This is only called once on startup, should be called more often to properly display + * version/address changes. + */ + @Override + public void onReceiveConnections(Map connections) { + boolean viewsExist = mSyncthingVersionView != null && mCurrentAddressView != null; + if (viewsExist && connections.containsKey(mDevice.deviceID)) { + mCurrentAddressView.setVisibility(VISIBLE); + mSyncthingVersionView.setVisibility(VISIBLE); + mCurrentAddressView.setText(connections.get(mDevice.deviceID).address); + mSyncthingVersionView.setText(connections.get(mDevice.deviceID).clientVersion); + } + } + + @Override + public void onApiChange(SyncthingService.State currentState) { + if (currentState != ACTIVE) { + getActivity().finish(); + return; + } + + if (!mIsCreateMode) { + List devices = mSyncthingService.getApi().getDevices(false); + for (int i = 0; i < devices.size(); i++) { + if (devices.get(i).deviceID.equals( + getActivity().getIntent().getStringExtra(EXTRA_NODE_ID))) { + mDevice = devices.get(i); + break; + } + } + if (mDevice == null) { + Log.w(TAG, "Device not found in API update"); + getActivity().finish(); + return; + } + } + + mSyncthingService.getApi().getConnections(this); + + updateViewsAndSetListeners(); + } + + private void updateViewsAndSetListeners() { + // Update views + mIdView.setText(mDevice.deviceID); + mNameView.setText((mDevice.name)); + mAddressesView.setText(displayableAddresses()); + mCompressionValueView.setText(Compression.fromValue(getActivity(), mDevice.compression).getTitle(getActivity())); + mIntroducerView.setChecked(mDevice.introducer); + + // Keep state updated + mIdView.addTextChangedListener(mIdTextWatcher); + mNameView.addTextChangedListener(mNameTextWatcher); + mAddressesView.addTextChangedListener(mAddressesTextWatcher); + mIntroducerView.setOnCheckedChangeListener(mIntroducerCheckedChangeListener); + } + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + super.onCreateOptionsMenu(menu, inflater); + inflater.inflate(R.menu.device_settings, menu); + } + + @Override + public void onPrepareOptionsMenu(Menu menu) { + menu.findItem(R.id.create).setVisible(mIsCreateMode); + menu.findItem(R.id.share_device_id).setVisible(!mIsCreateMode); + menu.findItem(R.id.delete).setVisible(!mIsCreateMode); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.create: + if (isEmpty(mDevice.deviceID)) { + Toast.makeText(getActivity(), R.string.device_id_required, Toast.LENGTH_LONG) + .show(); + return true; + } + if (isEmpty(mDevice.name)) { + Toast.makeText(getActivity(), R.string.device_name_required, Toast.LENGTH_LONG) + .show(); + return true; + } + mSyncthingService.getApi().editDevice(mDevice, getActivity(), this); + getActivity().finish(); + return true; + case R.id.share_device_id: + RestApi.shareDeviceId(getActivity(), mDevice.deviceID); + return true; + case R.id.delete: + new AlertDialog.Builder(getActivity()) + .setMessage(R.string.delete_device_confirm) + .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + mSyncthingService.getApi().deleteDevice(mDevice, getActivity()); + } + }) + .setNegativeButton(android.R.string.no, null) + .show(); + return true; + case android.R.id.home: + getActivity().finish(); + return true; + default: + return super.onOptionsItemSelected(item); + } + } + + /** + * Receives value of scanned QR code and sets it as device ID. + */ + @Override + public void onActivityResult(int requestCode, int resultCode, Intent intent) { + BarcodeIntentResult scanResult = BarcodeIntentIntegrator.parseActivityResult(requestCode, resultCode, intent); + if (scanResult != null) { + mDevice.deviceID = scanResult.getContents(); + mIdView.setText(mDevice.deviceID); + } + } + + /** + * Callback for {@link RestApi#editDevice}. + * Displays an error toast if error message present. + */ + @Override + public void onDeviceIdNormalized(String normalizedId, String error) { + if (error != null) { + Toast.makeText(getActivity(), error, Toast.LENGTH_LONG).show(); + } + } + + private void initDevice() { + mDevice = new RestApi.Device(); + mDevice.name = ""; + mDevice.deviceID = ""; + mDevice.addresses = "dynamic"; + mDevice.compression = METADATA.getValue(getActivity()); + mDevice.introducer = false; + } + + private void prepareEditMode() { + getActivity().getWindow().setSoftInputMode(SOFT_INPUT_STATE_ALWAYS_HIDDEN); + + mIdView.setEnabled(false); + mQrButton.setVisibility(GONE); + + mIdContainer.setOnClickListener(this); + } + + /** + * Sends the updated device info if in edit mode. + */ + private void updateDevice() { + if (!mIsCreateMode && mDeviceNeedsToUpdate) { + mSyncthingService.getApi().editDevice(mDevice, getActivity(), this); + } + } + + private String persistableAddresses(CharSequence userInput) { + return isEmpty(userInput) ? DYNAMIC_ADDRESSES : userInput.toString(); + } + + private String displayableAddresses() { + return DYNAMIC_ADDRESSES.equals(mDevice.addresses) ? "" : mDevice.addresses; + } + + @Override + public void onClick(View v) { + if (v.equals(mCompressionContainer)) { + new AlertDialog.Builder(getActivity()) + .setTitle(R.string.compression) + .setSingleChoiceItems(R.array.compress_entries, + Compression.fromValue(getActivity(), mDevice.compression).getIndex(), + mCompressionEntrySelectedListener) + .show(); + } else if (v.equals(mQrButton)){ + BarcodeIntentIntegrator integrator = new BarcodeIntentIntegrator(DeviceFragment.this); + integrator.initiateScan(); + } else if (v.equals(mIdContainer)) { + mSyncthingService.getApi().copyDeviceId(mDevice.deviceID); + } + } +} diff --git a/src/main/java/com/nutomic/syncthingandroid/fragments/DevicesFragment.java b/src/main/java/com/nutomic/syncthingandroid/fragments/DeviceListFragment.java similarity index 95% rename from src/main/java/com/nutomic/syncthingandroid/fragments/DevicesFragment.java rename to src/main/java/com/nutomic/syncthingandroid/fragments/DeviceListFragment.java index ba24e923..a6f3be63 100644 --- a/src/main/java/com/nutomic/syncthingandroid/fragments/DevicesFragment.java +++ b/src/main/java/com/nutomic/syncthingandroid/fragments/DeviceListFragment.java @@ -23,7 +23,7 @@ import java.util.TimerTask; /** * Displays a list of all existing devices. */ -public class DevicesFragment extends ListFragment implements SyncthingService.OnApiChangeListener, +public class DeviceListFragment extends ListFragment implements SyncthingService.OnApiChangeListener, ListView.OnItemClickListener { private DevicesAdapter mAdapter; @@ -96,7 +96,7 @@ public class DevicesFragment extends ListFragment implements SyncthingService.On Intent intent = new Intent(getActivity(), SettingsActivity.class); intent.setAction(SettingsActivity.ACTION_NODE_SETTINGS_FRAGMENT); intent.putExtra(SettingsActivity.EXTRA_IS_CREATE, false); - intent.putExtra(DeviceSettingsFragment.EXTRA_NODE_ID, mAdapter.getItem(i).deviceID); + intent.putExtra(DeviceFragment.EXTRA_NODE_ID, mAdapter.getItem(i).deviceID); startActivity(intent); } diff --git a/src/main/java/com/nutomic/syncthingandroid/fragments/DeviceSettingsFragment.java b/src/main/java/com/nutomic/syncthingandroid/fragments/DeviceSettingsFragment.java deleted file mode 100644 index eed7f7f7..00000000 --- a/src/main/java/com/nutomic/syncthingandroid/fragments/DeviceSettingsFragment.java +++ /dev/null @@ -1,330 +0,0 @@ -package com.nutomic.syncthingandroid.fragments; - -import android.app.Activity; -import android.app.AlertDialog; -import android.content.ActivityNotFoundException; -import android.content.DialogInterface; -import android.content.Intent; -import android.os.Bundle; -import android.preference.CheckBoxPreference; -import android.preference.EditTextPreference; -import android.preference.ListPreference; -import android.preference.Preference; -import android.support.v4.app.Fragment; -import android.support.v4.preference.PreferenceFragment; -import android.util.Log; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.View; -import android.widget.Toast; - -import com.nutomic.syncthingandroid.R; -import com.nutomic.syncthingandroid.activities.SettingsActivity; -import com.nutomic.syncthingandroid.activities.SyncthingActivity; -import com.nutomic.syncthingandroid.syncthing.RestApi; -import com.nutomic.syncthingandroid.syncthing.SyncthingService; -import com.nutomic.syncthingandroid.util.BarcodeIntentIntegrator; -import com.nutomic.syncthingandroid.util.BarcodeIntentResult; - -import java.util.List; -import java.util.Map; - -/** - * Shows device details and allows changing them. - */ -public class DeviceSettingsFragment extends PreferenceFragment implements - SyncthingActivity.OnServiceConnectedListener, Preference.OnPreferenceChangeListener, - Preference.OnPreferenceClickListener, RestApi.OnReceiveConnectionsListener, - SyncthingService.OnApiChangeListener, RestApi.OnDeviceIdNormalizedListener { - - public static final String EXTRA_NODE_ID = "device_id"; - - private static final String TAG = "DeviceSettingsFragment"; - - private static final int SCAN_QR_REQUEST_CODE = 235; - - private SyncthingService mSyncthingService; - - private RestApi.Device mDevice; - - private Preference mDeviceId; - - private EditTextPreference mName; - - private EditTextPreference mAddresses; - - private ListPreference mCompression; - - private CheckBoxPreference mIntroducer; - - private Preference mVersion; - - private Preference mCurrentAddress; - - private boolean mIsCreate; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - ((SyncthingActivity) getActivity()).registerOnServiceConnectedListener(this); - - mIsCreate = ((SettingsActivity) getActivity()).getIsCreate(); - setHasOptionsMenu(true); - - if (mIsCreate) { - addPreferencesFromResource(R.xml.device_settings_create); - } else { - addPreferencesFromResource(R.xml.device_settings_edit); - } - - mDeviceId = findPreference("device_id"); - mDeviceId.setOnPreferenceChangeListener(this); - mName = (EditTextPreference) findPreference("name"); - mName.setOnPreferenceChangeListener(this); - mAddresses = (EditTextPreference) findPreference("addresses"); - mAddresses.setOnPreferenceChangeListener(this); - mCompression = (ListPreference) findPreference("compression"); - mCompression.setOnPreferenceChangeListener(this); - mIntroducer = (CheckBoxPreference) findPreference("introducer"); - mIntroducer.setOnPreferenceChangeListener(this); - if (!mIsCreate) { - mVersion = findPreference("version"); - mVersion.setSummary("?"); - mCurrentAddress = findPreference("current_address"); - mCurrentAddress.setSummary("?"); - } - - if (mIsCreate) { - if (savedInstanceState != null) { - mDevice = (RestApi.Device) savedInstanceState.getSerializable("device"); - } - if (mDevice == null) { - mDevice = new RestApi.Device(); - mDevice.name = ""; - mDevice.deviceID = ""; - mDevice.addresses = "dynamic"; - mDevice.compression = "metadata"; - mDevice.introducer = false; - ((EditTextPreference) mDeviceId).setText(mDevice.deviceID); - } - } - } - - /** - * Save current settings in case we are in create mode and they aren't yet stored in the config. - */ - @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - outState.putSerializable("device", mDevice); - } - - @Override - public void onServiceConnected() { - mSyncthingService = ((SyncthingActivity) getActivity()).getService(); - mSyncthingService.registerOnApiChangeListener(this); - } - - @Override - public void onDestroy() { - super.onDestroy(); - mSyncthingService.unregisterOnApiChangeListener(this); - } - - @Override - public void onApiChange(SyncthingService.State currentState) { - if (currentState != SyncthingService.State.ACTIVE) { - getActivity().finish(); - return; - } - - if (mIsCreate) - getActivity().setTitle(R.string.add_device); - else { - RestApi.Device device = null; - getActivity().setTitle(R.string.edit_device); - List devices = mSyncthingService.getApi().getDevices(false); - for (int i = 0; i < devices.size(); i++) { - if (devices.get(i).deviceID.equals( - getActivity().getIntent().getStringExtra(EXTRA_NODE_ID))) { - device = devices.get(i); - break; - } - } - if (device == null) { - Log.w(TAG, "Device not found in API update"); - getActivity().finish(); - return; - } - mDevice = device; - mDeviceId.setOnPreferenceClickListener(this); - } - - mSyncthingService.getApi().getConnections(DeviceSettingsFragment.this); - - mDeviceId.setSummary(mDevice.deviceID); - mName.setText((mDevice.name)); - mName.setSummary(mDevice.name); - mAddresses.setText(mDevice.addresses); - mAddresses.setSummary(mDevice.addresses); - mCompression.setValue(mDevice.compression); - mCompression.setSummary(mDevice.compression); - mIntroducer.setChecked(mDevice.introducer); - } - - @Override - public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { - super.onCreateOptionsMenu(menu, inflater); - inflater.inflate(R.menu.device_settings, menu); - } - - @Override - public void onPrepareOptionsMenu(Menu menu) { - menu.findItem(R.id.create).setVisible(mIsCreate); - menu.findItem(R.id.share_device_id).setVisible(!mIsCreate); - menu.findItem(R.id.delete).setVisible(!mIsCreate); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.create: - if (mDevice.deviceID.equals("")) { - Toast.makeText(getActivity(), R.string.device_id_required, Toast.LENGTH_LONG) - .show(); - return true; - } - if (mDevice.name.equals("")) { - Toast.makeText(getActivity(), R.string.device_name_required, Toast.LENGTH_LONG) - .show(); - return true; - } - mSyncthingService.getApi().editDevice(mDevice, getActivity(), this); - getActivity().finish(); - return true; - case R.id.share_device_id: - RestApi.shareDeviceId(getActivity(), mDevice.deviceID); - return true; - case R.id.delete: - new AlertDialog.Builder(getActivity()) - .setMessage(R.string.delete_device_confirm) - .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - mSyncthingService.getApi().deleteDevice(mDevice, getActivity()); - } - }) - .setNegativeButton(android.R.string.no, null) - .show(); - return true; - case android.R.id.home: - getActivity().finish(); - return true; - default: - return super.onOptionsItemSelected(item); - } - } - - @Override - public boolean onPreferenceChange(Preference preference, Object o) { - if (preference instanceof EditTextPreference) { - EditTextPreference pref = (EditTextPreference) preference; - pref.setSummary((String) o); - } - if (preference instanceof ListPreference) { - ListPreference pref = (ListPreference) preference; - pref.setSummary((String) o); - } - if (preference.equals(mDeviceId)) { - mDevice.deviceID = (String) o; - deviceUpdated(); - return true; - } else if (preference.equals(mName)) { - mDevice.name = (String) o; - deviceUpdated(); - return true; - } else if (preference.equals(mAddresses)) { - mDevice.addresses = (String) o; - deviceUpdated(); - return true; - } else if (preference.equals(mCompression)) { - mDevice.compression = (String) o; - deviceUpdated(); - return true; - } else if (preference.equals(mIntroducer)) { - mDevice.introducer = (Boolean) o; - deviceUpdated(); - return true; - } - return false; - } - - @Override - public boolean onPreferenceClick(Preference preference) { - if (preference.equals(mDeviceId)) { - mSyncthingService.getApi().copyDeviceId(mDevice.deviceID); - return true; - } - return false; - } - - /** - * Sets version and current address of the device. - * - * NOTE: This is only called once on startup, should be called more often to properly display - * version/address changes. - */ - @Override - public void onReceiveConnections(Map connections) { - if (mVersion == null || mCurrentAddress == null) - return; - if (connections.containsKey(mDevice.deviceID)) { - mVersion.setSummary(connections.get(mDevice.deviceID).clientVersion); - mCurrentAddress.setSummary(connections.get(mDevice.deviceID).address); - } - } - - /** - * Sends the updated device info if in edit mode. - */ - private void deviceUpdated() { - if (!mIsCreate) { - mSyncthingService.getApi().editDevice(mDevice, getActivity(), this); - } - } - - /** - * Sends QR code scanning intent when clicking the QR code icon. - */ - public void onClick(View view) { - BarcodeIntentIntegrator integrator = new BarcodeIntentIntegrator(this); - integrator.initiateScan(); - } - - /** - * Receives value of scanned QR code and sets it as device ID. - */ - @Override - public void onActivityResult(int requestCode, int resultCode, Intent intent) { - BarcodeIntentResult scanResult = BarcodeIntentIntegrator.parseActivityResult(requestCode, resultCode, intent); - if (scanResult != null) { - mDevice.deviceID = scanResult.getContents(); - ((EditTextPreference) mDeviceId).setText(mDevice.deviceID); - mDeviceId.setSummary(mDevice.deviceID); - } - } - - /** - * Callback for {@link RestApi#editDevice}. - * Displays an error toast if error message present. - */ - @Override - public void onDeviceIdNormalized(String normalizedId, String error) { - if (error != null) { - Toast.makeText(getActivity(), error, Toast.LENGTH_LONG).show(); - } - } - -} diff --git a/src/main/java/com/nutomic/syncthingandroid/fragments/FolderFragment.java b/src/main/java/com/nutomic/syncthingandroid/fragments/FolderFragment.java index afce907e..e9ce9b98 100644 --- a/src/main/java/com/nutomic/syncthingandroid/fragments/FolderFragment.java +++ b/src/main/java/com/nutomic/syncthingandroid/fragments/FolderFragment.java @@ -32,6 +32,7 @@ import com.nutomic.syncthingandroid.syncthing.RestApi; import com.nutomic.syncthingandroid.syncthing.RestApi.SimpleVersioning; import com.nutomic.syncthingandroid.syncthing.RestApi.Versioning; import com.nutomic.syncthingandroid.syncthing.SyncthingService; +import com.nutomic.syncthingandroid.util.TextWatcherAdapter; import java.util.ArrayList; import java.util.List; @@ -76,7 +77,7 @@ public class FolderFragment extends Fragment private TextView mVersioningKeepView; - private boolean mIsCreate; + private boolean mIsCreateMode; private KeepVersionsDialogFragment mKeepVersionsDialogFragment = new KeepVersionsDialogFragment(); @@ -154,12 +155,12 @@ public class FolderFragment extends Fragment super.onCreate(savedInstanceState); SettingsActivity activity = (SettingsActivity) getActivity(); - mIsCreate = activity.getIsCreate(); - activity.setTitle(isCreatingFolder() ? R.string.create_folder : R.string.edit_folder); + mIsCreateMode = activity.getIsCreate(); + activity.setTitle(mIsCreateMode ? R.string.create_folder : R.string.edit_folder); activity.registerOnServiceConnectedListener(this); setHasOptionsMenu(true); - if (isCreatingFolder()) { + if (mIsCreateMode) { if (savedInstanceState != null) { mFolder = (RestApi.Folder) savedInstanceState.getSerializable("folder"); } @@ -169,6 +170,14 @@ public class FolderFragment extends Fragment } } + @Override + public void onDestroy() { + super.onDestroy(); + if (mSyncthingService != null) { + mSyncthingService.unregisterOnApiChangeListener(this); + } + } + /** * Save current settings in case we are in create mode and they aren't yet stored in the config. */ @@ -196,11 +205,50 @@ public class FolderFragment extends Fragment mPathView.setOnClickListener(mPathViewClickListener); view.findViewById(R.id.versioningContainer).setOnClickListener(mVersioningContainerClickListener); - if (isEditingFolder()) { + if (!mIsCreateMode) { prepareEditMode(); } } + @Override + public void onDestroyView() { + super.onDestroyView(); + mIdView.removeTextChangedListener(mIdTextWatcher); + mPathView.removeTextChangedListener(mPathTextWatcher); + } + + @Override + public void onServiceConnected() { + mSyncthingService = ((SyncthingActivity) getActivity()).getService(); + mSyncthingService.registerOnApiChangeListener(this); + } + + @Override + public void onApiChange(SyncthingService.State currentState) { + if (currentState != ACTIVE) { + getActivity().finish(); + return; + } + + if (!mIsCreateMode) { + List folders = mSyncthingService.getApi().getFolders(); + String passedId = getActivity().getIntent().getStringExtra(EXTRA_REPO_ID); + for (RestApi.Folder currentFolder : folders) { + if (currentFolder.id.equals(passedId)) { + mFolder = currentFolder; + break; + } + } + if (mFolder == null) { + Log.w(TAG, "Folder not found in API update"); + getActivity().finish(); + return; + } + } + + updateViewsAndSetListeners(); + } + private void updateViewsAndSetListeners() { // Update views mIdView.setText(mFolder.id); @@ -233,53 +281,6 @@ public class FolderFragment extends Fragment mKeepVersionsDialogFragment.setOnValueChangeListener(mOnValueChangeListener); } - @Override - public void onDestroyView() { - super.onDestroyView(); - mIdView.removeTextChangedListener(mIdTextWatcher); - mPathView.removeTextChangedListener(mPathTextWatcher); - } - - @Override - public void onApiChange(SyncthingService.State currentState) { - if (currentState != ACTIVE) { - getActivity().finish(); - return; - } - - if (isEditingFolder()) { - List folders = mSyncthingService.getApi().getFolders(); - String passedId = getActivity().getIntent().getStringExtra(EXTRA_REPO_ID); - for (RestApi.Folder currentFolder : folders) { - if (currentFolder.id.equals(passedId)) { - mFolder = currentFolder; - break; - } - } - if (mFolder == null) { - Log.w(TAG, "Folder not found in API update"); - getActivity().finish(); - return; - } - } - - updateViewsAndSetListeners(); - } - - @Override - public void onServiceConnected() { - mSyncthingService = ((SyncthingActivity) getActivity()).getService(); - mSyncthingService.registerOnApiChangeListener(this); - } - - @Override - public void onDestroy() { - super.onDestroy(); - if (mSyncthingService != null) { - mSyncthingService.unregisterOnApiChangeListener(this); - } - } - @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { super.onCreateOptionsMenu(menu, inflater); @@ -288,8 +289,8 @@ public class FolderFragment extends Fragment @Override public void onPrepareOptionsMenu(Menu menu) { - menu.findItem(R.id.create).setVisible(isCreatingFolder()); - menu.findItem(R.id.delete).setVisible(isEditingFolder()); + menu.findItem(R.id.create).setVisible(mIsCreateMode); + menu.findItem(R.id.delete).setVisible(!mIsCreateMode); } @Override @@ -324,8 +325,9 @@ public class FolderFragment extends Fragment case android.R.id.home: getActivity().finish(); return true; + default: + return super.onOptionsItemSelected(item); } - return super.onOptionsItemSelected(item); } @Override @@ -355,7 +357,6 @@ public class FolderFragment extends Fragment private void addEmptyDeviceListView() { LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(WRAP_CONTENT, dp(48, getActivity())); - // 72dp margin to align with dividers int dividerInset = getResources().getDimensionPixelOffset(R.dimen.material_divider_inset); int contentInset = getResources().getDimensionPixelOffset(R.dimen.abc_action_bar_content_inset_material); setMarginStart(params, dividerInset); @@ -376,28 +377,8 @@ public class FolderFragment extends Fragment } private void updateRepo() { - if (isEditingFolder()) { + if (!mIsCreateMode) { mSyncthingService.getApi().editFolder(mFolder, false, getActivity()); } } - - private boolean isEditingFolder() { - return !mIsCreate; - } - - private boolean isCreatingFolder() { - return mIsCreate; - } - - private class TextWatcherAdapter implements TextWatcher { - - @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) {} - - @Override - public void onTextChanged(CharSequence s, int start, int before, int count) {} - - @Override - public void afterTextChanged(Editable s) {} - } } diff --git a/src/main/java/com/nutomic/syncthingandroid/util/Compression.java b/src/main/java/com/nutomic/syncthingandroid/util/Compression.java new file mode 100644 index 00000000..28063ecb --- /dev/null +++ b/src/main/java/com/nutomic/syncthingandroid/util/Compression.java @@ -0,0 +1,57 @@ +package com.nutomic.syncthingandroid.util; + +import android.content.Context; + +import com.nutomic.syncthingandroid.R; + +/** + * Device compression attribute helper. This unifies operations between string values as expected by + * Syncthing with string values as displayed to the user and int ordinals as expected by the dialog + * click interface. + */ +public enum Compression { + NONE(0), + METADATA(1), + ALWAYS(2); + + private final int index; + + Compression(int index) { + this.index = index; + } + + public int getIndex() { + return index; + } + + public String getValue(Context context) { + return context.getResources().getStringArray(R.array.compress_values)[index]; + } + + public String getTitle(Context context) { + return context.getResources().getStringArray(R.array.compress_entries)[index]; + } + + public static Compression fromIndex(int index) { + switch (index) { + case 0: + return NONE; + case 2: + return ALWAYS; + default: + return METADATA; + } + } + + public static Compression fromValue(Context context, String value) { + int index = 0; + String[] values = context.getResources().getStringArray(R.array.compress_values); + for (int i = 0; i < values.length; i++) { + if (values[i].equals(value)) { + index = i; + } + } + + return fromIndex(index); + } +} diff --git a/src/main/java/com/nutomic/syncthingandroid/util/TextWatcherAdapter.java b/src/main/java/com/nutomic/syncthingandroid/util/TextWatcherAdapter.java new file mode 100644 index 00000000..ee9f2888 --- /dev/null +++ b/src/main/java/com/nutomic/syncthingandroid/util/TextWatcherAdapter.java @@ -0,0 +1,16 @@ +package com.nutomic.syncthingandroid.util; + +import android.text.Editable; +import android.text.TextWatcher; + +public class TextWatcherAdapter implements TextWatcher { + + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) {} + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) {} + + @Override + public void afterTextChanged(Editable s) {} +} diff --git a/src/main/java/com/nutomic/syncthingandroid/widget/EnhancedEditText.java b/src/main/java/com/nutomic/syncthingandroid/widget/EnhancedEditText.java new file mode 100644 index 00000000..5df51557 --- /dev/null +++ b/src/main/java/com/nutomic/syncthingandroid/widget/EnhancedEditText.java @@ -0,0 +1,50 @@ +package com.nutomic.syncthingandroid.widget; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.inputmethod.EditorInfo; +import android.view.inputmethod.InputConnection; +import android.widget.EditText; + +import static android.view.inputmethod.EditorInfo.IME_FLAG_NO_ENTER_ACTION; + +/** + * Apparently EditText blocks touch event propagation to the parent even + * when disabled/not clickable/not focusable. Therefore we have to manually + * check whether we are enabled and either ignore the event or process it normally.
+ *
+ * This class also blocks the default EditText behaviour of textMultiLine flag enforcing replacement + * of the IME action button with the new line character. This allows rendering soft wraps on single + * line input. + */ +public class EnhancedEditText extends EditText { + + public EnhancedEditText(Context context) { + super(context); + } + + public EnhancedEditText(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public EnhancedEditText(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + if (isEnabled()) { + return super.onTouchEvent(event); + } else { + return false; + } + } + + @Override + public InputConnection onCreateInputConnection(EditorInfo outAttrs) { + InputConnection conn = super.onCreateInputConnection(outAttrs); + outAttrs.imeOptions &= ~IME_FLAG_NO_ENTER_ACTION; + return conn; + } +} diff --git a/src/main/res/drawable-hdpi/ic_cellphone_black_24dp_active.png b/src/main/res/drawable-hdpi/ic_cellphone_black_24dp_active.png new file mode 100644 index 0000000000000000000000000000000000000000..23f0c445dde1a0861817a234bbb02129926bfe3c GIT binary patch literal 137 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k0wldT1B8K8fTxRNNCo5DX&ZSDC|k0wldT1B8K;zo(01NCo5DYa4kFIB>8W%w-Pb z7Fzay(Vc_Ejj{{U_2-NH&{tpam??Nhd)9OdUq?^wSzdQTUfeLrSlB8Sm9en<{jK!v j_dOatd(0;PTgp5mNRJ5X#8VF4`I?IRdijBF(9nc7!+BBW=a^`d`T?;S+gU0uzb( zSz;p4;;FLX!~@Bc=xHeQMM4&ebiC!bAO!{7^2`rX*mY^@f>d<=`!-TpN5&?9Vs7-$ zZuzs*@ZyAI>jCJIY)3Ra57SV>qqGQ8`f92jN9`h{XyPYlhGlS?IADNe^O z=R!sn%mh4@oXE(Ei6cL83`m6$x1M<*mEPA<1JdA7-bUJ7-pUsyeiCM%h1oq{T#!Wr z0HORT8?dZ0kGUssLeUY)t&wtbG&R%tboI8ccv6rb!fdzx@` kL`D*?*~G||4#)rT0j0dGvQ8xPtpET307*qoM6N<$g0=N}b^rhX literal 0 HcmV?d00001 diff --git a/src/main/res/drawable-hdpi/ic_link_black_24dp_active.png b/src/main/res/drawable-hdpi/ic_link_black_24dp_active.png new file mode 100644 index 0000000000000000000000000000000000000000..2cc6a5a38f1354b0cf52fc6d5f2b4a849d7bf4ac GIT binary patch literal 294 zcmV+>0oneEP)X=?&j z8NyJ+6n7}A5P%S6^}sX*>>yO`iK6Y1hl8SB;xf-%vK|0>m`lsy0!4Gl(#9u3I2g)d za1i2?b~0=u#1WM^Mu=T9+#o~?DPe(9S`p%g4DW~+(y2h{UJ)N;_(VL{<3zWJZ<;H5 zw6=VYwoBzN`wSs=$j}}iez)x558}h$Miw7MyTWH7tzH0nGuHWBqi7C!>{a}U>`=fI s_hp~xj!B9z46$7DH?qtih6Z3+zX?uq&;rYMa{vGU07*qoM6N<$f`m?d5&!@I literal 0 HcmV?d00001 diff --git a/src/main/res/drawable-hdpi/ic_link_black_24dp_inactive.png b/src/main/res/drawable-hdpi/ic_link_black_24dp_inactive.png new file mode 100644 index 0000000000000000000000000000000000000000..b0effd9374a89134dd9b85f0773f74f57efde04b GIT binary patch literal 268 zcmV+n0rUQeP)IzceHedq|2qX<$jqHJQ;A_$Vj@^9Yn*V2^XC=-TR16CS*Mmg?l3tW z0GvYoJ^NJPt3%6)WJn1Y7BCfDKEIj$P02TF)MEn)eFy9Dmzw07h;VG z$Z)I5MgDOr{AW>PZprY9;gK|^!Zc4hTpHcb!x$6YsnbHIqb-#kE$DICiN^T(@V|8m z{~VX);fKq=guLW1|k0wldT1B8K8tfz}(NCjiE#GwR{4F*39O^iw= zvIaKDyG$r*mRgx25YnMzP{Z>n@r47w>VgjQlWdMX2Ti(CnhTD~?qpMJOw7Ho!f`R% x#3-SpF8(==Ke`1k@qRiMwV~38$I*a`;br^@E~oyNi-8s~c)I$ztaD0e0szMjFH-;j literal 0 HcmV?d00001 diff --git a/src/main/res/drawable-hdpi/ic_phonelink_black_24dp_inactive.png b/src/main/res/drawable-hdpi/ic_phonelink_black_24dp_inactive.png new file mode 100644 index 0000000000000000000000000000000000000000..3d0ab6e49186ccc124a9241aa21bab724ccaf570 GIT binary patch literal 148 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k0wldT1B8K8w5N+>NCo5DDS=!K3IeR{>n2t3 zB;NnaFZyNbq>0`Fr_TL3|J=avpxZKq>7tT5*J{MKmb^-u8*nIK@x)`!ZFyThPO!3a x7N5rFs^N54J>>QMh5y{XTsyw;t&c|m!#~IPb+_9#O8~85@O1TaS?83{1OPpxHlhFk literal 0 HcmV?d00001 diff --git a/src/main/res/drawable-hdpi/ic_qrcode.png b/src/main/res/drawable-hdpi/ic_qrcode.png deleted file mode 100644 index 3f7475eccfd923b522f942e0e151ed0765fd7a48..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 942 zcmV;f15x~mP)424|?jZg@M&}c0mpIN#%OO20Dv0++9;PQ7;hB>003atFaSAc zb7%p8;3Qn@SO5Tkxd3v`V#UI%7b^f7f_OzlXQbBqGyuKYKMjCa)+EeFp69+&zIZLD z*B6kk0RRA)+CLP)x~`_UsTp0>Yym)HJ)IS|6-Q&U-qb!x#4=0q_kw(@|@(O z=HK&NW0DUS0Q?mI+Dwwp5b1rj5Fz>J&qz;FP(Jd<)j&8UBC?r4nB(f;QEuSEl?QxV=IY4z_F002On0H9IQrifScTqo}=+Cj^* zh&dnvfRqCatGTgy+~W=MR3g0qNS|%E4*&q5lK?x=O?L=00000(7S^)0JH?A@mpIp{rUX6-7KEN z_->z+V_pm3L6vgrgG<_Ps42MbQy}|{IojGT zuK?h!03zNOqydm-$*&DTUU>m{6R)-XAD4u^0ssK0w(HLV82P>+ZHBA8Jzd*0($2Q> z(pGB!$Nf>eW}Z>5Rb$psu2n(S2_XOg000E_IRrrv1VIo4K@bE%5cCE52c%VJ<_4D(}V(cmY?P=<$Jy(o)LQMnz1{UEuxKJ1|e{&7n1h*3f@!ZD@#K}MHY5Itkm z!5u96c8rn7ipw&i3CFH7+Ect&MlLHRWk$1HY#20 zV}b_^*(jtqWTPPtDOCnWDYgK9d_-RYDKM)ZU}aU=T5Yt&cg=(S~z9q}=(FGd?%nVLW* z=tx%i9CctJpl`>VqcsBJt!OHrY0{~r~^O%Pg?klyVp7P34Yya4~W+p%HZIc7BD`awbG*oaAj23#Z1 zcaWgOj&m<)VI3uCL?vA@N>F6S;svcHsE{ruX!U{;BC$OY)Yy?;y4fbk-|S|1*z8Oy zKWw%kEM`MhcRU}1k!dTsZZ#|lb5)gq(i!_6WzskO_zUyVQ`>ZOugR&gPWm3bWJWqD zle)!3JT^0O_GnV~=up{Ei8sdYV34=QkOfBLbnelBfK1;(JjckyE9LQTw(Up6$a?FZ zS2eatz5eZ`uOC>1$6k=%kA%+;THK&)JEY&UIf!)-Ub5qib$EGWgL{u&&>^7~6+S-b bDtPTxxU-vPEof&(Wozp$||r1vWG^87+Yk-KTCaUb5cdZ(}{TsNDTHJ>>U` zSa2pd zz<^VW(J6!OY*;#sPC4gP7%|k0wldT1B8LpJ5LwKkP619mmAv-JBYYF+$_j* zOOcuNVAj?JS<=~_t2_7nch$^c(q0q9dBYRIkiBpVcN!&R~ok;oVl1-a_Xnw zF_x;5SK?_~JQvrn`IWgZtznbWE1mK^NWP^itBk+@>y;0GB$;;hb-FH6nsW5f!5E>H zjiH{)tZx5GpVd%x>b}SFoV*)rXLNFCeRVw$Wz6ZY^qz~`f{|k0wldT1B8K8t*47)NCo5DsoiV`40v4M%d_6T zzxB<+voFH=S+CA;YhG8yR3JOC+u>+ZyL(U%`^j1Co|ZklqL0jYqeDG5GE4poFzu8v zy682f$~C6Nf3FAMZbp~sS9|XiEDC6OKQoFuc$-?wV}rG>+Jd+5zL>A{yWAyVYn!9M fg1+f@4?JS6U)Zc9_)c^k&>;+-u6{1-oD!M!s2 literal 0 HcmV?d00001 diff --git a/src/main/res/drawable-hdpi/ic_zip_box_black_24dp_inactive.png b/src/main/res/drawable-hdpi/ic_zip_box_black_24dp_inactive.png new file mode 100644 index 0000000000000000000000000000000000000000..f64ae58966b76fd38e176167969d820db62f9336 GIT binary patch literal 178 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k0wldT1B8K8rKgKyNCo5DsfK(96gXV}>vp6s z$8bL!(jnV9%+u|TT-pOZWABuNDxl6h}zoIelK2j?{^ii zlz7*ush^jem|Dpg*f~p3UwzW5n6g{5a(0=9UrXJl7O2!a`{H?5nbN+DR}Ml_0cTFy c?I~pbH+iSh3AN(oKu0imy85}Sb4q9e0Lb4%asU7T literal 0 HcmV?d00001 diff --git a/src/main/res/drawable-mdpi/ic_qrcode.png b/src/main/res/drawable-mdpi/ic_qrcode.png deleted file mode 100644 index c20e21bfa5bb671f7acb6ff695dc3dabe48f77f4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 857 zcmV-f1E&0mP)6iS#9=)e*vg%T{m5-frJvFExmlkiY@Z)fJ^o|8XHhT%d!aTp8+ zgTY`h7*N6LdYqlysm4``LAl z-JH+iP@1E4{%!<#@6`l^3-$OK0o%5z`gF0a^LHcQu4n{c=WA2p1~CHKR^J(=DDWLH z0$RcI^^zd8NqIh`6b2=I0AV!7c+z`39_pAb1PmAKttMHi34=9Z^nwrRLjVs$Qaz6Z zhSuy{pT~1b0LIWTriDl;jM6%T%-@Fq?T>$D%bLDKKuH?(`x1aubXk@>4CkJnB+y4s z52s|`_ncT?0R4bznvQ23^!pM}vhNyc%>#bi2k=4#Hp;uZRHPl8=lK)`q!WbS^4>q4 zAn3!x<6T8pxeXUok=1Dpc-XR!dB0whv*36K&YB@t`GCAtf^do`xLlYD^UXN-Vm z4q8Mb01KxJkru$g%jt?JWCU~}p!NFzem98PpN2EEwQ1`c&~BC_0=~5ts6lB5@1o`e zDbkk!8e+6CBoV;B4=CwNVHEl_oN@xB)_HdVN~vtghP5bAs}GcXfOJY%AHe$o(ub1tV&lri2p`jxfV;v8;L_R=`mti@ jHxpnm7z_r3;WP0E+VJu_yQ=9s00000NkvXXu0mjfH{XTz diff --git a/src/main/res/drawable-xhdpi/ic_cellphone_black_24dp_active.png b/src/main/res/drawable-xhdpi/ic_cellphone_black_24dp_active.png new file mode 100644 index 0000000000000000000000000000000000000000..aaaa44afca53e00b7b1e0179ceef0b47187a2728 GIT binary patch literal 161 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA0wn)(8}b0D3{MxwkP61PH#YJzDDtoze9NG; z%J~Y@gq^SQ4{me$@ZwvM8f(S2V-FI}$y%9~{W;VWZE}ZKXJg~;$xLSNbj%sW8Sg5RJO=VEOv+gZ}g2F5Y zMkW>x0R@K!2F8OWwf_|#ESGN#W9ljBooQEh$>Yk#KjDYw)~;(DsEkre8pULbk{33~!#r#2egG67{zkaQ{}HV(X}-pXn=Uo#_%u)lww2PR>{ zzqjDAU`<9rg+ftLkP$P-!`h4;H>74)w#+d0!4ZYDOp!3gz$bU4<0>M08SsVlT!K$W z0pEzh&IEKYFnatm;nV7fSS)FOwPLxb`NOVAtkrKP*9a4;;;i%3NZ1XFOe|hS|T1> zhLKmV!^cmmv^Cq(;2un_DKCk%SmF5(GgI z#2l&Vc`;5xSmQ5xYD!|>kn_jr2;s~RWXy{Al&KyKBq}0YjPg(Jd{07H%G5{;3MUx&q852>aS1mmC{O;0!uBaJ!=$F<$|S`qg9y3`M{LO z?dh13#2r>OfJUyKh%rTMV2dqk-G`j9Mk!U!?$m=6UmtW*CC3soNb*MNS^i5Z^eC`p zj1nyc2}>lDbb9>`hsyZJH~dUOSmTZHcARjEs8;{3PejZ*FnBlU+3^NN!G&(oli6}6 fM-c=;5NzTf_$t4|4J%io00000NkvXXu0mjfrwNiX literal 0 HcmV?d00001 diff --git a/src/main/res/drawable-xhdpi/ic_link_black_24dp_inactive.png b/src/main/res/drawable-xhdpi/ic_link_black_24dp_inactive.png new file mode 100644 index 0000000000000000000000000000000000000000..97aaef54b72688bdb16275d81f93f33c525a27d1 GIT binary patch literal 274 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDB3?!H8JlO)Imt3i5B9OzI%w|Tt6)0F z{6cU~qx&{lr_88JvE{Yhe;V06)7-SXi`O%#H2hgQk8O`Z-lrT+)_i@t33H>DywiE0 zpxoNcW^*8NVnN7(>6bP=6X|N1`&3xGYs%i#)~F8=b5AQtcQ>u*h%^0P;cNNxT}`v} sjw}aeJ+mV>Zq)y^aqsS0SC*RjFW{iKtxMnYgCL)Iy85}Sb4q9e0Lpb-bpQYW literal 0 HcmV?d00001 diff --git a/src/main/res/drawable-xhdpi/ic_phonelink_black_24dp_active.png b/src/main/res/drawable-xhdpi/ic_phonelink_black_24dp_active.png new file mode 100644 index 0000000000000000000000000000000000000000..5575e46de6902a38493e5b3893b66c0b70223a80 GIT binary patch literal 164 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA0wn)(8}b0DY)==*kP61P*S0bqFc5GK^qnZn zWL-I_pxnECrsUVF_qB5kjzwh#a3~(nc~P_B{~M773eTAy-fR%D)@54GC>C?#M9hre zjN(Ry>Glejs|7FgGB7f+)Um$#H|@k1jye2i?0;1=3ZFYt$=qXjI*b4S literal 0 HcmV?d00001 diff --git a/src/main/res/drawable-xhdpi/ic_qrcode.png b/src/main/res/drawable-xhdpi/ic_qrcode.png deleted file mode 100644 index 34fe1032eac0482f21771c633aaf0a018d94cc23..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1233 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7xzrV430R;uumf=k45$ey{CB+W%_3 z(NSPzF4mS~P-(MqXt#4{?`Y)V>5-ff*v>UWfV-nnR*Z!^X=TNvKk6m3g}0ae*eYC@?T7G$dVdWMKI*dGX@K z&mKKe@=Vc9&OCMba%z~aoVe>t&nj_Jz5irJFh!KXI$ ze7YPf;yQsLG}JZz`=%&1MgfJ=;#vm=7KeuW3JtCdmdDgL-#n8&PaxkSr;m8Nt3 zYM%$PGYT*;)-^M52&Dey5YRaA_iwGSRBza_RjZ!8dX<&>?fZAZ1CzH39eA#{U|n{$ zv3O^txWJ}57Lc)E^g_MCf3kpr9!CQM#|LSkT^g_duV$HXHf`_c&z~P}Wt=p7_Uvb0 zzHAY-{QmuW`E#qvvrnI6dL?g?3ixIv3oncXA)V&#{>*24L4bk3j%uduEjdH??Xy|29I z&7VIvSx!!FPV&2V@8%?5b7GkM;`ZA2|Jgru@_&-L|NNs+>u!Nkfdod7T^)ifHv$-I zU7C)x4&#UL5;=QPs^ev_F#d+aKD zdbh-izkYh=!jC(wE_O?O#D6w|Lxqv4!sL?J{MP~s#;$=T-In(D`O7Y6YTKR2&Y8Hi zYtf4yOKa=mK1m+7xo4*)^YQb~P0rbPb^4xt`>M`9-P~U__rG)YWV44)FU+`q$obWA zmH64yn;C3h<6ulEDP?@}Z?d7?S5>=mM(JX&i2q_sSs9Hk?|02~Y&i2JKQIdDj=#}U z#8^)FUuZk-)xofBy7SW+7rry)v|RbVR&;6ee_?p4N%k?8;j@1K_;}ZvRGrzMK7D#L z=XjZ2gUsijKVQluSAWU2mUpOo7QmSETsY#YL=y__t^b6s)yBp+=UtQhI@J>z9;XW{hu$VG1e%f5fG-u8ni~FDDdDzZv z=ID7jFZ;ufA2)vbYzm88q#7Eto~1I#`LZkn*1 z&~f0<69X`jubwn%O7B-zMuCK_42tg$oqt}u{_M0L90j$txwhE}hSAZ{ zb1QQmKbi6Paq{!(zuSH-e3H9Wb~(ew30r*@Ff3Fr`O&hQfu&#_GvgugZic(Ip#0~c zZ^zVfX7cZbjtS>GKz48};0L?mG!t@p0c0Pj`Y6wN_)zNk?dsMbDNk2Fmvv4FO#nd3 B2~_|9 diff --git a/src/main/res/drawable-xhdpi/ic_qrcode_black_24dp_active.png b/src/main/res/drawable-xhdpi/ic_qrcode_black_24dp_active.png new file mode 100644 index 0000000000000000000000000000000000000000..f45477142592175e6615dbf73184faae96c48a64 GIT binary patch literal 137 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA0wn)(8}b0D08bakkP61PQ+IMQ7zi9Ts$X`F z;n}PcnoN^c+bnowv1duo8^t&Ko46URiyNDK_B>Y9p1}VrVb}WnO-;Xg7`Pl>hI6|! l>PfJgIzD;2Nb^C5jM0k34fEeE+72|E!PC{xWt~$(69DopFRB0l literal 0 HcmV?d00001 diff --git a/src/main/res/drawable-xhdpi/ic_qrcode_black_24dp_inactive.png b/src/main/res/drawable-xhdpi/ic_qrcode_black_24dp_inactive.png new file mode 100644 index 0000000000000000000000000000000000000000..529c070055c48c0eaea8c02e6b956f033897512e GIT binary patch literal 139 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA0wn)(8}b0DAWs*^kP61+1x6CAiw|&GFLALI z*1h9d&iz83{mCcy#|__pG8~gX%dX7WbB%q+5%<%J4$8Z4`F1d)wt<0pF2CDtR}PQ; m77}OK7pGoSU|*ad!oVPLQLFNDH}5K-=?tE(elF{r5}E*zqAXni literal 0 HcmV?d00001 diff --git a/src/main/res/drawable-xhdpi/ic_tag_text_outline_black_24dp_active.png b/src/main/res/drawable-xhdpi/ic_tag_text_outline_black_24dp_active.png new file mode 100644 index 0000000000000000000000000000000000000000..3fede43420d05806b7bac4d4dfd2c4092f196dec GIT binary patch literal 320 zcmV-G0l)rXg)&h$rnnGZ~_|i6P>&~xtB2Sexim5BOfR1r;QT!(*}uVKW&Uy z5czo_^7BIE=Y`163z3qSU4%%@3z3}{A}=pQdR~aS<$0v!Wg|BljT<9Bvj5&7nO<7t SzWF2o00003#U;hLg3#VRLY0vFAF3;_#>tJu?C3-0ipv45a&;{!vLXQR|@AxzQQO`(Ue~S#)vYO_ipDzDsLj5HxbX9i04hj z^CseX6Y;!>c;1BaX+rrtp?seBaz3$zjYeZ*;h*fiZ|%&dc<;z>{{R3007*qoM6N<$ Eg6eRGvj6}9 literal 0 HcmV?d00001 diff --git a/src/main/res/drawable-xhdpi/ic_zip_box_black_24dp_active.png b/src/main/res/drawable-xhdpi/ic_zip_box_black_24dp_active.png new file mode 100644 index 0000000000000000000000000000000000000000..240f40a69855072007402dbf0f616ed03cf49263 GIT binary patch literal 169 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA0wn)(8}b0D0#6smkP61P(>L-SP~c(7Zw@e& zO%iK37rfjvTcq*jzjfbDx3RP+yDT%>=&RnkMehDaXKTsnU91s>GZh;fyLJEknA*Xw z@u2-3yU2xEulOLujdJ@12X_4Zp{v-~blTZk?tVqY1dWC98j4I6jHL-q81S&H_hwmb zp*+FkUcH8vmpjMockh42BzyBYO(`~t_~9<@cHiFq!Qr{b$lP!$=#KB>wJ`ZjRRCfmMb^r>PGo+Y4|E=br>mdKI;Vst07ukG=>Px# literal 0 HcmV?d00001 diff --git a/src/main/res/drawable-xxhdpi/ic_cellphone_black_24dp_inactive.png b/src/main/res/drawable-xxhdpi/ic_cellphone_black_24dp_inactive.png new file mode 100644 index 0000000000000000000000000000000000000000..2dc0ef752d097c59394213da7172572687d253a5 GIT binary patch literal 195 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY0wn)GsXhawx;$MRLn;{G-rC4}#DIt8V5^Y1 zW4WS*=z@RUMgI=CA9p$S&eXuNvv#ASVdR^HZcoFE7mpIn-#%2zc``@-lESMr^YtCG z-Y)RGlEtpOsO&!r=PzqV&n6a5Ar+4a3XUiY5s*;6Y!i#B^-rI=1ImtDn_oRhpTc~v f^q2gsebe_g&Zs?V>}<^nbQOcAtDnm{r-UW|w4_H; literal 0 HcmV?d00001 diff --git a/src/main/res/drawable-xxhdpi/ic_info_black_24dp_active.png b/src/main/res/drawable-xxhdpi/ic_info_black_24dp_active.png new file mode 100644 index 0000000000000000000000000000000000000000..459b0d4ae95abdd89868de927baa7336e0396616 GIT binary patch literal 547 zcmV+;0^I$HP)DsEDS%1QTNqM-jYGTu)hPRk#04GWLP&}_7M>1~Dln85j zq)36yZA6{%jFi|DrxGEoT0|zPv!EFnoFmSH zgf2%-od&&fM2Ef8pgkc6-6Bqdgli6(BaS!YfELPm&|jKp4G<6Oqc!ppbdOf-C1`@y z!b?z!)*5mCvlmuqZM_6-&{AH4RON!I`^c*QQZKv&rD(-of+lEfDh+E2?yOc54x(>k*^4=^*88+qavq4-^gI@EGQw9$WhQ2T{3z?94scYQ+C#K zwuIy`v>tRpPGhS%KgccM&05Yc0t#rew373i76pYYE#!oh(B|Fn!)j4dz}Voc9AL!I zz;|iO1qO9WeZ9Yk2{A5WRwyT-i#1(dbDVIB7rIy%a?K2NeM>_CD>_h=EtwcJ6AfOm+d zy(K_VM1g4Bg%AZX9}&&_NX$ynaE@Y9$O-`kVrT^ci@ie(?kx-5Lk#Z@3#7EhgIW@1 zJ0KRepMT7fMf;sBTE;AuwV+b*{ZR-~c#m$Z2A!FZ&|3}ai5c}2u^J>iW>kq-Udf1% z-g;0+z@Qv)u$)29odi8&(B4VV2L{znf+_}mL#+Sog|7^1oCGxt>YW62-Ua#lk@^3n zuAKx`4B9&h`k?#J@f+QTj@(I5uKV=kH@Z(hptK%TFzSi>Q&`VW^5N{)We{XmgLceN zS_>+eC9@W^^XqoZ2WCrXjpsDPEO5to&}|laYc%H#iv?Vav!4uOGR_MhlkYGt<}oGR#HoA1 yV`3}{$a%&GD!$Ut(b4dgiVr;FngCC2Hk+TNU9!cwuiQBR00004RA;!WL8-BZb~VUo$8Etbx2ujB3` zJ8x!IKoA5$5ClOGgnva9ZTMIr#1V>EI#kRNAy)9wMm4_}2QCie5!nPqE5sP}JaX<4 zGPchyNI@Y$C!3fGUYJ|w6QrQvqr#W-mSN+(f)r+4N%609!WwhD6HAARnPZJpY~Lv_ zcg!DsqKn&799u^Z+l$>(bICDM`HT_&rkQ2L#o0*j6vw%SoChnlt!qdcCF?(MLklr6 z>QX|fY#X^#u~`3i+DR=s(AUDcR$EeEJISNNR$A|&oTV}@$~;jXEoniK!`5U>If8(V z<}{M1qtC4iT4=ZNcLZJCl|@N?A}eS)f*QP})@|RjYWo4t_IhF578y2EsNqXHshLzk z_15ZI6ZCAfj>L{IHk#|B6**5vjt$dhmcWoSDf!}R#@A8Ur_WlQ3zzKBhf|7}1_nm% zC@9=r;AIEDAq@Zk002ov JPDHLkV1mYo==lHu literal 0 HcmV?d00001 diff --git a/src/main/res/drawable-xxhdpi/ic_link_black_24dp_inactive.png b/src/main/res/drawable-xxhdpi/ic_link_black_24dp_inactive.png new file mode 100644 index 0000000000000000000000000000000000000000..daa211f9844475e29004d28bf627b2e029af1ab9 GIT binary patch literal 445 zcmV;u0Yd(XP)=4pWx1!H9Hvh z|KVViua1mRrcGZRkm7=G+gSX@2Ul4Nu{Cp4|=p_7?883;P|UT nM+(-=7+_FJDW#NBO1+XF)kWK`{i5G-00000NkvXXu0mjfI2zQE literal 0 HcmV?d00001 diff --git a/src/main/res/drawable-xxhdpi/ic_phonelink_black_24dp_active.png b/src/main/res/drawable-xxhdpi/ic_phonelink_black_24dp_active.png new file mode 100644 index 0000000000000000000000000000000000000000..132fe37e0821fd5ab17944702125407a8aab101f GIT binary patch literal 213 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY0wn)GsXhaw=6Jd|hEy=Vy|Iz^umO+DMeZ4P z%$021aW1ZI8y<88S2sI^8w51{Uq7{xefpLAt}ZSjx2}|G?%%<`_scr=GtG`i8$4tHpUJCzt6@c=LOe`D| zWPz+x`bn950tyalC+v@hG|&3_G>)IkbnfK(^l+Omw*>_S?Hhyz#0GRHgQu&X J%Q~loCIBgUPK5vf literal 0 HcmV?d00001 diff --git a/src/main/res/drawable-xxhdpi/ic_phonelink_black_24dp_inactive.png b/src/main/res/drawable-xxhdpi/ic_phonelink_black_24dp_inactive.png new file mode 100644 index 0000000000000000000000000000000000000000..854c42560a62eae8669aeb93290cdddbaf9b57fc GIT binary patch literal 205 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY0wn)GsXhawrg*wIhEy=VyK^DVeE3ftMcD3EQ_~KkQ0$xF27~zHaP58{57xypUXO@geCy1u|`b* literal 0 HcmV?d00001 diff --git a/src/main/res/drawable-xxhdpi/ic_qrcode.png b/src/main/res/drawable-xxhdpi/ic_qrcode.png deleted file mode 100644 index 5ead1fb977cb7f7c0173a2427c1411f84531a73b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2606 zcma)8do)yQ8-Hip7`JRh?xvDTHOi@!T!u>ITB%%zBuA5laVa#+cIh%Pl_RHeiP8yS z=;Ahvnabr5DwTN+s^m>^R4xr)3?`ppZ8tA{p|HT@ALeA&)N(phXZob z>e2uJIUDPJhq0Zvyzmm3J^U#^5&)?gn|&6}5gFr|=Ke>zG#d6;TTr&GRJZi{L9_O6!W&K@0rdctSY-hVk%q*`v~yHo4M8y*jU-p~T;uEH9w( zc!#<2>Y9NAuR^0H8yiiBo@U9@8bV)%W=+!$Po<^Tm|>xR^z5?Vx4L2HJgu7&Jrm_w zl_gkmwVtX7BtQw7z0@uejNkL@GdmWKoQ-P;7gHdN!Pf*5Ye*lYvfgZ#N1{c4?qMS9ZP}}u_C)b2e+gH z2h#xldST4R|0LNsTHZzfAt+wzwnbkhvHfvbncl=HecrQY7S2V-Qe9nKkTa)C-I@f# zC82wD_veOdb%N;cQx=8Wt~A5ePel0MTVxY_0aiJIf2o^QR(3<*d65Ed8@^Ws4wi)~ z#BrMOAkYFd5Kwny8UFRiCeqGyrk|f*#!wc0$>u29(cyYZ>)gaA#^?;&a4^KRkbdsm z@jc!(b97(dfiP+0V1NvPqr7JP=4Xi;|4bpi+&;8K$%LhG8Jt)j@H98n@{uqaeVg>M zqclz+!3MaozL2v;z3f;b37oIU@Z3}pm@R|ww243SrCA!o5L|NUzg;n6t>Mov%oKd+ zeU)YI-V+oPW2V1Sx@l~3a+Bcu^pKeNT2iKh?=J~=F&1U zRtnP7(iHi^MU!=(AOj^Jpk20IE1hr zAxPj+AUZ_6nL{%xwxiRze?f*;O|JcpA^s+zKu|4BprQl0U~SnPAOp#VuF7n1APld5gr}Mz9g0amg0e_CIOz( zfrtCRYIJBIq|!PyKR-Y3J!RuhMn<_FIf>u02CmxbrMw{@cjNc;7_c_peA&ou4hN@T1W@G_x5Dshq|3_oBgDZL(nB`CgqJK4y4NzKeSH8L^<5#uxbmVKm0|*L3LF4fMf114$#nH~cx41ufdq-E- z(e^nbMK(@dOKVwYH`FvWW!;u#_O<)I$@y8kYI3DVJIkKxd_Mlo2#f}zc8XVkp8WGL zgSpH*cgzB#Kd5FpfaPXC9}a`Cst{DHa+Ltq@kd*YGXV*}moH!+Vv~ooImux?zzWyz z6YkV@wGoW81?)`a+b$YC4;!v|<$ah-T)(skqP1nIM#&`f`-~tC+&KW@`uW8&P=vM= zeA$aj#P>$(B7_(rn}81e+bM)1uBxtnMfyVAwC0?{A;vWwbM^6ZF1NUvT-Bw*-)vxz z7`~ZEq|BvY;yaY{#_7xK_{V&yl8TBA?O!J^*-dQ-GWj+smf(;^f5x_(BA}NDq^Q5M zx+>l$Pp;KZJ=lJ@;C(H}PW=1qc=~&FdjWmv&&sn!wcXuh=X~cIm66jAj^bEYz7ydd zZ5nU8lU=~apyLyD@wy*HTE^oG;U8j<2L+;C%~q`j2=B#0I5xb0xM!~o>aJ#_wR}mg zj$SFKIR!nKj?a<{Pfj^F3SAp*M1Z|%@3tX=iDm>FJJA5~B842g*ac<&_4p)Oy^ zJ2-f2(_lywO|;}0$-x3pTjr;S>NtkClPZWeUor&s4GlTR3Vv%Y_Tttq)=)oR49R-) z<`C81$R*24GQ${?Z2d8#Nr@dJtGEh&tKeZp7_ad+HoX>lM=8y7+3fbRvoo#YcqjBu zFq7w2q}PO9uZ}a(!!7pQRHUJ%rm$FAS$Vr+X_W!_@)`DOCT@HOL)<#$src4;#$9rP zx-OiVUm9drNrps1PNV%5Y%StUu)rC;~?D^-Ky-p9VLBz zeg08Vosm{nR)sRbGoweT+|Z%cjeK9j+y2qfp0_3CwJ)DEh7*(o*|)Y(pHoG@&?RFQs5_PPx=kek(})ra&Dd5< sHLLBa^+oOC0L7G}PZ!6Kiny&8PV+Jta4-er_dQ&;WwBA`x9yC*M_P`DW}nfR74FsadCro+ x=&4Qrn7T`xE=dPp{4J%(c`k5K-cgY&(^*-wRy@6bHn@mvv4FO#p2mGZg>; literal 0 HcmV?d00001 diff --git a/src/main/res/drawable-xxhdpi/ic_qrcode_black_24dp_inactive.png b/src/main/res/drawable-xxhdpi/ic_qrcode_black_24dp_inactive.png new file mode 100644 index 0000000000000000000000000000000000000000..e0c9df0ca430027e3432440552265539c02adb44 GIT binary patch literal 156 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xf3?%cF6NrD7YAE9(wUkkj%<3~6mL!&JI6s7B zI4k~Jb&|dmBn!%1malR$kOd?IT5#E-gM)%(L5a&!2gf0ao{+;)ketIDjzbc>We&$7 z3I2yXj(}ABu^cI>H|JGEig3)~SwiZ~DI!u|j*JxM)FE)36y!j~K}rg8^rRq1PYV2$ z^LH%m`~0OwAmHn3Dc^6q7y*q+UyLy#&uTDuFY!AW~&TrIJC0O_~7c={H2m*q&U@feJuD%5>y#1SBaZPI^*v;v_xC zC+RsVlFt#41RTG)PttRIlAaSMX*oXW=#zYoo)qWkNpX&z6z9lEagLM}=ZHx@M^BP) z1SFrMC&f8B(zm%uyzt->?`&yl+44qWv`tM-{Q(0d6a&b|!`=V@002ovPDHLkV1h$v B&fNe2 literal 0 HcmV?d00001 diff --git a/src/main/res/drawable-xxhdpi/ic_tag_text_outline_black_24dp_inactive.png b/src/main/res/drawable-xxhdpi/ic_tag_text_outline_black_24dp_inactive.png new file mode 100644 index 0000000000000000000000000000000000000000..77572b06652f547b78152f146c1adabadd63b414 GIT binary patch literal 443 zcmV;s0Yv_ZP)R3e<1m|)?hMa%21fPs;2^Mc_Yb(&vlgLj` zqNgKZso_kXHD~sQ-6=RVbA3JOTi{qoJ$YTEL|zvukLE_CCD0PN=_D1DIPl-$;qLt! zNChY|F5cxtAnK$kP|LXX0S5!A00qW{`y8F5?@-CnN%9$r06IyzWd%ne>F-d%@sskz z6dW^YHs{Mkn#qY|qK7n>lT9Rn;~`aZx@oXPs^mb!#Y(E=_(_!sBrZa#x>-w* zDmV*~QpJbbN#*~tpJM%^_)?wJP*(BKH7_Tf3EV9(yn)mqyebY-59=Z&z)uoDE|Tz* zSxLg7)=9Bgo#qS#c$RdnB9*JVNzR1^z(I->2^^KAa2%wai6fBw9G#?dbdt`|Nis)h zUy}SBouqSglAoiKbdFB4a|DuuBaj>%f#l!_Bo9X*=^UNp=jbGzqmwKgfi#Rb1E0LP lz>yP)#EBz;t*x!q_6L^bc)|&WRb>DG002ovPDHLkV1iYl#P

  • }Y-igj-YhQ_}tc(1a)$7D0_9*(B|nKO^x$|%u$#$0|eGv`l0s)78zX0Hv0+GiFt zJFPh8vukdEE$*d{oSwPF<}9FK@$t-Cs`qt6Z?H8DE!}~>e$5cb2_Jx zibfq!!fTG0m~8yF?Pr5qKdxis*K$90WalG}oV2uft=M^|+hPRf0v*WU>FVdQ&MBb@ E0QWghQvd(} literal 0 HcmV?d00001 diff --git a/src/main/res/drawable-xxhdpi/ic_zip_box_black_24dp_inactive.png b/src/main/res/drawable-xxhdpi/ic_zip_box_black_24dp_inactive.png new file mode 100644 index 0000000000000000000000000000000000000000..61e2f21f75be409c8aa4f65325f6836f6617c705 GIT binary patch literal 197 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY0wn)GsXhawdOTemLn;{G-rUH0K!Jz#qOk9@ zf^804Jl@!coLaI)sWIkGWn;MGM?>SyF}(|nBc<~$aY{YeEwSdT`3{e3ap%&4l&_w( zDsfy@$8*Kgw7*epW!Nvfzbc$UDjDW}6BHcxIXAKVoX#oqBtA@D#bZMKOa;fLPwE~M w7A(5#wDY5CU*n>G4dL~V)|fHPo_Uk`pSX*+GEqA>(Cd zpTMqV?27Nhn;0LN<|!L{%E-|3q_v!tjuup76Uo9-}gomm~sU>?Sob(l}A z&5eOA?n;YUn^}Xp>B_B)4HK1lKP2|BpSg16S%rfq>y(NE^SEw2W;8WtWMbhED9AnF znFC@dI5aSTMF=q%85rgEae>q~+-ooJ6I>p0K!ji7XNm1`+eBaHHEY#gMqi)&MLzN6 n56uJi@4~B2KS<|iWZJi+K>%QLv3>2$ zwp(6O-i6=xuUMmK@Y(d?o$KA~LC~^SPFrQqEmimb3E`+q+Y+NHIzO6SpFxB#I^kuH?ORC*9A9#E}7j$6eyRDBHfp#(2NEiJ73}%6N zgutJVq97#??(;pIqolXLj>qbLP2Xz;tC^d`=P%(`SaVdKRpP>*CFhMieldJZU$*k} RohLdV4W6!kF6*2UngBALUH$+7 literal 0 HcmV?d00001 diff --git a/src/main/res/drawable-xxxhdpi/ic_info_black_24dp_active.png b/src/main/res/drawable-xxxhdpi/ic_info_black_24dp_active.png new file mode 100644 index 0000000000000000000000000000000000000000..090f8258807947c8d9237b2661078fa11606f36d GIT binary patch literal 721 zcmV;?0xtcDP)DtPkyaDxL?Jp?Fes`qpi8w9uRuj+G`g7tSd6+cjC=)9!RUL{p)t81{o95@Q2aF=&M$5_1Cz81kJSl0Y3C46wLE z66%&Lq5VP@g z2xx&vRRhM@1mYs91_%cP@Qt3j0bMfqRzlPb5Q_MAt#ZI6KG{rF4wzu!%Qm94O?;^# zN;}1u4x+R+J}e@N%i*bnC~gf;RYY+vp6ZC=YItfPifiJjjTq@8G15JrMydx4@${m4 zz!Xn!st3G&fdR^o&=+`!KmBX8rFuXEPj%G;&hS)KJ;23NN%epto*dN!a`^C|c0e0n zYHA0Z;LDcU0UKZBVhgTR4!FR#_0N8}o1v?2K!*$g9I6|zPayM*RSg(n6Hryv0GGfl z`f3LBu$Vy^QPK`GY9I>w!_1a>LK5zYB|@km30Eehb0ope2rbJkl2Ct{!vKd4l0XmS zFr>f$iMauJ3|ftOLZ4L(E6|Pc@Z^br!);8DZjOj#sUs10${dl}HaX=V;-fYv zY+#|1!x}C%n%pyF%IkYmhTPNO43{D~j7g literal 0 HcmV?d00001 diff --git a/src/main/res/drawable-xxxhdpi/ic_info_black_24dp_inactive.png b/src/main/res/drawable-xxxhdpi/ic_info_black_24dp_inactive.png new file mode 100644 index 0000000000000000000000000000000000000000..35f85460033d85c800ebcf155f678cc7609c3c4b GIT binary patch literal 670 zcmV;P0%84$P)7YF`dhkSzbkvazo$`1?IxfbeBR>C-9y;LDfqQbK zr!oQ@d!R&mtmMJ%r(YsHR}$cePmT;whK~at|B!(?;L+L}GGIGedO`+nLkj^lGH^8k zS4$8D?YYthQPP?#7z(6CKS_%U3>SMv)C>?JE_BCH)qo1aMM6Z?0O19DOvu#@$eCbm zfv6iG%(3>Va=<&53@4QXY7ACZh|-o=i4mo3v63N5OR?Z1ikn*9LKU~5QG_Tiq|pvh zTuh?`QCvc!6mil|;-oJcRjLP+G&-psP}AtFdcgVj577S=`t=v_&EG~7)dTi4+NmB8 z((GH^#`w6M|to`mkx>X_C% z4#+_L#lr!g3>lz|DUJk`NY51nxBTL3!99)z+Fw0x=5y%j(w))~uZNrJ7LQJCI{gF0 znjQq~JNnHtqc>{`#9=urdS-~I5C>I+cnreu((>k-@r+?m6Xv{MabefIGe-@>k}WA> zQOcGjp5DLXhQuU%QBrgMuBPORJuxA3ri@0T(P-q%e>uy}GK1Ffr~m)}07*qoM6N<$ Ef;X8er2qf` literal 0 HcmV?d00001 diff --git a/src/main/res/drawable-xxxhdpi/ic_link_black_24dp_active.png b/src/main/res/drawable-xxxhdpi/ic_link_black_24dp_active.png new file mode 100644 index 0000000000000000000000000000000000000000..18ba9a5dfa4f03515b24ea2b1688d7358a0d1ecd GIT binary patch literal 674 zcmV;T0$u%yP)Z1}M3G{b7bheF{i0aM^{;&hv~I9kew=ME86LF`iQ#$@=K3Uh{&c z&+w+8j3y?^wXKfxp(1L$B8aTVFWXnOH>RE`hUnt2W{BvX?_#LvL^!z5KMEM^OlvWAyVjO6 zN$@8ic5Cjgci|zpfV-?sg$Cxq1iaZFU3E~sSA?}~3s~ZhUEoaT2(6SD;ak8IH|AN_ z<~QpZBJ?oAd@H|M=NO@fOVqaUo0Skk2qAeS56o%n@cx$1lx@%okOie(I;!aa6d2#;#kLvzRWE3c4+jBizNjPwvFKDEcQc5YM zlu}A5rIb?2FlE7xBNbm7*<&9pasa}7+U(r9vi#>%bti9jJ*9|1y~9Uw`ypf4+_@go=CYT zYYILZ8tF!}3%5Qe<~zmADY0&Nt$M9#yU;`V-&( zF#2@+Fq;1KiA*jf%DY-hOxi5w=7h4453}8Jx@JrWlXlB#h@A^dlDpW@JaVPnJ*{NS zkS6X)ELpcreN9Tl5F!@trk+n8x*w~YNJ;okPox)4!C$zZXd{`DJsVb@NGne^>?yGq zlKsJ>MTqX?aJL|$B|{#(fDA(?uK_=BeDXpMMr70hJ~3rH(3_YgC=^$o`Ox>kDuH#KR7Wa$^{Jad8M{yOpeWI&nlT5Tf&}IGCh^; zPRdNiW*zf{Gkg)7n76%QxUCxtG@XG#L2^O(#o%vGS9R^uW~j1FQQy9*n_XmPaW zmrPeG8h(B&2CA}SJs=NOj!uaDTa$Q>5hU7hr$MWD%`xV#GaEJKE@YP4RBv%?kWCD; iEwq^&^|ui0urEyS<@bF0rm=PdNQbAZpUXO@geCyNWm{PQ literal 0 HcmV?d00001 diff --git a/src/main/res/drawable-xxxhdpi/ic_phonelink_black_24dp_inactive.png b/src/main/res/drawable-xxxhdpi/ic_phonelink_black_24dp_inactive.png new file mode 100644 index 0000000000000000000000000000000000000000..b2f04b035dd6eb55d00b3d860f1654a262b2166e GIT binary patch literal 254 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD0wg^q?%xcgj(WN{hEy=Vy=5rWY{0{M(SAyr z1-nVv#4ax5UH=zeQg`LhN>SbYpJn|t7cls8ZBgiMznclWuPpI3d!c9YQt>p;jg*;; z-8$w8XZdbyW+~4eOeU aK%k1rQD|S|mZO%!Al06(elF{r5}E)NXI2FO literal 0 HcmV?d00001 diff --git a/src/main/res/drawable-xxxhdpi/ic_qrcode_black_24dp_active.png b/src/main/res/drawable-xxxhdpi/ic_qrcode_black_24dp_active.png new file mode 100644 index 0000000000000000000000000000000000000000..a5f05770341b37fc22f2e69b9dfb16bb42df7f10 GIT binary patch literal 155 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeK3?y%aJ*@^(YymzYu0R?HmZtAK52Tn%g8YIR zx~l&zX9Mz_JY5_^D&o#gJjlynz`?ZJ@%#Nryc)bOIj*m0snB1v?&8+mtBDt~CEhs5 xw8h`@%A4-IFfv@{OAW8()C(z6gJ4;LdX>%l1~g+liXc7o8wGJYD@<);T3K0RRm`G)@2j literal 0 HcmV?d00001 diff --git a/src/main/res/drawable-xxxhdpi/ic_tag_text_outline_black_24dp_active.png b/src/main/res/drawable-xxxhdpi/ic_tag_text_outline_black_24dp_active.png new file mode 100644 index 0000000000000000000000000000000000000000..bd2545fa3ae7302c9390b263b2127423c93138ee GIT binary patch literal 685 zcmV;e0#f~nP)o z?Mv)B*A-Jp*+$*Tm4y`I2bnv&wunOPrGz7`E}#&1f#AsNXIIFJFQCAO?@qjuQGpNt z{Hs|MIPp~!c<~h!xbejmQt>B=vdIdm8|Mv{x(ez0zOn+x*iu#CnYxM!TvJy~fp6+6 zDR53*6$Rd@tDw*@PhD|^ntkdDD^vlksAxP2EA(iOSABo{(5di7s;Acd_-g%we2ObvRPHdv77ZF~F~u!PN=iyfN*MDEms@zf TL;M6100000NkvXXu0mjf{Q^3J literal 0 HcmV?d00001 diff --git a/src/main/res/drawable-xxxhdpi/ic_tag_text_outline_black_24dp_inactive.png b/src/main/res/drawable-xxxhdpi/ic_tag_text_outline_black_24dp_inactive.png new file mode 100644 index 0000000000000000000000000000000000000000..fef8eff9c4be482a50495503eac47f03746edad0 GIT binary patch literal 570 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD0wg^q?%&M7z{Ke3;uuoF`1Xcjep7%%>%;AL z0uSBkb2(TNoO|d&!-xO%A>XBE)qEA;SNXo-(hob)R*y&!xcMl{ip}krc>l!4KB?1M z=X}omI(TH}tG_?ZpNaNMcW!@oX3wX>di90Z^yKUpUJv@)(pY)FWg-w)KCHNOd4h+@ z7aLs`#t$d*+)erI75OTHCa>q)%dNZC?*ilB?)#y-4L}C3cec|{D@XPT5m8)Eq&b)r z&TkiJ@zywPF0h2ZaGJh=PWAV}#*-=Lp^Vt`VB|-2*=FcUj|e;ge$FSD`I6_Ks)23m*YedtU$Id=z`#|H8Xn zbxjlY3m#grcfovvjPh9fh248X6mn}1P3=1H>ZrZlKhGbWbL1`bZx?=i^ZrNmhO^~~ zj~o(2r=JzFTEfm~pV&|<>~_Ha0%KiM9p_KZN9{NK1@^h|wv@fxmdKI;Vst07qC2?*IS* literal 0 HcmV?d00001 diff --git a/src/main/res/drawable-xxxhdpi/ic_zip_box_black_24dp_active.png b/src/main/res/drawable-xxxhdpi/ic_zip_box_black_24dp_active.png new file mode 100644 index 0000000000000000000000000000000000000000..c3359f74c4819a6006c45ce6ed858391841e6147 GIT binary patch literal 270 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD0wg^q?%xcgu6nvShEy=Vy}gn5kb!{1Mg3M; z4(Fp@Hxz~Tx^u98yz)il1Ruw_OaILeu3oqE@EIVuSE4v^XK5FE1&di`eARg9#c9ONE_L%TgItfvbd5%}i!pqxCrq}tGUb?r^PS7SuXKc+LqNfy zp`j|^KLaBZ3x~i1H8CKcfiW)$8#loIBUo5r!SBP@-}(114`}Fo<|bD=|Nh}i- t)*Orv(Bde*qQ2nQxxo7yKrVd4DfapAX}dRzKLb6;;OXk;vd$@?2>^qCWR?H` literal 0 HcmV?d00001 diff --git a/src/main/res/drawable-xxxhdpi/ic_zip_box_black_24dp_inactive.png b/src/main/res/drawable-xxxhdpi/ic_zip_box_black_24dp_inactive.png new file mode 100644 index 0000000000000000000000000000000000000000..b861d2d7436ab008a0d89acff7178649f5eea313 GIT binary patch literal 259 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD0wg^q?%xcgPI;q7f@S0jM}FoPDa))S8kZTw^0Kb*x$eX$b-DLwx0Rj09d_oEi z4GfGQ8S|3BLJ!o$zyfI8?|lqF={r_T-|TDd{`<1yP2Hcl<@WpU|6^nlx_(bzV}ivZ l8^*QM7w=1)2?RH}cTGF)zL0 + + + + diff --git a/src/main/res/drawable/ic_info_black_24dp.xml b/src/main/res/drawable/ic_info_black_24dp.xml new file mode 100644 index 00000000..81edf070 --- /dev/null +++ b/src/main/res/drawable/ic_info_black_24dp.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/src/main/res/drawable/ic_link_black_24dp.xml b/src/main/res/drawable/ic_link_black_24dp.xml new file mode 100644 index 00000000..9bd770ba --- /dev/null +++ b/src/main/res/drawable/ic_link_black_24dp.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/src/main/res/drawable/ic_phonelink_black_24dp.xml b/src/main/res/drawable/ic_phonelink_black_24dp.xml new file mode 100644 index 00000000..87c6109a --- /dev/null +++ b/src/main/res/drawable/ic_phonelink_black_24dp.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/src/main/res/drawable/ic_qrcode_black_24dp.xml b/src/main/res/drawable/ic_qrcode_black_24dp.xml new file mode 100644 index 00000000..bdf21d93 --- /dev/null +++ b/src/main/res/drawable/ic_qrcode_black_24dp.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/src/main/res/drawable/ic_tag_text_outline_black_24dp.xml b/src/main/res/drawable/ic_tag_text_outline_black_24dp.xml new file mode 100644 index 00000000..fdc74823 --- /dev/null +++ b/src/main/res/drawable/ic_tag_text_outline_black_24dp.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/src/main/res/drawable/ic_transparent_24dp.xml b/src/main/res/drawable/ic_transparent_24dp.xml new file mode 100644 index 00000000..c4043eb2 --- /dev/null +++ b/src/main/res/drawable/ic_transparent_24dp.xml @@ -0,0 +1,8 @@ + + + + + diff --git a/src/main/res/drawable/ic_zip_box_black_24dp.xml b/src/main/res/drawable/ic_zip_box_black_24dp.xml new file mode 100644 index 00000000..7fce39a7 --- /dev/null +++ b/src/main/res/drawable/ic_zip_box_black_24dp.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/src/main/res/layout/fragment_device.xml b/src/main/res/layout/fragment_device.xml new file mode 100644 index 00000000..8afb2561 --- /dev/null +++ b/src/main/res/layout/fragment_device.xml @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/res/layout/fragment_folder.xml b/src/main/res/layout/fragment_folder.xml index c883375a..2f1d8fe4 100644 --- a/src/main/res/layout/fragment_folder.xml +++ b/src/main/res/layout/fragment_folder.xml @@ -3,7 +3,7 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" - tools:context=".fragments.FoldersFragment"> + tools:context=".fragments.FolderFragment"> + android:showDividers="middle"> + android:hint="@string/folder_id" + android:imeOptions="actionDone" + android:inputType="textCapWords" /> @@ -40,9 +41,9 @@ android:orientation="vertical"> @@ -50,9 +51,9 @@ \ No newline at end of file + tools:ignore="RtlHardcoded,RtlSymmetry" /> diff --git a/src/main/res/layout/pref_widget_scan_qr_code.xml b/src/main/res/layout/pref_widget_scan_qr_code.xml index 5412c17a..8b06f59d 100644 --- a/src/main/res/layout/pref_widget_scan_qr_code.xml +++ b/src/main/res/layout/pref_widget_scan_qr_code.xml @@ -1,8 +1,8 @@ diff --git a/src/main/res/values/styles.xml b/src/main/res/values/styles.xml index 47455f7f..c546bc97 100644 --- a/src/main/res/values/styles.xml +++ b/src/main/res/values/styles.xml @@ -25,18 +25,20 @@ @dimen/abc_action_bar_content_inset_material - - -