From 7ca62c946a8de40a91db30ea43037031cdfb6459 Mon Sep 17 00:00:00 2001 From: Catfriend1 Date: Sun, 28 Oct 2018 22:46:51 +0100 Subject: [PATCH] Add "recent changes" UI to drawer (fixes #117) (#116) * Add "recent changes" UI to drawer * Update build.gradle - guava 26.0-android * Add REST endpoint * Add DiskEvent to model * Add DiskEventData to model * Add RestApi#getDiskEvents * Add ChangeListAdapter#clear * Implement data exchange between UI and service * Display DiskEvents * Add icons * Return DiskEvents in reverse order * Display device name instead of partial ID * Format dateTime * Update whatsnew * Imported translations * Update APK version to 0.14.51.12 / 4175 * Fix lint * Review * Update README.md --- README.md | 3 +- app/build.gradle | 6 +- app/src/main/AndroidManifest.xml | 9 + .../activities/RecentChangesActivity.java | 139 ++++++++++++++ .../fragments/DrawerFragment.java | 9 + .../syncthingandroid/http/GetRequest.java | 1 + .../syncthingandroid/model/DiskEvent.java | 15 ++ .../syncthingandroid/model/DiskEventData.java | 18 ++ .../syncthingandroid/service/RestApi.java | 26 +++ .../views/ChangeListAdapter.java | 177 ++++++++++++++++++ app/src/main/play/en-GB/whatsnew | 2 +- .../drawable-hdpi/ic_file_add_black_24dp.png | Bin 0 -> 663 bytes .../drawable-hdpi/ic_file_edit_black_24dp.png | Bin 0 -> 632 bytes .../ic_file_remove_black_24dp.png | Bin 0 -> 613 bytes .../ic_folder_add_black_24dp.png | Bin 0 -> 377 bytes .../ic_folder_delete_black_24dp.png | Bin 0 -> 325 bytes .../ic_folder_edit_black_24dp.png | Bin 0 -> 418 bytes .../drawable-ldpi/ic_file_add_black_24dp.png | Bin 0 -> 405 bytes .../drawable-ldpi/ic_file_edit_black_24dp.png | Bin 0 -> 383 bytes .../ic_file_remove_black_24dp.png | Bin 0 -> 396 bytes .../ic_folder_add_black_24dp.png | Bin 0 -> 282 bytes .../ic_folder_delete_black_24dp.png | Bin 0 -> 262 bytes .../ic_folder_edit_black_24dp.png | Bin 0 -> 268 bytes .../drawable-mdpi/ic_file_add_black_24dp.png | Bin 0 -> 462 bytes .../drawable-mdpi/ic_file_edit_black_24dp.png | Bin 0 -> 437 bytes .../ic_file_remove_black_24dp.png | Bin 0 -> 442 bytes .../ic_folder_add_black_24dp.png | Bin 0 -> 253 bytes .../ic_folder_delete_black_24dp.png | Bin 0 -> 234 bytes .../ic_folder_edit_black_24dp.png | Bin 0 -> 269 bytes .../drawable-xhdpi/ic_file_add_black_24dp.png | Bin 0 -> 651 bytes .../ic_file_edit_black_24dp.png | Bin 0 -> 623 bytes .../ic_file_remove_black_24dp.png | Bin 0 -> 609 bytes .../ic_folder_add_black_24dp.png | Bin 0 -> 382 bytes .../ic_folder_delete_black_24dp.png | Bin 0 -> 364 bytes .../ic_folder_edit_black_24dp.png | Bin 0 -> 441 bytes .../ic_file_add_black_24dp.png | Bin 0 -> 1005 bytes .../ic_file_edit_black_24dp.png | Bin 0 -> 1012 bytes .../ic_file_remove_black_24dp.png | Bin 0 -> 953 bytes .../ic_folder_add_black_24dp.png | Bin 0 -> 637 bytes .../ic_folder_delete_black_24dp.png | Bin 0 -> 586 bytes .../ic_folder_edit_black_24dp.png | Bin 0 -> 714 bytes .../ic_file_add_black_24dp.png | Bin 0 -> 1089 bytes .../ic_file_edit_black_24dp.png | Bin 0 -> 1142 bytes .../ic_file_remove_black_24dp.png | Bin 0 -> 1068 bytes .../ic_folder_add_black_24dp.png | Bin 0 -> 864 bytes .../ic_folder_delete_black_24dp.png | Bin 0 -> 843 bytes .../ic_folder_edit_black_24dp.png | Bin 0 -> 908 bytes .../res/layout/activity_recent_changes.xml | 15 ++ app/src/main/res/layout/fragment_drawer.xml | 11 ++ .../main/res/layout/item_recent_change.xml | 51 +++++ app/src/main/res/values-de/strings.xml | 7 + app/src/main/res/values/strings.xml | 7 + 52 files changed, 491 insertions(+), 5 deletions(-) create mode 100644 app/src/main/java/com/nutomic/syncthingandroid/activities/RecentChangesActivity.java create mode 100644 app/src/main/java/com/nutomic/syncthingandroid/model/DiskEvent.java create mode 100644 app/src/main/java/com/nutomic/syncthingandroid/model/DiskEventData.java create mode 100644 app/src/main/java/com/nutomic/syncthingandroid/views/ChangeListAdapter.java create mode 100644 app/src/main/res/drawable-hdpi/ic_file_add_black_24dp.png create mode 100644 app/src/main/res/drawable-hdpi/ic_file_edit_black_24dp.png create mode 100644 app/src/main/res/drawable-hdpi/ic_file_remove_black_24dp.png create mode 100644 app/src/main/res/drawable-hdpi/ic_folder_add_black_24dp.png create mode 100644 app/src/main/res/drawable-hdpi/ic_folder_delete_black_24dp.png create mode 100644 app/src/main/res/drawable-hdpi/ic_folder_edit_black_24dp.png create mode 100644 app/src/main/res/drawable-ldpi/ic_file_add_black_24dp.png create mode 100644 app/src/main/res/drawable-ldpi/ic_file_edit_black_24dp.png create mode 100644 app/src/main/res/drawable-ldpi/ic_file_remove_black_24dp.png create mode 100644 app/src/main/res/drawable-ldpi/ic_folder_add_black_24dp.png create mode 100644 app/src/main/res/drawable-ldpi/ic_folder_delete_black_24dp.png create mode 100644 app/src/main/res/drawable-ldpi/ic_folder_edit_black_24dp.png create mode 100644 app/src/main/res/drawable-mdpi/ic_file_add_black_24dp.png create mode 100644 app/src/main/res/drawable-mdpi/ic_file_edit_black_24dp.png create mode 100644 app/src/main/res/drawable-mdpi/ic_file_remove_black_24dp.png create mode 100644 app/src/main/res/drawable-mdpi/ic_folder_add_black_24dp.png create mode 100644 app/src/main/res/drawable-mdpi/ic_folder_delete_black_24dp.png create mode 100644 app/src/main/res/drawable-mdpi/ic_folder_edit_black_24dp.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_file_add_black_24dp.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_file_edit_black_24dp.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_file_remove_black_24dp.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_folder_add_black_24dp.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_folder_delete_black_24dp.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_folder_edit_black_24dp.png create mode 100644 app/src/main/res/drawable-xxhdpi/ic_file_add_black_24dp.png create mode 100644 app/src/main/res/drawable-xxhdpi/ic_file_edit_black_24dp.png create mode 100644 app/src/main/res/drawable-xxhdpi/ic_file_remove_black_24dp.png create mode 100644 app/src/main/res/drawable-xxhdpi/ic_folder_add_black_24dp.png create mode 100644 app/src/main/res/drawable-xxhdpi/ic_folder_delete_black_24dp.png create mode 100644 app/src/main/res/drawable-xxhdpi/ic_folder_edit_black_24dp.png create mode 100644 app/src/main/res/drawable-xxxhdpi/ic_file_add_black_24dp.png create mode 100644 app/src/main/res/drawable-xxxhdpi/ic_file_edit_black_24dp.png create mode 100644 app/src/main/res/drawable-xxxhdpi/ic_file_remove_black_24dp.png create mode 100644 app/src/main/res/drawable-xxxhdpi/ic_folder_add_black_24dp.png create mode 100644 app/src/main/res/drawable-xxxhdpi/ic_folder_delete_black_24dp.png create mode 100644 app/src/main/res/drawable-xxxhdpi/ic_folder_edit_black_24dp.png create mode 100644 app/src/main/res/layout/activity_recent_changes.xml create mode 100644 app/src/main/res/layout/item_recent_change.xml diff --git a/README.md b/README.md index 86de1e83..ee0bd359 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,11 @@ [![License: MPLv2](https://img.shields.io/badge/License-MPLv2-blue.svg)](https://opensource.org/licenses/MPL-2.0) - + # Major enhancements in this fork are: - Individual sync conditions can be applied per device and per folder (for expert users). +- Recent changes UI. - UI explains why syncthing is running or not running according to the run conditions set in preferences. - "Battery eater" problem is fixed. - Android 8 and 9 support. diff --git a/app/build.gradle b/app/build.gradle index 3dc3e4ad..4f1762fe 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -10,7 +10,7 @@ dependencies { implementation 'com.google.code.gson:gson:2.8.2' implementation 'org.mindrot:jbcrypt:0.4' // com.google.guava:guava:24.1-jre will crash on Android 5.x - implementation 'com.google.guava:guava:23.6-android' + implementation 'com.google.guava:guava:26.0-android' implementation 'com.annimon:stream:1.1.9' implementation 'com.android.volley:volley:1.1.0' implementation 'com.android.support.constraint:constraint-layout:1.1.3' @@ -37,8 +37,8 @@ android { applicationId "com.github.catfriend1.syncthingandroid" minSdkVersion 16 targetSdkVersion 26 - versionCode 4174 - versionName "0.14.51.11" + versionCode 4175 + versionName "0.14.51.12" testApplicationId 'com.github.catfriend1.syncthingandroid.test' testInstrumentationRunner 'android.support.test.runner.AndroidJUnitRunner' playAccountConfig = playAccountConfigs.defaultAccountConfig diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 1c9c78c5..bf5db0ac 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -46,6 +46,15 @@ android:label="@string/app_name" android:launchMode="singleTask"> + + + mDevices; + private ChangeListAdapter mRecentChangeAdapter; + private RecyclerView mRecyclerView; + private RecyclerView.LayoutManager mLayoutManager; + private SyncthingService.State mServiceState = SyncthingService.State.INIT; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_recent_changes); + mRecyclerView = findViewById(R.id.changes_recycler_view); + mRecyclerView.setHasFixedSize(true); + mLayoutManager = new LinearLayoutManager(this); + mRecyclerView.setLayoutManager(mLayoutManager); + mRecentChangeAdapter = new ChangeListAdapter(this); + + // Set onClick listener and add adapter to recycler view. + mRecentChangeAdapter.setOnClickListener( + new ItemClickListener() { + @Override + public void onItemClick(DiskEvent diskEvent) { + Log.v(TAG, "User clicked item with title \'" + diskEvent.data.path + "\'"); + /** + * Future improvement: + * Collapse texts to the first three lines and open a DialogFragment + * if the user clicks an item from the list. + */ + } + } + ); + mRecyclerView.setAdapter(mRecentChangeAdapter); + } + + @Override + public void onServiceConnected(ComponentName componentName, IBinder iBinder) { + super.onServiceConnected(componentName, iBinder); + SyncthingServiceBinder syncthingServiceBinder = (SyncthingServiceBinder) iBinder; + syncthingServiceBinder.getService().registerOnServiceStateChangeListener(this); + } + + @Override + public void onServiceStateChange(SyncthingService.State newState) { + Log.v(TAG, "onServiceStateChange(" + newState + ")"); + mServiceState = newState; + if (newState == SyncthingService.State.ACTIVE) { + onTimerEvent(); + } + } + + @Override + protected void onDestroy() { + SyncthingService syncthingService = getService(); + if (syncthingService != null) { + syncthingService.unregisterOnServiceStateChangeListener(this); + } + super.onDestroy(); + } + + private void onTimerEvent() { + if (isFinishing()) { + return; + } + if (mServiceState != SyncthingService.State.ACTIVE) { + return; + } + SyncthingService syncthingService = getService(); + if (syncthingService == null) { + Log.e(TAG, "syncthingService == null"); + return; + } + RestApi restApi = syncthingService.getApi(); + if (restApi == null) { + Log.e(TAG, "restApi == null"); + return; + } + mDevices = restApi.getDevices(true); + Log.v(TAG, "Querying disk events"); + restApi.getDiskEvents(DISK_EVENT_LIMIT, this::onReceiveDiskEvents); + } + + private void onReceiveDiskEvents(List diskEvents) { + Log.v(TAG, "onReceiveDiskEvents"); + if (isFinishing()) { + return; + } + + mRecentChangeAdapter.clear(); + for (DiskEvent diskEvent : diskEvents) { + if (diskEvent.data != null) { + // Replace "modifiedBy" partial device ID by readable device name. + if (!TextUtils.isEmpty(diskEvent.data.modifiedBy)) { + for (Device device : mDevices) { + if (diskEvent.data.modifiedBy.equals(device.deviceID.substring(0, diskEvent.data.modifiedBy.length()))) { + diskEvent.data.modifiedBy = device.getDisplayName(); + break; + } + } + } + mRecentChangeAdapter.add(diskEvent); + } + } + mRecentChangeAdapter.notifyDataSetChanged(); + } +} diff --git a/app/src/main/java/com/nutomic/syncthingandroid/fragments/DrawerFragment.java b/app/src/main/java/com/nutomic/syncthingandroid/fragments/DrawerFragment.java index 63ef1aed..271de321 100644 --- a/app/src/main/java/com/nutomic/syncthingandroid/fragments/DrawerFragment.java +++ b/app/src/main/java/com/nutomic/syncthingandroid/fragments/DrawerFragment.java @@ -17,6 +17,7 @@ import android.widget.Toast; import com.google.common.collect.ImmutableMap; import com.nutomic.syncthingandroid.R; import com.nutomic.syncthingandroid.activities.MainActivity; +import com.nutomic.syncthingandroid.activities.RecentChangesActivity; import com.nutomic.syncthingandroid.activities.SettingsActivity; import com.nutomic.syncthingandroid.activities.TipsAndTricksActivity; import com.nutomic.syncthingandroid.activities.WebGuiActivity; @@ -44,6 +45,7 @@ public class DrawerFragment extends Fragment implements SyncthingService.OnServi */ private TextView mVersion = null; private TextView mDrawerActionShowQrCode; + private TextView mDrawerRecentChanges; private TextView mDrawerActionWebGui; private TextView mDrawerActionImportExport; private TextView mDrawerActionRestart; @@ -91,6 +93,7 @@ public class DrawerFragment extends Fragment implements SyncthingService.OnServi mVersion = view.findViewById(R.id.version); mDrawerActionShowQrCode = view.findViewById(R.id.drawerActionShowQrCode); + mDrawerRecentChanges = view.findViewById(R.id.drawerActionRecentChanges); mDrawerActionWebGui = view.findViewById(R.id.drawerActionWebGui); mDrawerActionImportExport = view.findViewById(R.id.drawerActionImportExport); mDrawerActionRestart = view.findViewById(R.id.drawerActionRestart); @@ -100,6 +103,7 @@ public class DrawerFragment extends Fragment implements SyncthingService.OnServi // Add listeners to buttons. mDrawerActionShowQrCode.setOnClickListener(this); + mDrawerRecentChanges.setOnClickListener(this); mDrawerActionWebGui.setOnClickListener(this); mDrawerActionImportExport.setOnClickListener(this); mDrawerActionRestart.setOnClickListener(this); @@ -134,6 +138,7 @@ public class DrawerFragment extends Fragment implements SyncthingService.OnServi // Show buttons if syncthing is running. mVersion.setVisibility(synthingRunning ? View.VISIBLE : View.GONE); mDrawerActionShowQrCode.setVisibility(synthingRunning ? View.VISIBLE : View.GONE); + mDrawerRecentChanges.setVisibility(synthingRunning ? View.VISIBLE : View.GONE); mDrawerActionWebGui.setVisibility(synthingRunning ? View.VISIBLE : View.GONE); mDrawerActionRestart.setVisibility(synthingRunning ? View.VISIBLE : View.GONE); mDrawerTipsAndTricks.setVisibility(View.VISIBLE); @@ -171,6 +176,10 @@ public class DrawerFragment extends Fragment implements SyncthingService.OnServi case R.id.drawerActionShowQrCode: showQrCode(); break; + case R.id.drawerActionRecentChanges: + startActivity(new Intent(mActivity, RecentChangesActivity.class)); + mActivity.closeDrawer(); + break; case R.id.drawerActionWebGui: startActivity(new Intent(mActivity, WebGuiActivity.class)); mActivity.closeDrawer(); diff --git a/app/src/main/java/com/nutomic/syncthingandroid/http/GetRequest.java b/app/src/main/java/com/nutomic/syncthingandroid/http/GetRequest.java index f1d3463b..64d7498d 100644 --- a/app/src/main/java/com/nutomic/syncthingandroid/http/GetRequest.java +++ b/app/src/main/java/com/nutomic/syncthingandroid/http/GetRequest.java @@ -26,6 +26,7 @@ public class GetRequest extends ApiRequest { public static final String URI_DEVICEID = "/rest/svc/deviceid"; public static final String URI_REPORT = "/rest/svc/report"; public static final String URI_EVENTS = "/rest/events"; + public static final String URI_EVENTS_DISK = "/rest/events/disk"; public GetRequest(Context context, URL url, String path, String apiKey, @Nullable Map params, OnSuccessListener listener) { diff --git a/app/src/main/java/com/nutomic/syncthingandroid/model/DiskEvent.java b/app/src/main/java/com/nutomic/syncthingandroid/model/DiskEvent.java new file mode 100644 index 00000000..01ff74da --- /dev/null +++ b/app/src/main/java/com/nutomic/syncthingandroid/model/DiskEvent.java @@ -0,0 +1,15 @@ +package com.nutomic.syncthingandroid.model; + +/** + * REST API endpoint "/rest/events/disk" + */ +public class DiskEvent { + public long id = 0; + public long globalID = 0; + public String time = ""; + + // type = {"LocalChangeDetected", "RemoteChangeDetected"} + public String type = ""; + + public DiskEventData data; +} diff --git a/app/src/main/java/com/nutomic/syncthingandroid/model/DiskEventData.java b/app/src/main/java/com/nutomic/syncthingandroid/model/DiskEventData.java new file mode 100644 index 00000000..bf4f5c73 --- /dev/null +++ b/app/src/main/java/com/nutomic/syncthingandroid/model/DiskEventData.java @@ -0,0 +1,18 @@ +package com.nutomic.syncthingandroid.model; + +/** + * REST API endpoint "/rest/events/disk" + */ +public class DiskEventData { + // action = {"added", "deleted", "modified"} + public String action = ""; + + public String folder = ""; + public String folderID = ""; + public String label = ""; + public String modifiedBy = ""; + public String path = ""; + + // type = {"file", "dir"} + public String type = ""; +} diff --git a/app/src/main/java/com/nutomic/syncthingandroid/service/RestApi.java b/app/src/main/java/com/nutomic/syncthingandroid/service/RestApi.java index 74fdecfc..bd47db1f 100644 --- a/app/src/main/java/com/nutomic/syncthingandroid/service/RestApi.java +++ b/app/src/main/java/com/nutomic/syncthingandroid/service/RestApi.java @@ -27,6 +27,7 @@ import com.nutomic.syncthingandroid.model.Completion; import com.nutomic.syncthingandroid.model.CompletionInfo; import com.nutomic.syncthingandroid.model.Connections; import com.nutomic.syncthingandroid.model.Device; +import com.nutomic.syncthingandroid.model.DiskEvent; import com.nutomic.syncthingandroid.model.Event; import com.nutomic.syncthingandroid.model.Folder; import com.nutomic.syncthingandroid.model.FolderIgnoreList; @@ -42,6 +43,7 @@ import com.nutomic.syncthingandroid.service.Constants; import java.lang.reflect.Type; import java.net.URL; +import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; @@ -671,6 +673,30 @@ public class RestApi { }); } + /** + * Requests and parses information about recent changes. + */ + public void getDiskEvents(int limit, OnResultListener1> listener) { + new GetRequest( + mContext, mUrl, + GetRequest.URI_EVENTS_DISK, mApiKey, + ImmutableMap.of("limit", Integer.toString(limit)), + result -> { + List diskEvents = new ArrayList<>(); + try { + JsonArray jsonDiskEvents = new JsonParser().parse(result).getAsJsonArray(); + for (int i = jsonDiskEvents.size()-1; i >= 0; i--) { + JsonElement jsonDiskEvent = jsonDiskEvents.get(i); + diskEvents.add(new Gson().fromJson(jsonDiskEvent, DiskEvent.class)); + } + listener.onResult(diskEvents); + } catch (Exception e) { + Log.e(TAG, "getDiskEvents: Parsing REST API result failed. result=" + result); + } + } + ); + } + /** * Listener for {@link #getEvents}. */ diff --git a/app/src/main/java/com/nutomic/syncthingandroid/views/ChangeListAdapter.java b/app/src/main/java/com/nutomic/syncthingandroid/views/ChangeListAdapter.java new file mode 100644 index 00000000..239e5444 --- /dev/null +++ b/app/src/main/java/com/nutomic/syncthingandroid/views/ChangeListAdapter.java @@ -0,0 +1,177 @@ +package com.nutomic.syncthingandroid.views; + +import android.annotation.TargetApi; +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.res.Resources; +import android.support.v7.widget.RecyclerView; +import android.net.Uri; +import android.os.Build; +// import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import com.nutomic.syncthingandroid.R; +import com.nutomic.syncthingandroid.model.DiskEvent; + +import java.io.File; +import java.time.format.DateTimeFormatter; +import java.time.format.FormatStyle; +import java.time.ZonedDateTime; +import java.time.ZoneId; + +import java.util.ArrayList; +import java.util.Locale; + +public class ChangeListAdapter extends RecyclerView.Adapter { + + // private static final String TAG = "ChangeListAdapter"; + + private final Context mContext; + private final Resources mResources; + private ArrayList mChangeData = new ArrayList(); + private ItemClickListener mOnClickListener; + private LayoutInflater mLayoutInflater; + + public interface ItemClickListener { + void onItemClick(DiskEvent diskEvent); + } + + public ChangeListAdapter(Context context) { + mContext = context; + mResources = mContext.getResources(); + mLayoutInflater = LayoutInflater.from(mContext); + } + + public void clear() { + mChangeData.clear(); + } + + public void add(DiskEvent diskEvent) { + mChangeData.add(diskEvent); + } + + public void setOnClickListener(ItemClickListener onClickListener) { + mOnClickListener = onClickListener; + } + + public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { + public ImageView typeIcon; + public TextView filename; + public TextView folderPath; + public TextView modifiedByDevice; + public TextView dateTime; + public View layout; + + public ViewHolder(View view) { + super(view); + typeIcon = view.findViewById(R.id.typeIcon); + filename = view.findViewById(R.id.filename); + folderPath = view.findViewById(R.id.folderPath); + modifiedByDevice = view.findViewById(R.id.modifiedByDevice); + dateTime = view.findViewById(R.id.dateTime); + view.setOnClickListener(this); + } + + @Override + public void onClick(View view) { + int position = getAdapterPosition(); + DiskEvent diskEvent = mChangeData.get(position); + if (mOnClickListener != null) { + mOnClickListener.onItemClick(diskEvent); + } + } + } + + @Override + public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View view = mLayoutInflater.inflate(R.layout.item_recent_change, parent, false); + return new ViewHolder(view); + } + + @SuppressLint("SetTextI18n") + @Override + public void onBindViewHolder(ViewHolder viewHolder, final int position) { + DiskEvent diskEvent = mChangeData.get(position); + + // Separate path and filename. + Uri uri = Uri.parse(diskEvent.data.path); + String filename = uri.getLastPathSegment(); + String path = getPathFromFullFN(diskEvent.data.path); + + // Decide which icon to show. + int drawableId = R.drawable.ic_help_outline_black_24dp; + switch (diskEvent.data.type) { + case "dir": + switch (diskEvent.data.action) { + case "added": + drawableId = R.drawable.ic_folder_add_black_24dp; + break; + case "deleted": + drawableId = R.drawable.ic_folder_delete_black_24dp; + break; + case "modified": + drawableId = R.drawable.ic_folder_edit_black_24dp; + break; + default: + } + break; + case "file": + switch (diskEvent.data.action) { + case "added": + drawableId = R.drawable.ic_file_add_black_24dp; + break; + case "deleted": + drawableId = R.drawable.ic_file_remove_black_24dp; + break; + case "modified": + drawableId = R.drawable.ic_file_edit_black_24dp; + break; + default: + } + break; + default: + } + viewHolder.typeIcon.setImageResource(drawableId); + + // Fill text views. + viewHolder.filename.setText(filename); + viewHolder.folderPath.setText(diskEvent.data.label + File.separator + path); + viewHolder.modifiedByDevice.setText(mResources.getString(R.string.modified_by_device, diskEvent.data.modifiedBy)); + + // Convert dateTime to readable localized string. + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { + viewHolder.dateTime.setText(mResources.getString(R.string.modification_time, diskEvent.time)); + } else { + viewHolder.dateTime.setText(mResources.getString(R.string.modification_time, formatDateTime(diskEvent.time))); + } + } + + @Override + public int getItemCount() { + return mChangeData.size(); + } + + /** + * Converts dateTime to readable localized string. + */ + @TargetApi(26) + private String formatDateTime(String dateTime) { + ZonedDateTime parsedDateTime = ZonedDateTime.parse(dateTime); + ZonedDateTime zonedDateTime = parsedDateTime.withZoneSameInstant(ZoneId.systemDefault()); + DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM).withLocale(Locale.getDefault()); + return formatter.format(zonedDateTime); + } + + private String getPathFromFullFN(String fullFN) { + int index = fullFN.lastIndexOf('/'); + if (index > 0) { + return fullFN.substring(0, index); + } + return ""; + } +} diff --git a/app/src/main/play/en-GB/whatsnew b/app/src/main/play/en-GB/whatsnew index c16c41ab..e402b2ba 100644 --- a/app/src/main/play/en-GB/whatsnew +++ b/app/src/main/play/en-GB/whatsnew @@ -1,4 +1,5 @@ Enhancements +* Added "Recent changes" UI [NEW] * Specify sync conditions differently for each folder, device [NEW] * Added offline 'tips & tricks' content [NEW] * UI explains why syncthing is running (or not) @@ -6,6 +7,5 @@ Enhancements Fixes * Fixed the "battery eater" * Android 8 and 9 support -* Fixed phone plugged to charger detection Maintenance * Updated syncthing to v0.14.51 (receiveOnly folders) diff --git a/app/src/main/res/drawable-hdpi/ic_file_add_black_24dp.png b/app/src/main/res/drawable-hdpi/ic_file_add_black_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..25d1e5ac10049eb574fc7d1ad3318a1bf68927e5 GIT binary patch literal 663 zcmV;I0%-k-P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGf6951U69E94oEQKA0xU^HK~z{r?U&6< zR8bg*Z<&#O>=YN38S0|Itpw@HmbI&J(V~t2fY4f9yJ;bU61a4s;35fe;YZZJP*92O zav>E|sQLN)&Y1%;&bjBFnL7i@Jn(SOIn2y`=RNOvXKqsGtZ|`m_0f%kc*D%HvxB3! zX=XX`0RP}onSREb7=PNPJE(7YfKRj# z;3ewyBdFj`X7&?i&eX-iwU~y&RW-0=hnZQxXZX*|lH?w);Vm-@;0ws{A9w9AibZ^m zDsIt%A21kHD4CJ%qaB{6 z+8J^bZ=bi8e3?)Ye#7smUKB#dei~O%C(6e|d}N1lyP$y7LpIDTOfR~=lhu;sl_8;^ zRJ3WRzfIs}tZIg`(ug{7-VEhY)YnlpB%f-b8pLEs$Jo_H==C+pP_ERXF-GCLu};fZ z^qsOv)JYMlAy+$Ud~LyJ!%afeF8Y*|oUZDQw zie?Px#1ZP1_K>z@;j|==^1poj532;bRa{vGf6951U69E94oEQKA0u4z-K~z{r?Uy}E z98na8Cm+THqMf9OUm-RMVx_z)4+K)H|G+{lM6j^1u&_`>Quu{}zaWAr z+L-!85$d(;a+?sjyY(G4A3k{DtE|-|`nWzAoQ2+8D_G`nz z5bEPsgNZB@Ga(T_eJ!ZQZ!}RBYzevMQySu@uNk+(x zp@{hDv-Xm$5^BOdJVebR7rN}HaSe4v*?5cZ!)3a&poBC-4ou|c9Y%8}saf$=A)%zy zw7JlHo4_YnvR-zlZ4`qv71CuK^@Z#6C8>~CN--Ey zQ8pF2Gb%D6-86N}klWfQ1RqUZjhz`gv{48?D&%!A`bg*md+`gZTDi!3oaiR0X?l!x z+Hf$4dR?kDk)1ZwtCV$8+jxQhQD2Px#1ZP1_K>z@;j|==^1poj532;bRa{vGf6951U69E94oEQKA0s2WqK~z{r?U%bs zBtaC0+f^481(Rh1@2G)+sVu0Gh8ijc1}46MFQC4Gfe4CVxWNVniim+X^c57mpqWM@ zsCd78fAusBGgDLDGd%+?^T9{g8Jza?sZ)n(uf%twEOE8bjgwesqVPQ7EMA)^CjQ_Z ze&*;gHee)d6{^4!Y{N&K$5njAObp>P?qd&Dp*Y8WyfRT9w4k2y9f$RSg9+5%&!Cb^ zuIv$puGEjjHI?$jRXwofFGI7ABlut<&+EcHY&4MrTS5UZ`0Otuv5BLo<`(UEfX<{` z3FX5Es#5nR^4nksn@nV(kO_&@?dw1_ezS=(U`xm~pQ4bueXV%tFViV>g#uEy&)Q42 zN~j6X@DeqPTZxpxz8K zF4FjoAE?BZ^g&GgL*3K%ewVd`e{sxTdN;U@ZzhUPH4b1cDxo=?!bs>QYpAEuP2y0m zRGQq@k>P4GeNl5Lr+v?WUduH~lw67b0nhsa{F;;AIum$Y00000NkvXXu0mjfGszRB literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-hdpi/ic_folder_add_black_24dp.png b/app/src/main/res/drawable-hdpi/ic_folder_add_black_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..d60b84ffb5065ba680199284a7ee898af7b555b8 GIT binary patch literal 377 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbB7>k44ofy`glX(f`u%tWsIx;Y9 z?C1WI$O`0h7I;J!Gca%qgD@k*tT_@u4Sb$1jv*25Z>Kx*F&c`rv2%C!9yz4Aqvf+j z>)Kv{&eq=5J6iV6ozTI}@o##j`qj+ztXtumUrevb6tCF7&EI{Rhl-MMi*-e7KD+n^ z=9@Phf)i)!dn~M)&?;>ry6zLFrU>_!hszep#695RTQGG-Tu_TXK^hYB2%u-Rg~Su^=elR+f}}m zMO?Wn)@x^MN?o)1hRTKO=8ul;=rO%;RO|ld)2i8PuKv>dZLP>O_hBH=j4yqG-zWbz zKN+$5Yjl~o^1?F4cA>3lnim{< U7l+8Y0)vae)78&qol`;+0PQf84gdfE literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-hdpi/ic_folder_delete_black_24dp.png b/app/src/main/res/drawable-hdpi/ic_folder_delete_black_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..f63ef91456865e34c91ebf2329f15e5c7406825a GIT binary patch literal 325 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbB7>k44ofy`glX(f`u%tWsIx;Y9 z?C1WI$O`0h7I;J!Gca%qgD@k*tT_@u!CRg#jv*25Z>KwQ9WoGbU9HDr-gNzgklfj| z(t#}Ec{cMjI>ZIO^80#uOg0Ovi%OBRnH2g=-N!3RqifPkOPfR5HR?Osls%I9om-Rl zEohnLz-2C>b?1q&mj>6SiWM4%x$hj3?3rXdp_E8bg=d#Wzp$P!@T6r`8 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-hdpi/ic_folder_edit_black_24dp.png b/app/src/main/res/drawable-hdpi/ic_folder_edit_black_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..0cd74ce0bd5f645350f4824ae411daab70fa9e62 GIT binary patch literal 418 zcmV;T0bTxyP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGf6951U69E94oEQKA0XIoRK~z{r?U%7? zLNOGEuR6522oBQGxliFE`3SBq#UkzCpnaou?AC5op*Sf;)b{`JMC@&%$0oTgk`F%a zA&BSa5OZUeNF)lT2Jhhnek$z15{$+zv^93QfeclFQJ6wo<3p|>Lq&mKZfhFDH+Tc9 z&`FVjj6Jv`zabeY+J0~_gY|8BIFR<&(-g_8sDaZlID4(38Ksssd=Xh|F@3)ED$CP{ zC0vNCy$BJg0k1{YUW5n~lzgD5uK^AJenNlFS?-}H_#m?OBE*DvO1DIFV*i>Dfu5l` z7$3P166!lvI6;>1s;*b3=G`DAk4@xYmNj^gO;a@V~BuVM}m60a_0E&ITk)$@{m&(`;OM_KUx>HwC`vNujmo(R$cRuds?hnl6?LL zk^39lPtQ1MWq0(Ugr{O*lh(E4XOikQRc8HYd=-AGDZVwgrlT+RtKB2kYX+)!)-1DI za8D;ibazBSWY4#&hVPA>jspmP8K literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-ldpi/ic_file_edit_black_24dp.png b/app/src/main/res/drawable-ldpi/ic_file_edit_black_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..c1b706e7dbea517ea7e260683858ddd86baae65a GIT binary patch literal 383 zcmV-_0f7FAP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGf6951U69E94oEQKA0Tf9@K~y+Ty_CC3 z13?%@*9(YD87Kci)im7NJ1J-kw>tUq_D6HX+=%+d^5X~ z*&!oS1P>hM{}=XS=eF6RSjxwO4Q$}5>B>y8i=U%CS zw($e^OgG~gdw7N4_=sy5We3N$EKvlB3shJeqhTpQ;u0sQ^>QrdqX-w?N7Fvd9pVEv z(c!002ovPDHLkV1hFZnEwC( literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-ldpi/ic_file_remove_black_24dp.png b/app/src/main/res/drawable-ldpi/ic_file_remove_black_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..b06f3a289769ecae76e7ecc181ad7a0e26fb4861 GIT binary patch literal 396 zcmV;70dxL|P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGf6951U69E94oEQKA0U=35K~y+Tt(3t^ zLO~RUZy7~cl!+^MMw=k0wVPVGa@7+QK7c)p=-x+&!j&z0fYuT91|hAAsOHCYr(>6uZ+6I?M_o-Z8XyU7ClLW;-Oz+0T6*uf@l;x(RPVX=&D ze8ZZ_emKM%?BEAp;u_ASf)g9&$O?%wRIw|ZTkJQ5#5sPV_T^YkPZ2KOM`ItSKH(5s z=8b8Re{EI@^dMk_)Ea=)BE+P{d6wu=WgbiAMzuZ~`E6=w)X z>!L2D?;VPn(PACxV%BZwP#5?3r;cJom#s^-f%_(lbA&492ruCP^%^{2_R@yv%lEK{ q7y3Yig_Kv*Glu?Bo^7~LlH?n+-!nHI_4eWb0000!lvI6;>1s;*b3=G`DAk4@xYmNj^aJ{FCV~BHx0 z`yJghC9dR{`u@eLhwff6ZGHXf)AX_%EmALp__|6BPySJ`w+%b5;{DcxeU0%9iM9P5 z)1*p{vgt4W%6l^Gf^_m-Ume@c*A|_Vl=U&PPw3O#@>lKUe4P!a-)FSkP!D?AsCa93 avHdhv%TG=FI=p~RXYh3Ob6Mw<&;$Tw@M|~# literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-ldpi/ic_folder_delete_black_24dp.png b/app/src/main/res/drawable-ldpi/ic_folder_delete_black_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..438f3e1df4d693cd196ce19fffb56883767ff611 GIT binary patch literal 262 zcmeAS@N?(olHy`uVBq!ia0vp^LLkh+1|-AI^@Rf|#^NA%Cx&(BWL^R}Ea{HEjtmSN z`?>!lvI6;>1s;*b3=G`DAk4@xYmNj^aJHw5V~B0DfuUt-GyIyFmL;8k*vRPf%dyzbDp3Dc|ES_ zWm^Btl;t-ZWnT4H;)}YZ+-%u38{T*FL?$*}KDyKV;5D-)8~;x;2Rf6%)78&qol`;+ E07dLwhyVZp literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-ldpi/ic_folder_edit_black_24dp.png b/app/src/main/res/drawable-ldpi/ic_folder_edit_black_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..abea0c4a7f89426b46fadbb4d3d6681de0815d41 GIT binary patch literal 268 zcmeAS@N?(olHy`uVBq!ia0vp^LLkh+1|-AI^@Rf|#^NA%Cx&(BWL^R}Ea{HEjtmSN z`?>!lvI6;>1s;*b3=G`DAk4@xYmNj^aG|G*V~BnLOPo50_5_sW`C{E!Vj@mDD}Z^okimfu+~yfM76Px#1ZP1_K>z@;j|==^1poj532;bRa{vGf6951U69E94oEQKA0b@x-K~zXf)s?$0 z1wkB#7m12QByJ4~J%t7hg~l_8N}|zt08gM0g;pX;UO+`erSb$W5z%UtF5hp@O#F9t z_A=*G=S#lK%x?Dl{yUdFS>H3@TFV5U;7mTM<{kI&D<4%51`Of@F5(qFp=B1g@fGLr z4!5v2#G>kd@h~5iSx4QU$7k19$OyJ#3iXhFD25LZHsl_oA)1nIdBF|WuHiL~Vu4-) zgbi6mg%k(_V!Nsd8?vGcmee=+bgkyysiA zRaCW$^y9i03)nO|`k(1rz^#8ceY1y3wM)3b|Bf0-d~c!s5Q=x4I*4+36G-k$L1!2kdN07*qoM6N<$ Ef_=Wgpa1{> literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-mdpi/ic_file_edit_black_24dp.png b/app/src/main/res/drawable-mdpi/ic_file_edit_black_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..663e19a64b964e1f4273f7c52a57a91b3f8d88c1 GIT binary patch literal 437 zcmV;m0ZRUfP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGf6951U69E94oEQKA0ZK_kK~zXf<(0cG z1wjCY7m12QByJ4~J%t7hg+`|rl|K($_s^M$*}3fQ zIj1`DC12*U+4IkJPto)A+0thWk8sMg^1R_LewtQ>FrXjra2_x40ez-%3!iZYZ*T)E zLwq#)AKW*sm{rvCS$wp0g$!XMCQvWwhf=rz;fLH}GDJ(#DNnd&%N4xDVJy*2fbc_> zQ6VM5fYhm~!w*?fhfljR_^_qc-B){|J&6cMJc;k95nZbzU;(w!8m$X+EaCxHu7UzI zqTDGu#4A)#$U5rX674RLo56@_HK5y5RLlPhxJR9?@C0QE13I~AmE>kHV9Ssf)Jf7z zLI!PF$tZr~nQ6u7`DUvcagJZD>K~~kImK<%jn*fi33E7($GE2sM=C(evx9YinIW%u fg3)d6Ws2e#Mfy7W;|=W@00000NkvXXu0mjfFb=b~ literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-mdpi/ic_file_remove_black_24dp.png b/app/src/main/res/drawable-mdpi/ic_file_remove_black_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..c6f0c972bd1a61ae4a662420be79450e3f659796 GIT binary patch literal 442 zcmV;r0Y(0aP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGf6951U69E94oEQKA0Z&OpK~zXf)s?+2 z1wj~w7m12QB>ox{dI}913XN+JmE<&T!4)V(p_Pb|8=xVgQn>;@5z%Utex7%BHfDFf zo!xaJah~MK%`8i_K0k(x;Q>y$RW&cz!FRW+pcv4Pw>Xbyc#k2|xQS0V zgV(r$(U1`B{tI{As>~|t^I3fGbA=3HBPLKc>5D9~01<}Vpc$eg`7MvQ=EoI0$6?IT zO@IhPmQf)&iUC$v)e(j)=|V``CwTLt&OKDMP)$k{cRY!&s2yGDg24igq|+RWxQEeG zP=Iz+)kQJZQTOKPw#c>oivXSZWrh3L3abX$uh&u`8DQL70(Y)*O)bNuDl_As*gur(|QL70(Y)*O)bdQTU}5D)LSQxdrv6nNa$Dqm~el^wXeFA0bWEmP_`%UhQVTd%n3r a8vBE;Y?(~HWvxJ`FnGH9xvXQL70(Y)*O)bMV>B>As*gur(EPcq#)3?QTj^jorSR{F5Yo{ zyqWL9wf`(aQWiUeSJyu9-sf=XN!`0!Nm9F$8p3xN%u5tCpP?laC2DjqByg=stDswr zcEg^-9P$&I-9n@$^H*NpIn`o^>G6|41&wt|H(1Fs-#)1J$Hd_i-<1sO9TrD3nCE>+ z+-|gmF(gJ*KPx#1ZP1_K>z@;j|==^1poj532;bRa{vGf6951U69E94oEQKA0w765K~!i%?U_4E z#6T2aHriO(D1yJjRxEvhjlI@_osC#o`e-b*@)y{M4{Q_#U*}|U zm#|Ednaw1dUGu?5Cc$L(?A*y@W2vCvpVQ=TO&EYHu+7^`#xcB8&1_hOU+~wF4{#V} z!ZLLE;l)Qd0#l_G-b3m16>h*m*lyr1lyi3iZSe`F8e#}aXFqTT+OP%Xd=lIjpW!G> z1zuP>y5a##DgzK*h!;2xt!ehRCY<}*q%gp?YL@ANyuNh^n*b~!SLi}?!wWd+?HOVd zz%{xMU63KBygdVI8Gz_QbV8PsQHWXxAYmam64TyZ1bGNRbRjxm?2RKXfX%Z~Qo=$+ zl9v$>bRit#gR5i2-*@Mz= zBzc>})}$GLWy7))ZOh1rv;(m0#JUTR2@M}0%SVZ-i2H#2g><8uk?R2KyRydTVDK0h zwM*43!(+O|jkXL8D0=M=$(_a`E_R9bO002ovPDHLkV1l%^AUyy8 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_file_edit_black_24dp.png b/app/src/main/res/drawable-xhdpi/ic_file_edit_black_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..95a30c0fdc0d9d7688e905077c253dc4aa1ee292 GIT binary patch literal 623 zcmV-#0+9WQP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGf6951U69E94oEQKA0t87!K~!i%?U_4E z#6T2aRyJZ`qX_;AdrKc+p}p3EosC#o`e3@9=Hi3`yISx!bFiVi@kh2Tm|1-%67ApnUB(GF7|9BBbG?@C#z79x>) zSpgv~L?U?xsQmG&<~lUSbpYOoPD!irQFt9T^~)PE8>wLq&VIK{tGl(fi!yHCzO*NKrJjK4aZRCd*=s9m^>zV!o{!|@Cr{L|M6jyKDYq60>U0# z4V$&YZN4ig-%4Jd!e(d%hB$<8Fm5uNvi|p>wTt(7JatQ{^aCsd+qvl~T`T|q002ov JPDHLkV1mVb|9AiZ literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_file_remove_black_24dp.png b/app/src/main/res/drawable-xhdpi/ic_file_remove_black_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..debc48eaa24a58e34c89b175efd9d3ffe3616dd6 GIT binary patch literal 609 zcmV-n0-pVeP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGf6951U69E94oEQKA0rp8mK~!i%?U}tx z#4sF&PeBw^)Ky0jMeti3oLrn-6v4m3RUG{Q7k8ZnHy3eoR9qZ&@-J`^KX6eL{CeM} zKRG1VCT-HIng<@59M`7rC287TB@p=MG{jpI`rsmLiE8;cfLE$m3`_70eme374#GlM zfG$s7yoE#1E6wm4N~4c(752kc1Gk{;yIEBh@1WNZ15g_KfK$+hbtwCj>biIjhoKjE zU}@-#A6W7;0MUhbfTPfw#&~PONxaPq18k_`H(ij&w+>+wfJ4X?x)7c46plwVLu>-L zMi-(3GQ>nwGoYRUh%Q7sI_3;~EPL>o-KaHIvWxmU_dtq_Tn zr3VCEh(wAE@N@C1V!j`d0Zi5bhLi8v z$o+JLb>P?V=jXr}l(87@g?tbKcp`P^2sQ!u(y1tV;%#oKA87bKzla{=EBz;EG>Oyb zhVM`gwg-K42&KJOevpL8HI@gQSH*~Dcm(;!hf8|l9Apm&J8)SQv%}YX=TLr?qCAF8 v&!lvI6;>1s;*b3=G`DAk4@xYmNj^gRrNIV@QVc+Zm^Y7!3tnk0+mx-|$HMFSpsh z1Lhk)+zQ;GYaD94Y9h}?$#*NQrcOD2qSudiuAmc#BA2p7Yjy=^36rnn0oyBL&sS%5 zSY8nmT@~43mHOFZvVi*v-D6%iFG$Kb>j!ZMR5UpMm=wa?!5y)1YJaMV!*$=u$?Vm6 zuP!jnNjUDCpRxX@+NRH`TCX#oCnqO1sNa!4ppn72Cfkl<+62>H{smWmOHPxoFI9U| zS?MoZb58m_v*+i@=?^l`vVNHQdPB>aM274nwh7s%8?}25)i(Io1#FprAyq2g=~iEU z!qfg@r<}z5zOuK>H=H>x@-b?*N&mgvcgHU5-l*y!?SHFs{+r3yN?Dtux?2RC{!lvI6;>1s;*b3=G`DAk4@xYmNj^1EZ&lV@QVc+ZmpGhYWaJPj6_CKESo^L~H}E z`2(K~3AY*>@`ILy8JTD{$NuoI^19OWWWHL6g>s94lZaaZ*YyvRUa-tEYN%czD!w|i z!}3a(*Hs;txw)S`CJVT)5KUgH^Ma=@QRE)e9oqwnYmQ_y6f$~m`LwZv#_~v z%NTVJaF!kV()Mj;zLIwQk`RAud1-Fuh{dcM?tS(w;EuffgW*=4{ozMnR~ajQe`;OY zVVPgUzvG$u`2&}2(;3b;WJ?^FHJ>}-Z}()M$MYMuJ(7<2_4rMP?wj^ZhiazNHD5eJ zaxd9bZQc2sbFp-E)0U4*=6*kCml+#wuyU&hhvJj?6PvUp_wf01Ej%C%3?T+jS3j3^ HP6!lvI6;>1s;*b3=G`DAk4@xYmNj^gP*61V@QVc+Zm32hYbW=ofGfhV+t$i%-bPa zu9;KStT$nT1)q*a>UFLk!s?T9dDY5{B)#XV+umF|t3qvCa;el|1D?YPJ6ffG@YNgD zHmr&{%>1NDdR3N?{{(KW@U1Fd)6T}PQYmbSF^IavT-#D!Ah1>S!f)362m7zgV%XWr zC?5OTnKNc*UTMvtrLV1au=strR2seG{uxf&%J~ZOT(5fx`0wYKWGt}X$vb}KNy!O5 z3YG=)gf6s2zYmsm$Ws5Pqn^Q*#d*evS*D~hUvvG2 z{l~d$13TooB^7pd&fh&vVzPtKNmZBYwY&2^+IFPaeB|ko)M#Vd*Z%t3WP!p1|AJr7 zG+HS%$@l>4cgAM>bD|sDwXc^J%&xe;)znDCOiQj;_nnu;jt#B>lKrPDgRgmd*EUBk hbp-~){2Ara=Gz literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxhdpi/ic_file_add_black_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_file_add_black_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..2129a823e64c99fcbd7ca414a5d08fe93ea4ee43 GIT binary patch literal 1005 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 S^hXRB{|uh4elF{r5}E+^%=PgA literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxhdpi/ic_folder_edit_black_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_folder_edit_black_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..1bd5b0046625788aa7f9fd03fcb8de97697fdf60 GIT binary patch literal 714 zcmV;*0yX`KP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGf6951U69E94oEQKA0$)i)K~#8N?VCSK z96=byFF_4x6pN51*rbxQ5mF1bwt`ive1LodKS2;1%TzWggxHIPg`~2v6f6V#<32_b|KLI@#*NRG#F9=?OS@CUrF z$u&3yv*i(d3y+~Sz=!%1GDuHgmb`>V&>CD_{(=lrmawe;Kx<%in`OD}Lu)WG%(C3R zLTfOwOtRcK5tqRZXFGv3l;Y1iz<7oZzB?wURLzLNtiD+_a6sRZa# zvF&H2*w#sw0jkvL2U1&rZsC|~_7J1fym7NwEVgx0DL|=Q#V$)6I;mt(vL&Ybpa2R` z00k(3FF-NsKRc8`0TiGBDzN~{pa2R`0F_t(Wl#VGD1fhw_%Pf0JVxp1aYq2_Q3oA5 zsbo;Hk2`!F_@A9ti3PCAizW>tZ5e}A*ngZ?Fb4g{>1dKl2Avn%Zj?b?JcnG0(mBQl z7;EWG_gK0$NhO0W;Hhi2VX*kG?_}YOZbg~KVg_<4%0~NDJghNMld?-T-{*ahMU2aQ z2kx6${k#1t4rReG$CXNnbztXX2B$KQL70(Y)*J~22Igy?E{-7;ac}3I@AgfUIQ~2+rJ2`t%7zVd z{zL?5q#VA)rk#E2+%YC@>G}rQX;U^W@=)aFOx5hv@S5^zv&OOSGr#-1lQ}=LdfxAS z&uyL`{~kR5Ty?+X^K-vv7Qdfaoc>PI$Jf_a!2VgP_ahc&i^B}(3>u7i9`Hb!=AW8x z>=4_)Gp{ZGLB59k4Ho^wPcl9y1;$2(wfcTAmic#RcFHG?TYDlx!l#+KUskU_rfnbz z;g)u6^ZD0vJwa$ohWiWM@y<3IedbEdtbYeV;k4j!%_%<+f0 z1IqrdHxQNI^wi+_gH8h(&ytoK44cc?S0||cQTp%O_&srI#%+-&8a}_x&%Q3m0h+pE zosRYm?e7Z@v~S4T^7dRpr$Y6i2&n4{0^T)0(%-=n*1PR(qK;smqcOx)qB7HdFR0+Z z*0}Ah%`}ef3psP+bXIAf=IUa4(_FeBH~O&9Lp_~dGkvkEQ&U-^7%X2!GQ3vUpSzL6 zyX8{#2B7$AD@pb9jK0oHb2txAeABYkrsvz+oE4@{SKBY{wUN#3+#qYmaX9P6>(`9a zIHDgeHt_MEA3tHE%MB*&&I`{OnoJKpHt=!3&&)B6WA?+z20qNpEINWuw(?v4oyWrV zqh0loijPnuV_I-E(DR=+r%vDC*3nem(5LDo!V}=5D=3kWr`3OeVev{6CvoPC=iifU zS+yIhK{4iYo7v}oTEy&^hvY82;)t!}n8XpfTSl$@JR@?9ZZT~r+m&$R+5y`Gl57QS zjB^qh(j`DlH8Tcgw?mvIK%q<@hM&!*kyA=UZavS~b$JFu^P67vUv87XHMrHdU*nz6 z4A%r!-0()Dkbl$1Ln8&(t zPwCQc7sUP=W#u%ae{h%hcbu<6ohSM%_YN(d|Bq|8$;=iBzp#Ug|HJ|Y%bIFdeaD?$ z7t3#?JTZzXa-HB@z&hu(=U=X4|#o#2bq%yZgF_pnlX-#|j zLu(E3;tcB|fsZnB?XMFyofKa*uf@}5<#&dp7DNam1$JuEBmFsZaxAM4+`IwI_6(k` KelF{r5}E+)!_Vgc literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxxhdpi/ic_file_edit_black_24dp.png b/app/src/main/res/drawable-xxxhdpi/ic_file_edit_black_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..32bca46ecd818b026d250f4468e7340eed86e816 GIT binary patch literal 1142 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7OGojKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85p>QL70(Y)*K0-8g5S)$B>G+w{!Qd=LwWJ_C78?@JEJ+hf0%E z<>SQ)f}D#MURe+{`GpCWh*W(8pK7OztCLEH6H8}Q%Y+3A6MtxV-1%x#{>-R+@8SkE8Y z{=xhSe_vC0V#$(S86x6lp$Xc5m{!ZzOzDwp3K8#pbZFT(gI7oAf0gQKgK)!6Ed8@`6pk1szH zHku`{?XZgC7E6Xjybm)k_PXC@RsaeeOm{WslXGZPW108+!Nczw6%79`v>321Zh63X zCiR743)_YTImbD3IUIj*Ot{!0(83;YKEUY%!>`FUEc^*|liCdW7(I@EceZ7o{6P7D z1pk22ulTG2RR@hlKdB$TE49A{GHEfx< zW)|;0UV~%H70{#HiTMKq^G7DB$BYtq(By1}OO+2+-4u{&2yFnf9t2M?lxr}IWV`UT zta9(=|3`u+r_SaDa$lD0npBasD`&Ifb2o$2@OSrV9O*7f-C1 zbWS{zH`yV0C$ePnrVTm&Csi=-S)Q|aQWnb`z1t}ZZg?(hv74iDdqoS|hs`XG0)yT3Tz&5cZx_wx6ZtDU%eCO36%DVs6oA$S{L+}9G3GZ^<=gndtx%?K^-S2L17EIRf*njtT!UgG*JbBd> zu6G}tm&rDtB5v}uu1MM`;p6rL{>J@Goj+|C@G83K+I31YBy!AtQ29gdQySmS!*e^t zKd9W{SS&i9CAVd6K~g`1dnbEB4>ok_$Psx@yWcxfSuGWSWd(z$tDnm{r-UW|@O1C1 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxxhdpi/ic_file_remove_black_24dp.png b/app/src/main/res/drawable-xxxhdpi/ic_file_remove_black_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..efe176db8d9b42e8b8e66b845cabfb669a0894b6 GIT binary patch literal 1068 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7OGojKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85p>QL70(Y)*J~22IhmFE{-7;ac}3I@8&C%IsSd&30CngjfW3* z{487$aH4fFx8J!bv%8u3^!_oJ%V<7zxhYaKA)s$k$08R^`|hN@_P^(z-F&_-t=#VO z-*Yw3j{go_|Lk|qS)1RrZ{HYOpMQ5Ip{S^+=f_5cXd!ip1Cne7ZH#jg8PcK5Jrm`R zoSJo*t3qsFYyE({-l%28K08^V?b@`$c}wc2<$D_dU5&a=SVw!r|zZMZjy~D{y zCm!n8FzY+s{JZ~PNX?mPhhrL+A1a7jqZLM%zxZ__R#e{j{sZPvZ2O>a1tLM?x=!G`_l{Q}7~Qn|MeM=1F?7~k3x5fUyY zDl_%@f(rR-joaP^>IlAb5QYjrVYOg*?QnZro9ZFk2#MS{omJZ1Tw555u59MGcJRfv zqc%E%T<;G86|Z@fGG`B)2`^`X9?$bs^EFRzXWT#67Ns0gD{=Sq<%`oetREgWSkty| zpL{~+23b44!(YDqk8&=-u$u^F?!5k&KQ2Tz9iqq9~EhislHyHCg;9<5n%y7;CEAt3j z!T}G9Mv!bTr$YS(weDG^%MBUXZnmoba-00E!L7#i8gD!^QmUAf>C^B=qvXf;f>#%0 z-!Yy;G68OtL*bJ+j+2QEkG4GHH+iCdMmF(==C_p7OG37?&p9_O_L0jrAFrH-_?tyj z_7-?blr?QF2$oo;YIfjxj^(MO3Tqzg#+Y3})|KLa&9ZVDo_|P}IF}^8N4jn8Gu0U3 zw#`2#=z33n#3yzAp`zpyh4%dQ4@EV~4SzAt?zz+E{f?uEWnEM8+--J!KX=dQ^`5A7 zph{!obc&(LQL70(Y)*J~22Bxo`E{-7;ac}4B?GkYmX-zi^Jb3kngR6j9 zu(EJ1lcAaMC&4pE%Ws4f3p(toaU@9gv>QJ7@^h5a8V>DaZb zSa!xX^mzv&xsQ9{L!ub!XH5~5`@PE*c{c0+5;9t_w8iw_U@?SHuIy@A$;s5@N z>B7zhg%-?jZ>*d?NAd%++?GCxmbsg5I@ZSL%N@&L>uJCG?bfo}eM}P5y;tVCGWMK) zd1c$A&Fp_#%FMR(ex01=^ZdHZmF=7DW-&s-Moqn8=lYL}7fCuSJI3%P+I@QHLP-a= zY6i)(3`SfHJxmIVZ5w*hprNRl%D>^dpzKw*Z-Re)Qv|0NF?VU6xRSxC6zs*Y`LDv0 zJs&l{G3Yu1O`dsEF86%dTiw<!Gc`<|{^aeeXYCN6hygcLE&sPdgF z3Udi0ma=#b#C;C4Iux^gU%vl}&N;z?OJ#peKel4I(zCcb7ca^|BeTftp?<+_t0aT? z!28N8Ooum3fWlQ9Ozey6`g5POg`TqA=qK{wT z{e#i7*GU}6y%AZXoX#duwz)6;!<%0dUnJkpkKD$tf9Usy-}dLESNC3h!L()8*GbmQ zHtG*VD@pjn0hO*nIc7K?kx;&q)giYa?`~92~8nCcpz{fn5^pSnCleC{- TYp5zPS1@?G`njxgN@xNAZmw%G literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxxhdpi/ic_folder_delete_black_24dp.png b/app/src/main/res/drawable-xxxhdpi/ic_folder_delete_black_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..e42251383345ae29ce58682a47a4aa46412505d6 GIT binary patch literal 843 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7OGojKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85p>QL70(Y)*J~22Brs|E{-7;ac}3?p63aaXe-y8@MDE&hsz@8 zr4PkBqLzOW{_@B^#Z+&Tmam+rR1b)vT=oHf61A6&5n2h&1#tO$cN#;&O0fJfXoL$*QmzRq)1*=Zu=d zGL7L6lYa=_lE3!FYL3pmnB=?7YyWSQzt_4y(Pn|-oE(C zFj@J8n&Zcxyil$v?mb(lpRqIM)-&ll>DGsy3fC~oAGrO&_K$bozBZ;DG3jTu6_Rza z@&OE7`VS*_To!eB&wBNt$d>DVbEm9ncweyoZAaXVXft)g`{8GO<<~Y;-N;#QvO7~` zfu8swvreWfPhD=PY3^kE)9@`XqwA~u*%@yx%bYQ{mR}1EmnkeWep~L-ieiKW*G1EY zo-k-omGCMo7KMb}%t_~&-&8N$ovVIOZJppZhaXqp@Eu#WE;ssPrNcMB9AhiiiIUz8 zH|+$x-u)0*&s@T#1Pto7h}6X?+n(Rs81TvJz`n;bs$0%|yC{95>pJ6RS5Sn^oWxLU ze>~h(8zY{8zFg0!g>1RqVdibhRi9Zu+e&1Kq}70_=}k3QnJ>HZw?+M#z9Fat1ny85}Sb4q9e04&jFzW@LL literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxxhdpi/ic_folder_edit_black_24dp.png b/app/src/main/res/drawable-xxxhdpi/ic_folder_edit_black_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..2c85a310f25e77b15d1e200bb9f3c8b3a448c8c0 GIT binary patch literal 908 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7OGojKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85p>QL70(Y)*J~224+Q17srr_xVLkxyG0yDTFYGm54z_pP~u3- zN?Ekuq33MRAI@iw>J6^OxCk&i8XFr59E}i>pE$AKH8$XQar&z1LHXfV4}6)k@7&J^ zi>tEQmp-4jFV=SRX4{#5%cYx+_nB}BaW(WXDJ*6zgwR zWuF~Qkkn&Yzi#Kdl=Mdee;7YI8SsiWg

;-(*}U`ixbgInn6@*gQ44!+(zU9~Drn zC_P)MZY?aI@bA#^Coi0VveAFyE~FT3e5idVTl&yb;Tpd8hoe8p-dPqB@64zpuKmom zf-~=&ng~Oy_y?Xlt5_GDZ)$s}vgNy9Xq43h={w2NNs4cjXA7@*fBL7heCdILh+O^i z=D!0O4j0+=?$u~Ww48S=F6vst`wMowZ&1Ku!iEgikG$HPWF3~N zHk8^Q=l43ow}E+4ipCbU2^Xat+_D)YOBp0t9o!hfTv-q!kRb&q8^{h~h%iX5WlXuk z2x0(LWi!m|kWFBBIT_%>bKtjiK_1kcWlvA<+`26;)1mfvckR~eM!vuIcy)bUS!-z? z!=P~G-xa2g9c(f_i`{oz7tU)hbgA{5{l8)U)m_OYFSI&*t}v7>E1Z36XW5z-9)_d; zW||!i=1w@{KK1VIJhv;0?{n;CTkzt&;hU!4>B5dH_wsL0KK<|UZkHR2^F7zx{oU}t zYg+lCvb(ao&UV%~*77gOoj#4PVyfFli}japczZMOU)B(N?kH8AX~`1)8)qxGOOKlpLr}ew^F1^1ghkIUgdE!s=b>?Bx zt1m`on6AEbi_y~kfolchytbw1pI>L(o%_@{WBb}Yy#FoUUa?vr(I6ogdlMRJ;2?zr fAXeto-roCMs=CRWwCrvJa}a~4tDnm{r-UW|V4r)$ literal 0 HcmV?d00001 diff --git a/app/src/main/res/layout/activity_recent_changes.xml b/app/src/main/res/layout/activity_recent_changes.xml new file mode 100644 index 00000000..b4a72835 --- /dev/null +++ b/app/src/main/res/layout/activity_recent_changes.xml @@ -0,0 +1,15 @@ + + + + + + + + diff --git a/app/src/main/res/layout/fragment_drawer.xml b/app/src/main/res/layout/fragment_drawer.xml index ce6f2d5b..da222448 100644 --- a/app/src/main/res/layout/fragment_drawer.xml +++ b/app/src/main/res/layout/fragment_drawer.xml @@ -103,6 +103,17 @@ android:focusable="true" android:text="@string/show_device_id" /> + + + + + + + + + + + + + + + diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 48e1e30d..04db8b41 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -306,6 +306,13 @@ Bitte melden Sie auftretende Probleme via GitHub. Falls der Computer das Huawei-Gerät permanent als \"getrennt\" meldet, öffne die Syncthing-Oberfläche auf dem Computer. Gehe zu \"Externe Geräte\", klappe den Eintrag des Mobilgeräts aus, klicke \"Bearbeiten\", wechsle zu \"Erweitert\". Trage die IP-Adresse deines Mobilgeräts in \"Adressen\" wie folgt ein:\ntcp4://%1$s, dynamic\nFunktioniert sicher auf: Huawei P10 TELEFON_IP_ADRESSE + + + Letzte Änderungen + Gerät: %1$s + Zeit: %1$s + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 40538b07..221be274 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -306,6 +306,13 @@ Please report any problems you encounter via Github. If your desktop constantly reports your Huawei device as disconnected, open Syncthing UI of your desktop. Go to \'remote devices\', expand the phone\'s entry, click \'Edit\', switch to \'Advanced\'. Put your phone IP address into \'Addresses\' like this:\ntcp4://%1$s, dynamic\nConfirmed working for: Huawei P10 PHONE_IP_ADDRESS + + + Recent changes + Device: %1$s + Time: %1$s + +