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 00000000..25d1e5ac Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_file_add_black_24dp.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_file_edit_black_24dp.png b/app/src/main/res/drawable-hdpi/ic_file_edit_black_24dp.png new file mode 100644 index 00000000..3bfaa9e2 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_file_edit_black_24dp.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_file_remove_black_24dp.png b/app/src/main/res/drawable-hdpi/ic_file_remove_black_24dp.png new file mode 100644 index 00000000..d288235e Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_file_remove_black_24dp.png differ 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 00000000..d60b84ff Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_folder_add_black_24dp.png differ 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 00000000..f63ef914 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_folder_delete_black_24dp.png differ 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 00000000..0cd74ce0 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_folder_edit_black_24dp.png differ diff --git a/app/src/main/res/drawable-ldpi/ic_file_add_black_24dp.png b/app/src/main/res/drawable-ldpi/ic_file_add_black_24dp.png new file mode 100644 index 00000000..8d6377ea Binary files /dev/null and b/app/src/main/res/drawable-ldpi/ic_file_add_black_24dp.png differ 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 00000000..c1b706e7 Binary files /dev/null and b/app/src/main/res/drawable-ldpi/ic_file_edit_black_24dp.png differ 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 00000000..b06f3a28 Binary files /dev/null and b/app/src/main/res/drawable-ldpi/ic_file_remove_black_24dp.png differ diff --git a/app/src/main/res/drawable-ldpi/ic_folder_add_black_24dp.png b/app/src/main/res/drawable-ldpi/ic_folder_add_black_24dp.png new file mode 100644 index 00000000..5684c383 Binary files /dev/null and b/app/src/main/res/drawable-ldpi/ic_folder_add_black_24dp.png differ 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 00000000..438f3e1d Binary files /dev/null and b/app/src/main/res/drawable-ldpi/ic_folder_delete_black_24dp.png differ 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 00000000..abea0c4a Binary files /dev/null and b/app/src/main/res/drawable-ldpi/ic_folder_edit_black_24dp.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_file_add_black_24dp.png b/app/src/main/res/drawable-mdpi/ic_file_add_black_24dp.png new file mode 100644 index 00000000..3cb286f9 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_file_add_black_24dp.png differ 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 00000000..663e19a6 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_file_edit_black_24dp.png differ 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 00000000..c6f0c972 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_file_remove_black_24dp.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_folder_add_black_24dp.png b/app/src/main/res/drawable-mdpi/ic_folder_add_black_24dp.png new file mode 100644 index 00000000..860df71c Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_folder_add_black_24dp.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_folder_delete_black_24dp.png b/app/src/main/res/drawable-mdpi/ic_folder_delete_black_24dp.png new file mode 100644 index 00000000..28647286 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_folder_delete_black_24dp.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_folder_edit_black_24dp.png b/app/src/main/res/drawable-mdpi/ic_folder_edit_black_24dp.png new file mode 100644 index 00000000..14f1e65f Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_folder_edit_black_24dp.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_file_add_black_24dp.png b/app/src/main/res/drawable-xhdpi/ic_file_add_black_24dp.png new file mode 100644 index 00000000..282b4455 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_file_add_black_24dp.png differ 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 00000000..95a30c0f Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_file_edit_black_24dp.png differ 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 00000000..debc48ea Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_file_remove_black_24dp.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_folder_add_black_24dp.png b/app/src/main/res/drawable-xhdpi/ic_folder_add_black_24dp.png new file mode 100644 index 00000000..6277acb1 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_folder_add_black_24dp.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_folder_delete_black_24dp.png b/app/src/main/res/drawable-xhdpi/ic_folder_delete_black_24dp.png new file mode 100644 index 00000000..197d29db Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_folder_delete_black_24dp.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_folder_edit_black_24dp.png b/app/src/main/res/drawable-xhdpi/ic_folder_edit_black_24dp.png new file mode 100644 index 00000000..b6fa419e Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_folder_edit_black_24dp.png differ 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 00000000..2129a823 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_file_add_black_24dp.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_file_edit_black_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_file_edit_black_24dp.png new file mode 100644 index 00000000..3bd5cc77 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_file_edit_black_24dp.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_file_remove_black_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_file_remove_black_24dp.png new file mode 100644 index 00000000..6b5533b8 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_file_remove_black_24dp.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_folder_add_black_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_folder_add_black_24dp.png new file mode 100644 index 00000000..e2a5345d Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_folder_add_black_24dp.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_folder_delete_black_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_folder_delete_black_24dp.png new file mode 100644 index 00000000..eb75193d Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_folder_delete_black_24dp.png differ 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 00000000..1bd5b004 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_folder_edit_black_24dp.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_file_add_black_24dp.png b/app/src/main/res/drawable-xxxhdpi/ic_file_add_black_24dp.png new file mode 100644 index 00000000..60f3f7a4 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_file_add_black_24dp.png differ 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 00000000..32bca46e Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_file_edit_black_24dp.png differ 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 00000000..efe176db Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_file_remove_black_24dp.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_folder_add_black_24dp.png b/app/src/main/res/drawable-xxxhdpi/ic_folder_add_black_24dp.png new file mode 100644 index 00000000..0a788e15 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_folder_add_black_24dp.png differ 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 00000000..e4225138 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_folder_delete_black_24dp.png differ 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 00000000..2c85a310 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_folder_edit_black_24dp.png differ 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 + +