1
0
Fork 0
mirror of https://github.com/syncthing/syncthing-android.git synced 2025-01-09 03:31:46 +00:00

Add explanation in UI why syncthing is (not) running (fixes #729)

* WIP - Allow expanding the drawer if syncting is not running
- Hide syncthing process stats in Drawer if syncthing is not running
- Hide menu action button if syncthing is not running (except settings and exit)

* WIP - Add RunConditionsMonitor#getRunDecisionExplanation

* WIP - Show run status explanation in StatusFragment

* Fix duplicate declaration in RunConditionMonitor

* Explain all syncthing service statuses instead of only
differentiating between ACTIVE and NON-ACTIVE

* Remove parts marked "// to-remove"

* Remove unused resources

* Move syncthing live status from drawer into status tab

* Fix handler start and stop in StatusFragments
Note: onResume is intentionally not overidden as the fragment
is not active after the user left and reentered the app

* Fix crash on orientation change

* Only update MainActivity.ViewPager when a service state occured
This fixes a UI glitch occuring because onResume also results in
onServiceStateChanged as the serviceStateChangeListeners are
re-registered.

* Remove unused strings
This commit is contained in:
Catfriend1 2018-08-19 23:22:38 +02:00 committed by GitHub
parent b7f15860dc
commit e0d8153b6d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
51 changed files with 518 additions and 420 deletions

View file

@ -24,7 +24,7 @@ import android.provider.Settings;
import android.support.design.widget.TabLayout;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.content.ContextCompat;
import android.support.v4.view.GravityCompat;
import android.support.v4.view.ViewPager;
@ -49,6 +49,7 @@ import com.nutomic.syncthingandroid.SyncthingApp;
import com.nutomic.syncthingandroid.fragments.DeviceListFragment;
import com.nutomic.syncthingandroid.fragments.DrawerFragment;
import com.nutomic.syncthingandroid.fragments.FolderListFragment;
import com.nutomic.syncthingandroid.fragments.StatusFragment;
import com.nutomic.syncthingandroid.model.Options;
import com.nutomic.syncthingandroid.service.RestApi;
import com.nutomic.syncthingandroid.service.SyncthingService;
@ -89,11 +90,13 @@ public class MainActivity extends StateDialogActivity
private Dialog mRestartDialog;
private boolean mBatteryOptimizationDialogDismissed;
private SyncthingService.State mSyncthingServiceState = SyncthingService.State.INIT;
private ViewPager mViewPager;
private FolderListFragment mFolderListFragment;
private DeviceListFragment mDeviceListFragment;
private StatusFragment mStatusFragment;
private DrawerFragment mDrawerFragment;
private ActionBarDrawerToggle mDrawerToggle;
@ -105,13 +108,17 @@ public class MainActivity extends StateDialogActivity
*/
@Override
public void onServiceStateChange(SyncthingService.State currentState) {
if (currentState != mSyncthingServiceState) {
mSyncthingServiceState = currentState;
updateViewPager();
}
switch (currentState) {
case STARTING:
break;
case ACTIVE:
showBatteryOptimizationDialogIfNecessary();
mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
mDrawerFragment.requestGuiUpdate();
// Check if the usage reporting minimum delay passed by.
Boolean usageReportingDelayPassed = (new Date().getTime() > getFirstStartTime() + USAGE_REPORTING_DIALOG_DELAY);
@ -176,39 +183,6 @@ public class MainActivity extends StateDialogActivity
return firstInstallTime;
}
private final FragmentPagerAdapter mSectionsPagerAdapter =
new FragmentPagerAdapter(getSupportFragmentManager()) {
@Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return mFolderListFragment;
case 1:
return mDeviceListFragment;
default:
return null;
}
}
@Override
public int getCount() {
return 2;
}
@Override
public CharSequence getPageTitle(int position) {
switch (position) {
case 0:
return getResources().getString(R.string.folders_fragment_title);
case 1:
return getResources().getString(R.string.devices_fragment_title);
default:
return String.valueOf(position);
}
}
};
/**
* Initializes tab navigation.
*/
@ -218,6 +192,7 @@ public class MainActivity extends StateDialogActivity
setContentView(R.layout.activity_main);
mDrawerLayout = findViewById(R.id.drawer_layout);
mViewPager = findViewById(R.id.pager);
FragmentManager fm = getSupportFragmentManager();
if (savedInstanceState != null) {
@ -225,18 +200,24 @@ public class MainActivity extends StateDialogActivity
savedInstanceState, FolderListFragment.class.getName());
mDeviceListFragment = (DeviceListFragment) fm.getFragment(
savedInstanceState, DeviceListFragment.class.getName());
mStatusFragment = (StatusFragment) fm.getFragment(
savedInstanceState, StatusFragment.class.getName());
mDrawerFragment = (DrawerFragment) fm.getFragment(
savedInstanceState, DrawerFragment.class.getName());
} else {
}
if (mFolderListFragment == null) {
mFolderListFragment = new FolderListFragment();
}
if (mDeviceListFragment == null) {
mDeviceListFragment = new DeviceListFragment();
}
if (mStatusFragment == null) {
mStatusFragment = new StatusFragment();
}
if (mDrawerFragment == null) {
mDrawerFragment = new DrawerFragment();
}
mViewPager = findViewById(R.id.pager);
mViewPager.setAdapter(mSectionsPagerAdapter);
TabLayout tabLayout = findViewById(R.id.tabContainer);
tabLayout.setupWithViewPager(mViewPager);
if (savedInstanceState != null) {
mViewPager.setCurrentItem(savedInstanceState.getInt("currentTab"));
if (savedInstanceState.getBoolean(IS_SHOWING_RESTART_DIALOG)){
@ -246,6 +227,8 @@ public class MainActivity extends StateDialogActivity
if(savedInstanceState.getBoolean(IS_QRCODE_DIALOG_DISPLAYED)) {
showQrCodeDialog(savedInstanceState.getString(DEVICEID_KEY), savedInstanceState.getParcelable(QRCODE_BITMAP_KEY));
}
} else {
updateViewPager();
}
fm.beginTransaction().replace(R.id.drawer, mDrawerFragment).commit();
@ -261,6 +244,74 @@ public class MainActivity extends StateDialogActivity
onNewIntent(getIntent());
}
/**
* Updates the ViewPager to show tabs depending on the service state.
*/
private void updateViewPager() {
FragmentStatePagerAdapter mSectionsPagerAdapter =
new FragmentStatePagerAdapter(getSupportFragmentManager()) {
@Override
public Fragment getItem(int position) {
if (mSyncthingServiceState == SyncthingService.State.ACTIVE) {
switch (position) {
case 0:
return mFolderListFragment;
case 1:
return mDeviceListFragment;
case 2:
return mStatusFragment;
default:
return null;
}
} else {
switch (position) {
case 0:
return mStatusFragment;
default:
return null;
}
}
}
@Override
public int getItemPosition(Object object) {
return this.POSITION_NONE;
}
@Override
public int getCount() {
return mSyncthingServiceState == SyncthingService.State.ACTIVE ? 3 : 1;
}
@Override
public CharSequence getPageTitle(int position) {
if (mSyncthingServiceState == SyncthingService.State.ACTIVE) {
switch (position) {
case 0:
return getResources().getString(R.string.folders_fragment_title);
case 1:
return getResources().getString(R.string.devices_fragment_title);
case 2:
return getResources().getString(R.string.status_fragment_title);
default:
return String.valueOf(position);
}
} else {
switch (position) {
case 0:
return getResources().getString(R.string.status_fragment_title);
default:
return String.valueOf(position);
}
}
}
};
mViewPager.setAdapter(mSectionsPagerAdapter);
TabLayout tabLayout = findViewById(R.id.tabContainer);
tabLayout.setupWithViewPager(mViewPager);
}
@Override
public void onResume() {
// Check if storage permission has been revoked at runtime.
@ -286,6 +337,8 @@ public class MainActivity extends StateDialogActivity
mSyncthingService.unregisterOnServiceStateChangeListener(this);
mSyncthingService.unregisterOnServiceStateChangeListener(mFolderListFragment);
mSyncthingService.unregisterOnServiceStateChangeListener(mDeviceListFragment);
mSyncthingService.unregisterOnServiceStateChangeListener(mDrawerFragment);
mSyncthingService.unregisterOnServiceStateChangeListener(mStatusFragment);
}
}
@ -297,6 +350,8 @@ public class MainActivity extends StateDialogActivity
syncthingService.registerOnServiceStateChangeListener(this);
syncthingService.registerOnServiceStateChangeListener(mFolderListFragment);
syncthingService.registerOnServiceStateChangeListener(mDeviceListFragment);
syncthingService.registerOnServiceStateChangeListener(mDrawerFragment);
syncthingService.registerOnServiceStateChangeListener(mStatusFragment);
}
/**
@ -314,6 +369,7 @@ public class MainActivity extends StateDialogActivity
};
putFragment.accept(mFolderListFragment);
putFragment.accept(mDeviceListFragment);
putFragment.accept(mStatusFragment);
putFragment.accept(mDrawerFragment);
outState.putInt("currentTab", mViewPager.getCurrentItem());
@ -402,18 +458,6 @@ public class MainActivity extends StateDialogActivity
super(activity, drawerLayout, R.string.app_name, R.string.app_name);
}
@Override
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
mDrawerFragment.onDrawerOpened();
}
@Override
public void onDrawerClosed(View view) {
super.onDrawerClosed(view);
mDrawerFragment.onDrawerClosed();
}
@Override
public void onDrawerSlide(View drawerView, float slideOffset) {
super.onDrawerSlide(drawerView, 0);

View file

@ -40,20 +40,12 @@ public abstract class StateDialogActivity extends SyncthingActivity {
protected void onResume() {
super.onResume();
mIsPaused = false;
switch (mServiceState) {
case DISABLED:
showDisabledDialog();
break;
default:
break;
}
}
@Override
protected void onPause() {
super.onPause();
mIsPaused = true;
dismissDisabledDialog();
dismissLoadingDialog();
}
@ -63,7 +55,6 @@ public abstract class StateDialogActivity extends SyncthingActivity {
if (getService() != null) {
getService().unregisterOnServiceStateChangeListener(this::onServiceStateChange);
}
dismissDisabledDialog();
}
private void onServiceStateChange(SyncthingService.State currentState) {
@ -71,50 +62,18 @@ public abstract class StateDialogActivity extends SyncthingActivity {
switch (mServiceState) {
case INIT: // fallthrough
case STARTING:
dismissDisabledDialog();
showLoadingDialog();
break;
case ACTIVE:
dismissDisabledDialog();
dismissLoadingDialog();
break;
case DISABLED:
if (!mIsPaused) {
showDisabledDialog();
}
break;
case DISABLED: // fallthrough
case ERROR: // fallthrough
default:
break;
}
}
private void showDisabledDialog() {
if (this.isFinishing() && (mDisabledDialog != null)) {
return;
}
mDisabledDialog = new AlertDialog.Builder(this)
.setTitle(R.string.syncthing_disabled_title)
.setMessage(R.string.syncthing_disabled_message)
.setPositiveButton(R.string.syncthing_disabled_change_settings,
(dialogInterface, i) -> {
Intent intent = new Intent(this, SettingsActivity.class);
intent.putExtra(SettingsActivity.EXTRA_OPEN_SUB_PREF_SCREEN, "category_run_conditions");
startActivity(intent);
}
)
.setNegativeButton(R.string.exit,
(dialogInterface, i) -> ActivityCompat.finishAffinity(this)
)
.setCancelable(false)
.show();
}
private void dismissDisabledDialog() {
Util.dismissDialogSafe(mDisabledDialog, this);
mDisabledDialog = null;
}
/**
* Shows the loading dialog with the correct text ("creating keys" or "loading").
*/

View file

@ -92,7 +92,7 @@ public abstract class SyncthingActivity extends AppCompatActivity implements Ser
/**
* Returns service object (or null if not bound).
*/
SyncthingService getService() {
public SyncthingService getService() {
return mSyncthingService;
}

View file

@ -13,75 +13,54 @@ import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableMap;
import com.nutomic.syncthingandroid.R;
import com.nutomic.syncthingandroid.activities.MainActivity;
import com.nutomic.syncthingandroid.activities.SettingsActivity;
import com.nutomic.syncthingandroid.activities.WebGuiActivity;
import com.nutomic.syncthingandroid.http.ImageGetRequest;
import com.nutomic.syncthingandroid.model.Connections;
import com.nutomic.syncthingandroid.model.SystemInfo;
import com.nutomic.syncthingandroid.model.SystemVersion;
import com.nutomic.syncthingandroid.service.Constants;
import com.nutomic.syncthingandroid.service.RestApi;
import com.nutomic.syncthingandroid.service.SyncthingService;
import com.nutomic.syncthingandroid.util.Util;
import java.net.URL;
import java.text.NumberFormat;
import java.util.Locale;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
/**
* Displays information about the local device.
*/
public class DrawerFragment extends Fragment implements View.OnClickListener {
public class DrawerFragment extends Fragment implements SyncthingService.OnServiceStateChangeListener,
View.OnClickListener {
private SyncthingService.State mServiceState = SyncthingService.State.INIT;
private static final String TAG = "DrawerFragment";
private TextView mCpuUsage;
private TextView mRamUsage;
private TextView mDownload;
private TextView mUpload;
private TextView mAnnounceServer;
private TextView mVersion;
private TextView mDrawerActionShowQrCode;
private TextView mDrawerActionWebGui;
private TextView mDrawerActionRestart;
private TextView mDrawerActionSettings;
private TextView mExitButton;
private Timer mTimer;
private MainActivity mActivity;
private SharedPreferences sharedPreferences;
public void onDrawerOpened() {
mTimer = new Timer();
mTimer.schedule(new TimerTask() {
@Override
public void run() {
updateGui();
}
}, 0, Constants.GUI_UPDATE_INTERVAL);
@Override
public void onServiceStateChange(SyncthingService.State currentState) {
mServiceState = currentState;
updateButtons();
}
@Override
public void onResume() {
super.onResume();
updateExitButtonVisibility();
}
public void onDrawerClosed() {
if (mTimer != null) {
mTimer.cancel();
mTimer = null;
}
updateButtons();
}
@Override
public void onDestroy() {
super.onDestroy();
onDrawerClosed();
}
/**
@ -94,121 +73,57 @@ public class DrawerFragment extends Fragment implements View.OnClickListener {
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
mCpuUsage = view.findViewById(R.id.cpu_usage);
mRamUsage = view.findViewById(R.id.ram_usage);
mDownload = view.findViewById(R.id.download);
mUpload = view.findViewById(R.id.upload);
mAnnounceServer = view.findViewById(R.id.announce_server);
mVersion = view.findViewById(R.id.version);
mExitButton = view.findViewById(R.id.drawerActionExit);
mActivity = (MainActivity) getActivity();
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(mActivity);
view.findViewById(R.id.drawerActionWebGui)
.setOnClickListener(this);
view.findViewById(R.id.drawerActionRestart)
.setOnClickListener(this);
view.findViewById(R.id.drawerActionSettings)
.setOnClickListener(this);
view.findViewById(R.id.drawerActionShowQrCode)
.setOnClickListener(this);
mVersion = view.findViewById(R.id.version);
mDrawerActionShowQrCode = view.findViewById(R.id.drawerActionShowQrCode);
mDrawerActionWebGui = view.findViewById(R.id.drawerActionWebGui);
mDrawerActionRestart = view.findViewById(R.id.drawerActionRestart);
mDrawerActionSettings = view.findViewById(R.id.drawerActionSettings);
mExitButton = view.findViewById(R.id.drawerActionExit);
// Show static content.
mVersion.setText(sharedPreferences.getString(Constants.PREF_LAST_BINARY_VERSION, ""));
// Add listeners to buttons.
mDrawerActionShowQrCode.setOnClickListener(this);
mDrawerActionWebGui.setOnClickListener(this);
mDrawerActionRestart.setOnClickListener(this);
mDrawerActionSettings.setOnClickListener(this);
mExitButton.setOnClickListener(this);
updateExitButtonVisibility();
}
private void updateExitButtonVisibility() {
boolean alwaysInBackground = alwaysRunInBackground();
mExitButton.setVisibility(alwaysInBackground ? View.GONE : View.VISIBLE);
updateButtons();
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mActivity = (MainActivity) getActivity();
if (savedInstanceState != null && savedInstanceState.getBoolean("active")) {
onDrawerOpened();
}
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean("active", mTimer != null);
}
/**
* Invokes status callbacks.
* Update action button availability.
*/
private void updateGui() {
MainActivity mainActivity = (MainActivity) getActivity();
if (mainActivity == null) {
return;
}
if (mainActivity.isFinishing()) {
return;
}
private void updateButtons() {
Boolean synthingRunning = mServiceState == SyncthingService.State.ACTIVE;
RestApi mApi = mainActivity.getApi();
if (mApi != null) {
mApi.getSystemInfo(this::onReceiveSystemInfo);
mApi.getSystemVersion(this::onReceiveSystemVersion);
mApi.getConnections(this::onReceiveConnections);
}
}
// Show buttons if syncthing is running.
mVersion.setVisibility(synthingRunning ? View.VISIBLE : View.GONE);
mDrawerActionShowQrCode.setVisibility(synthingRunning ? View.VISIBLE : View.GONE);
mDrawerActionWebGui.setVisibility(synthingRunning ? View.VISIBLE : View.GONE);
mDrawerActionRestart.setVisibility(synthingRunning ? View.VISIBLE : View.GONE);
/**
* This will not do anything if gui updates are already scheduled.
*/
public void requestGuiUpdate() {
if (mTimer == null) {
updateGui();
}
}
/**
* Populates views with status received via {@link RestApi#getSystemInfo}.
*/
private void onReceiveSystemInfo(SystemInfo info) {
if (getActivity() == null)
return;
NumberFormat percentFormat = NumberFormat.getPercentInstance();
percentFormat.setMaximumFractionDigits(2);
mCpuUsage.setText(percentFormat.format(info.cpuPercent / 100));
mRamUsage.setText(Util.readableFileSize(mActivity, info.sys));
int announceTotal = info.discoveryMethods;
int announceConnected =
announceTotal - Optional.fromNullable(info.discoveryErrors).transform(Map::size).or(0);
mAnnounceServer.setText(String.format(Locale.getDefault(), "%1$d/%2$d",
announceConnected, announceTotal));
int color = (announceConnected > 0)
? R.color.text_green
: R.color.text_red;
mAnnounceServer.setTextColor(ContextCompat.getColor(getContext(), color));
}
/**
* Populates views with status received via {@link RestApi#getSystemInfo}.
*/
private void onReceiveSystemVersion(SystemVersion info) {
if (getActivity() == null)
return;
mVersion.setText(info.version);
}
/**
* Populates views with status received via {@link RestApi#getConnections}.
*/
private void onReceiveConnections(Connections connections) {
Connections.Connection c = connections.total;
mDownload.setText(Util.readableTransferRate(mActivity, c.inBits));
mUpload.setText(Util.readableTransferRate(mActivity, c.outBits));
// Do not show the exit button if our app runs as a background service.
mExitButton.setVisibility(
sharedPreferences.getBoolean(Constants.PREF_ALWAYS_RUN_IN_BACKGROUND, false) ?
View.GONE :
View.VISIBLE
);
}
/**
* Gets QRCode and displays it in a Dialog.
*/
private void showQrCode() {
RestApi restApi = mActivity.getApi();
if (restApi == null) {
@ -255,9 +170,4 @@ public class DrawerFragment extends Fragment implements View.OnClickListener {
break;
}
}
private boolean alwaysRunInBackground() {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getActivity());
return sp.getBoolean(Constants.PREF_ALWAYS_RUN_IN_BACKGROUND, false);
}
}

View file

@ -0,0 +1,260 @@
package com.nutomic.syncthingandroid.fragments;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.ListFragment;
import android.text.TextUtils;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import com.google.common.base.Optional;
import com.nutomic.syncthingandroid.R;
import com.nutomic.syncthingandroid.activities.MainActivity;
import com.nutomic.syncthingandroid.activities.SettingsActivity;
import com.nutomic.syncthingandroid.activities.SyncthingActivity;
import com.nutomic.syncthingandroid.model.Connections;
import com.nutomic.syncthingandroid.model.SystemInfo;
import com.nutomic.syncthingandroid.model.SystemVersion;
import com.nutomic.syncthingandroid.service.Constants;
import com.nutomic.syncthingandroid.service.RestApi;
import com.nutomic.syncthingandroid.service.SyncthingService;
import com.nutomic.syncthingandroid.util.Util;
import java.util.ArrayList;
import java.util.Locale;
import java.util.Map;
import java.text.NumberFormat;
/**
* Displays why syncthing is running or disabled.
*/
public class StatusFragment extends ListFragment implements SyncthingService.OnServiceStateChangeListener {
private static final String TAG = "StatusFragment";
private Runnable mRestApiQueryRunnable = new Runnable() {
@Override
public void run() {
onTimerEvent();
mRestApiQueryHandler.postDelayed(this, Constants.GUI_UPDATE_INTERVAL);
}
};
private MainActivity mActivity;
private ArrayAdapter mAdapter;
private SyncthingService.State mServiceState = SyncthingService.State.INIT;
private final Handler mRestApiQueryHandler = new Handler();
private Boolean mLastVisibleToUser = false;
/**
* Object that must be locked upon accessing the status holders.
*/
private final Object mStatusHolderLock = new Object();
/**
* Status holders, filled on callbacks.
*/
private String mCpuUsage = "";
private String mRamUsage = "";
private String mDownload = "";
private String mUpload = "";
private String mAnnounceServer = "";
@Override
public void setUserVisibleHint(boolean isVisibleToUser)
{
super.setUserVisibleHint(isVisibleToUser);
if (isVisibleToUser && !mLastVisibleToUser) {
// User switched to the current tab, start handler.
mRestApiQueryHandler.post(mRestApiQueryRunnable);
} else if (!isVisibleToUser && mLastVisibleToUser) {
// User switched away to another tab, stop handler.
mRestApiQueryHandler.removeCallbacks(mRestApiQueryRunnable);
}
mLastVisibleToUser = isVisibleToUser;
}
@Override
public void onPause() {
mRestApiQueryHandler.removeCallbacks(mRestApiQueryRunnable);
super.onPause();
}
@Override
public void onServiceStateChange(SyncthingService.State currentState) {
mServiceState = currentState;
updateStatus();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_status, container, false);
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mAdapter = new ArrayAdapter(getActivity(), android.R.layout.simple_list_item_1);
setListAdapter(mAdapter);
setHasOptionsMenu(true);
updateStatus();
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mActivity = (MainActivity) getActivity();
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.status_list, menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.open_preferences:
startActivity(new Intent(getContext(), SettingsActivity.class));
return true;
default:
return super.onOptionsItemSelected(item);
}
}
private void updateStatus() {
SyncthingActivity syncthingActivity = (SyncthingActivity) getActivity();
if (syncthingActivity == null || getView() == null || syncthingActivity.isFinishing()) {
return;
}
SyncthingService syncthingService = syncthingActivity.getService();
if (syncthingService == null) {
return;
}
// Add status line showing the syncthing service state.
ArrayList<String> statusItems = new ArrayList<String>();
switch (mServiceState) {
case INIT:
case STARTING:
statusItems.add(getString(R.string.syncthing_starting));
break;
case ACTIVE:
statusItems.add(getString(R.string.syncthing_running));
break;
case DISABLED:
statusItems.add(getString(R.string.syncthing_not_running));
break;
case ERROR:
statusItems.add(getString(R.string.syncthing_has_crashed));
break;
}
// Add explanation why syncthing is (not) running.
switch (mServiceState) {
case ACTIVE:
case DISABLED:
statusItems.add(getString(R.string.reason) + "\n" +
"- " + syncthingService.getRunDecisionExplanation().trim().replace("\n", "\n- "));
default:
break;
}
// Add status holders refreshed by callbacks to the list.
if (mServiceState == SyncthingService.State.ACTIVE) {
synchronized (mStatusHolderLock) {
if (!TextUtils.isEmpty(mCpuUsage)) {
statusItems.add(getString(R.string.cpu_usage) + ": " + mCpuUsage);
}
if (!TextUtils.isEmpty(mRamUsage)) {
statusItems.add(getString(R.string.ram_usage) + ": " + mRamUsage);
}
if (!TextUtils.isEmpty(mDownload)) {
statusItems.add(getString(R.string.download_title) + ": " + mDownload);
}
if (!TextUtils.isEmpty(mUpload)) {
statusItems.add(getString(R.string.upload_title) + ": " + mUpload);
}
if (!TextUtils.isEmpty(mAnnounceServer)) {
statusItems.add(getString(R.string.announce_server) + ": " + mAnnounceServer);
}
}
}
// Update list contents.
mAdapter.setNotifyOnChange(false);
mAdapter.clear();
mAdapter.addAll(statusItems);
mAdapter.notifyDataSetChanged();
}
/**
* Invokes status callbacks via syncthing's REST API
* while the user is looking at the current tab.
*/
private void onTimerEvent() {
if (mServiceState != SyncthingService.State.ACTIVE) {
return;
}
MainActivity mainActivity = (MainActivity) getActivity();
if (mainActivity == null) {
return;
}
if (mainActivity.isFinishing()) {
return;
}
RestApi restApi = mainActivity.getApi();
if (restApi == null) {
return;
}
Log.v(TAG, "Invoking REST status queries");
restApi.getSystemInfo(this::onReceiveSystemInfo);
restApi.getConnections(this::onReceiveConnections);
}
/**
* Populates status holders with status received via {@link RestApi#getSystemInfo}.
*/
private void onReceiveSystemInfo(SystemInfo info) {
if (getActivity() == null) {
return;
}
NumberFormat percentFormat = NumberFormat.getPercentInstance();
percentFormat.setMaximumFractionDigits(2);
int announceTotal = info.discoveryMethods;
int announceConnected =
announceTotal - Optional.fromNullable(info.discoveryErrors).transform(Map::size).or(0);
synchronized (mStatusHolderLock) {
mCpuUsage = percentFormat.format(info.cpuPercent / 100);
mRamUsage = Util.readableFileSize(mActivity, info.sys);
mAnnounceServer = String.format(Locale.getDefault(), "%1$d/%2$d", announceConnected, announceTotal);
}
updateStatus();
}
/**
* Populates status holders with status received via {@link RestApi#getConnections}.
*/
private void onReceiveConnections(Connections connections) {
if (getActivity() == null) {
return;
}
Connections.Connection c = connections.total;
synchronized (mStatusHolderLock) {
mDownload = Util.readableTransferRate(mActivity, c.inBits);
mUpload = Util.readableTransferRate(mActivity, c.outBits);
}
updateStatus();
}
}

View file

@ -9,6 +9,7 @@ import java.util.concurrent.TimeUnit;
public class Constants {
public static final String FILENAME_SYNCTHING_BINARY = "libsyncthing.so";
public static final String PREF_LAST_BINARY_VERSION = "lastBinaryVersion";
// Preferences - Run conditions
public static final String PREF_ALWAYS_RUN_IN_BACKGROUND = "always_run_in_background";

View file

@ -225,8 +225,7 @@ public class RestApi {
* Precondition: {@link #mVersion} read from REST
*/
private void updateDebugFacilitiesCache() {
final String PREF_LAST_BINARY_VERSION = "lastBinaryVersion";
if (!mVersion.equals(PreferenceManager.getDefaultSharedPreferences(mContext).getString(PREF_LAST_BINARY_VERSION, ""))) {
if (!mVersion.equals(PreferenceManager.getDefaultSharedPreferences(mContext).getString(Constants.PREF_LAST_BINARY_VERSION, ""))) {
// First binary launch or binary upgraded case.
new GetRequest(mContext, mUrl, GetRequest.URI_DEBUG, mApiKey, null, result -> {
try {
@ -243,7 +242,7 @@ public class RestApi {
// Store current binary version so we will only store this information again
// after a binary update.
PreferenceManager.getDefaultSharedPreferences(mContext).edit()
.putString(PREF_LAST_BINARY_VERSION, mVersion)
.putString(Constants.PREF_LAST_BINARY_VERSION, mVersion)
.apply();
} catch (Exception e) {
Log.w(TAG, "updateDebugFacilitiesCache: Failed to get debug facilities. result=" + result);

View file

@ -8,6 +8,7 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.SyncStatusObserver;
import android.content.res.Resources;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.wifi.WifiInfo;
@ -20,6 +21,7 @@ import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;
import com.google.common.collect.Lists;
import com.nutomic.syncthingandroid.R;
import com.nutomic.syncthingandroid.SyncthingApp;
import com.nutomic.syncthingandroid.service.ReceiverManager;
@ -58,6 +60,7 @@ public class RunConditionMonitor {
private final Context mContext;
@Inject SharedPreferences mPreferences;
private ReceiverManager mReceiverManager;
private String mRunDecisionExplanation = "";
/**
* Sending callback notifications through {@link OnDeviceStateChangedListener} is enabled if not null.
@ -151,10 +154,18 @@ public class RunConditionMonitor {
}
}
public String getRunDecisionExplanation() {
return mRunDecisionExplanation;
}
/**
* Determines if Syncthing should currently run.
* Updates mRunDecisionExplanation.
*/
private boolean decideShouldRun() {
Resources res = mContext.getResources();
mRunDecisionExplanation = "";
// Get run conditions preferences.
boolean prefRunOnMobileData= mPreferences.getBoolean(Constants.PREF_RUN_ON_MOBILE_DATA, false);
boolean prefRunOnWifi= mPreferences.getBoolean(Constants.PREF_RUN_ON_WIFI, true);
@ -171,12 +182,14 @@ public class RunConditionMonitor {
case POWER_SOURCE_AC:
if (!isOnAcPower()) {
Log.v(TAG, "decideShouldRun: POWER_SOURCE_AC && !isOnAcPower");
mRunDecisionExplanation = res.getString(R.string.reason_not_on_ac_power);
return false;
}
break;
case POWER_SOURCE_BATTERY:
if (isOnAcPower()) {
Log.v(TAG, "decideShouldRun: POWER_SOURCE_BATTERY && isOnAcPower");
mRunDecisionExplanation = res.getString(R.string.reason_not_on_battery_power);
return false;
}
break;
@ -189,6 +202,7 @@ public class RunConditionMonitor {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (prefRespectPowerSaving && isPowerSaving()) {
Log.v(TAG, "decideShouldRun: prefRespectPowerSaving && isPowerSaving");
mRunDecisionExplanation = res.getString(R.string.reason_not_while_power_saving);
return false;
}
}
@ -196,35 +210,65 @@ public class RunConditionMonitor {
// Android global AutoSync setting.
if (prefRespectMasterSync && !ContentResolver.getMasterSyncAutomatically()) {
Log.v(TAG, "decideShouldRun: prefRespectMasterSync && !getMasterSyncAutomatically");
mRunDecisionExplanation = res.getString(R.string.reason_not_while_auto_sync_data_disabled);
return false;
}
// Run on mobile data.
if (prefRunOnMobileData && isMobileDataConnection()) {
Log.v(TAG, "decideShouldRun: prefRunOnMobileData && isMobileDataConnection");
return true;
if (prefRunOnMobileData) {
if (isMobileDataConnection()) {
Log.v(TAG, "decideShouldRun: prefRunOnMobileData && isMobileDataConnection");
mRunDecisionExplanation = res.getString(R.string.reason_on_mobile_data);
return true;
}
mRunDecisionExplanation = res.getString(R.string.reason_not_on_mobile_data);
}
// Run on wifi.
if (prefRunOnWifi && isWifiOrEthernetConnection()) {
if (prefRunOnMeteredWifi) {
// We are on non-metered or metered wifi. Check if wifi whitelist run condition is met.
if (wifiWhitelistConditionMet(prefWifiWhitelistEnabled, whitelistedWifiSsids)) {
Log.v(TAG, "decideShouldRun: prefRunOnWifi && isWifiOrEthernetConnection && prefRunOnMeteredWifi && wifiWhitelistConditionMet");
return true;
if (prefRunOnWifi) {
if (isWifiOrEthernetConnection()) {
mRunDecisionExplanation += "\n" + res.getString(R.string.reason_on_wifi);
if (prefRunOnMeteredWifi) {
mRunDecisionExplanation += "\n" + res.getString(R.string.reason_on_metered_nonmetered_wifi);
// We are on non-metered or metered wifi. Check if wifi whitelist run condition is met.
if (wifiWhitelistConditionMet(prefWifiWhitelistEnabled, whitelistedWifiSsids)) {
Log.v(TAG, "decideShouldRun: prefRunOnWifi && isWifiOrEthernetConnection && prefRunOnMeteredWifi && wifiWhitelistConditionMet");
mRunDecisionExplanation += "\n" + res.getString(R.string.reason_on_whitelisted_wifi);
return true;
}
mRunDecisionExplanation += "\n" + res.getString(R.string.reason_not_on_whitelisted_wifi);
} else {
// Check if we are on a non-metered wifi.
if (!isMeteredNetworkConnection()) {
mRunDecisionExplanation += "\n" + res.getString(R.string.reason_on_nonmetered_wifi);
// Check if wifi whitelist run condition is met.
if (wifiWhitelistConditionMet(prefWifiWhitelistEnabled, whitelistedWifiSsids)) {
Log.v(TAG, "decideShouldRun: prefRunOnWifi && isWifiOrEthernetConnection && !prefRunOnMeteredWifi && !isMeteredNetworkConnection && wifiWhitelistConditionMet");
mRunDecisionExplanation += "\n" + res.getString(R.string.reason_on_whitelisted_wifi);
return true;
}
mRunDecisionExplanation += "\n" + res.getString(R.string.reason_not_on_whitelisted_wifi);
} else {
mRunDecisionExplanation += "\n" + res.getString(R.string.reason_not_nonmetered_wifi);
}
}
} else {
// Check if we are on a non-metered wifi and if wifi whitelist run condition is met.
if (!isMeteredNetworkConnection() && wifiWhitelistConditionMet(prefWifiWhitelistEnabled, whitelistedWifiSsids)) {
Log.v(TAG, "decideShouldRun: prefRunOnWifi && isWifiOrEthernetConnection && !prefRunOnMeteredWifi && !isMeteredNetworkConnection && wifiWhitelistConditionMet");
return true;
}
mRunDecisionExplanation += "\n" + res.getString(R.string.reason_not_on_wifi);
/**
* if (prefRunOnWifi && !isWifiOrEthernetConnection()) { return false; }
* This is intentionally not returning "false" as the flight mode workaround
* relevant for some phone models needs to be done by the code below.
* ConnectivityManager.getActiveNetworkInfo() returns "null" on those phones which
* results in assuming !isWifiOrEthernetConnection even if the phone is connected
* to wifi during flight mode, see {@link isWifiOrEthernetConnection}.
*/
}
}
// Run in flight mode.
if (prefRunInFlightMode && isFlightMode()) {
Log.v(TAG, "decideShouldRun: prefRunInFlightMode && isFlightMode");
mRunDecisionExplanation += "\n" + res.getString(R.string.reason_on_flight_mode);
return true;
}

View file

@ -587,6 +587,13 @@ public class SyncthingService extends Service {
return mNotificationHandler;
}
public String getRunDecisionExplanation() {
if (mRunConditionMonitor == null) {
return "This should not happen: mRunConditionMonitor is not instantiated.";
}
return mRunConditionMonitor.getRunDecisionExplanation();
}
/**
* Exports the local config and keys to {@link Constants#EXPORT_PATH}.
*/

Binary file not shown.

After

Width:  |  Height:  |  Size: 743 B

View file

@ -61,123 +61,6 @@
android:layout_marginBottom="4dp"
android:background="@drawable/list_divider" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:minHeight="48dp"
android:orientation="vertical"
android:paddingLeft="@dimen/abc_action_bar_content_inset_material"
android:paddingRight="@dimen/abc_action_bar_content_inset_material">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/cpu_usage"
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
android:textColor="?android:textColorSecondary" />
<TextView
android:id="@+id/cpu_usage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearance.AppCompat.Caption" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:minHeight="48dp"
android:orientation="vertical"
android:paddingLeft="@dimen/abc_action_bar_content_inset_material"
android:paddingRight="@dimen/abc_action_bar_content_inset_material">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/ram_usage"
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
android:textColor="?android:textColorSecondary" />
<TextView
android:id="@+id/ram_usage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearance.AppCompat.Caption" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:minHeight="48dp"
android:orientation="vertical"
android:paddingLeft="@dimen/abc_action_bar_content_inset_material"
android:paddingRight="@dimen/abc_action_bar_content_inset_material">
<TextView
android:id="@+id/download_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/download_title"
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
android:textColor="?android:textColorSecondary" />
<TextView
android:id="@+id/download"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearance.AppCompat.Caption" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:minHeight="48dp"
android:orientation="vertical"
android:paddingLeft="@dimen/abc_action_bar_content_inset_material"
android:paddingRight="@dimen/abc_action_bar_content_inset_material">
<TextView
android:id="@+id/upload_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/upload_title"
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
android:textColor="?android:textColorSecondary" />
<TextView
android:id="@+id/upload"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearance.AppCompat.Caption" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:minHeight="48dp"
android:orientation="vertical"
android:paddingLeft="@dimen/abc_action_bar_content_inset_material"
android:paddingRight="@dimen/abc_action_bar_content_inset_material">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/announce_server"
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
android:textColor="?android:textColorSecondary" />
<TextView
android:id="@+id/announce_server"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearance.AppCompat.Caption" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<ListView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="match_parent">
</ListView>

View file

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/open_preferences"
android:icon="@drawable/ic_settings_white_24dp"
android:title="@string/settings_title"
app:showAsAction="always|withText" />
</menu>

View file

@ -135,8 +135,6 @@
<!--Sub Folder title-->
<!--SyncthingService-->
<!--Title of the "syncthing disabled" dialog-->
<!--Message of the "syncthing disabled" dialog-->
<!--Button text on the "syncthing disabled" dialog-->
<!--Button text on the "syncthing disabled" dialog, used as menu item to stop syncthing service if "always_run_in_background" is true-->
<!--Title of the notification shown while syncthing is running and enabled-->
<!--Toast shown if syncthing failed to create a config-->

View file

@ -259,7 +259,6 @@
<string name="syncthing_disabled_title">Syncthing не работи</string>
<!--Message of the "syncthing disabled" dialog-->
<!--Button text on the "syncthing disabled" dialog-->
<string name="syncthing_disabled_change_settings">Промяна на настройките</string>
<!--Button text on the "syncthing disabled" dialog, used as menu item to stop syncthing service if "always_run_in_background" is true-->
<string name="exit">Изход</string>
<!--Title of the notification shown while syncthing is running and enabled-->

View file

@ -347,7 +347,6 @@ Ens podeu informar dels problemes que trobeu a través de Github.</string>
<string name="syncthing_disabled_title">El Syncthing està desactivat</string>
<!--Message of the "syncthing disabled" dialog-->
<!--Button text on the "syncthing disabled" dialog-->
<string name="syncthing_disabled_change_settings">Canvia la configuració</string>
<!--Button text on the "syncthing disabled" dialog, used as menu item to stop syncthing service if "always_run_in_background" is true-->
<string name="exit">Surt</string>
<!--Title of the notification shown while syncthing is running and enabled-->

View file

@ -326,7 +326,6 @@ Všechny zaznamenané chyby prosím hlašte přes Github.</string>
<string name="syncthing_disabled_title">Syncthing je vypnutý</string>
<!--Message of the "syncthing disabled" dialog-->
<!--Button text on the "syncthing disabled" dialog-->
<string name="syncthing_disabled_change_settings">Změnit nastavení</string>
<!--Button text on the "syncthing disabled" dialog, used as menu item to stop syncthing service if "always_run_in_background" is true-->
<string name="exit">Ukončit</string>
<!--Title of the notification shown while syncthing is running and enabled-->

View file

@ -313,7 +313,6 @@ Vær venlig at rapportere ethvert problem, du støder på, via Github. </string>
<string name="syncthing_disabled_title">Syncthing er slået fra</string>
<!--Message of the "syncthing disabled" dialog-->
<!--Button text on the "syncthing disabled" dialog-->
<string name="syncthing_disabled_change_settings">Ændre Indstillinger</string>
<!--Button text on the "syncthing disabled" dialog, used as menu item to stop syncthing service if "always_run_in_background" is true-->
<string name="exit">Afslut</string>
<!--Title of the notification shown while syncthing is running and enabled-->

View file

@ -362,7 +362,6 @@ Bitte melden Sie auftretende Probleme via GitHub.</string>
<string name="syncthing_disabled_title">Syncthing ist deaktiviert</string>
<!--Message of the "syncthing disabled" dialog-->
<!--Button text on the "syncthing disabled" dialog-->
<string name="syncthing_disabled_change_settings">Einstellungen ändern</string>
<!--Button text on the "syncthing disabled" dialog, used as menu item to stop syncthing service if "always_run_in_background" is true-->
<string name="exit">Beenden</string>
<!--Title of the notification shown while syncthing is running and enabled-->

View file

@ -317,7 +317,6 @@
<string name="syncthing_disabled_title">Το Syncthing είναι απενεργοποιημένο</string>
<!--Message of the "syncthing disabled" dialog-->
<!--Button text on the "syncthing disabled" dialog-->
<string name="syncthing_disabled_change_settings">Αλλαγή ρυθμίσεως</string>
<!--Button text on the "syncthing disabled" dialog, used as menu item to stop syncthing service if "always_run_in_background" is true-->
<string name="exit">Έξοδος</string>
<!--Title of the notification shown while syncthing is running and enabled-->

View file

@ -121,8 +121,6 @@
<!--Sub Folder title-->
<!--SyncthingService-->
<!--Title of the "syncthing disabled" dialog-->
<!--Message of the "syncthing disabled" dialog-->
<!--Button text on the "syncthing disabled" dialog-->
<!--Button text on the "syncthing disabled" dialog, used as menu item to stop syncthing service if "always_run_in_background" is true-->
<!--Title of the notification shown while syncthing is running and enabled-->
<!--Toast shown if syncthing failed to create a config-->

View file

@ -240,7 +240,6 @@
<string name="syncthing_disabled_title">Syncthing está deshabilitado</string>
<!--Message of the "syncthing disabled" dialog-->
<!--Button text on the "syncthing disabled" dialog-->
<string name="syncthing_disabled_change_settings">Cambiar ajustes</string>
<!--Button text on the "syncthing disabled" dialog, used as menu item to stop syncthing service if "always_run_in_background" is true-->
<string name="exit">Salir</string>
<!--Title of the notification shown while syncthing is running and enabled-->

View file

@ -291,7 +291,6 @@
<string name="syncthing_disabled_title">Syncthing está deshabilitado</string>
<!--Message of the "syncthing disabled" dialog-->
<!--Button text on the "syncthing disabled" dialog-->
<string name="syncthing_disabled_change_settings">Cambiar la configuración</string>
<!--Button text on the "syncthing disabled" dialog, used as menu item to stop syncthing service if "always_run_in_background" is true-->
<string name="exit">Salir</string>
<!--Title of the notification shown while syncthing is running and enabled-->

View file

@ -288,7 +288,6 @@ Ilmoitathan ystävällisesti kaikista havaitsemistasi ongelmista Githubin kautta
<string name="syncthing_disabled_title">Syncthing on poistettu käytöstä</string>
<!--Message of the "syncthing disabled" dialog-->
<!--Button text on the "syncthing disabled" dialog-->
<string name="syncthing_disabled_change_settings">Muuta asetuksia</string>
<!--Button text on the "syncthing disabled" dialog, used as menu item to stop syncthing service if "always_run_in_background" is true-->
<string name="exit">Poistu</string>
<!--Title of the notification shown while syncthing is running and enabled-->

View file

@ -348,7 +348,6 @@ S\'il vous plaît, soumettez les problèmes que vous rencontrez via Github.</str
<string name="syncthing_disabled_title">Syncthing est désactivé</string>
<!--Message of the "syncthing disabled" dialog-->
<!--Button text on the "syncthing disabled" dialog-->
<string name="syncthing_disabled_change_settings">Modification des paramètres</string>
<!--Button text on the "syncthing disabled" dialog, used as menu item to stop syncthing service if "always_run_in_background" is true-->
<string name="exit">Quitter</string>
<!--Title of the notification shown while syncthing is running and enabled-->

View file

@ -351,7 +351,6 @@ VIGYÁZAT! Más alkalmazások kiolvashatják a backupból a titkos kulcsot, és
<string name="syncthing_disabled_title">A Syncthing le van tiltva</string>
<!--Message of the "syncthing disabled" dialog-->
<!--Button text on the "syncthing disabled" dialog-->
<string name="syncthing_disabled_change_settings">Beállítások megváltoztatása</string>
<!--Button text on the "syncthing disabled" dialog, used as menu item to stop syncthing service if "always_run_in_background" is true-->
<string name="exit">Kilépés</string>
<!--Title of the notification shown while syncthing is running and enabled-->

View file

@ -298,7 +298,6 @@ Jika ada masalah silakan laporkan lewat Github.</string>
<string name="syncthing_disabled_title">Syncthing dimatikan</string>
<!--Message of the "syncthing disabled" dialog-->
<!--Button text on the "syncthing disabled" dialog-->
<string name="syncthing_disabled_change_settings">Ubah Pengaturan</string>
<!--Button text on the "syncthing disabled" dialog, used as menu item to stop syncthing service if "always_run_in_background" is true-->
<string name="exit">Keluar</string>
<!--Title of the notification shown while syncthing is running and enabled-->

View file

@ -348,7 +348,6 @@ Si prega di segnalare eventuali problemi che si incontrano via Github.</string>
<string name="syncthing_disabled_title">Syncthing è disabilitato</string>
<!--Message of the "syncthing disabled" dialog-->
<!--Button text on the "syncthing disabled" dialog-->
<string name="syncthing_disabled_change_settings">Cambia Impostazioni</string>
<!--Button text on the "syncthing disabled" dialog, used as menu item to stop syncthing service if "always_run_in_background" is true-->
<string name="exit">Esci</string>
<!--Title of the notification shown while syncthing is running and enabled-->

View file

@ -314,7 +314,6 @@
<string name="syncthing_disabled_title">Syncthing は無効になりました</string>
<!--Message of the "syncthing disabled" dialog-->
<!--Button text on the "syncthing disabled" dialog-->
<string name="syncthing_disabled_change_settings">設定を変更</string>
<!--Button text on the "syncthing disabled" dialog, used as menu item to stop syncthing service if "always_run_in_background" is true-->
<string name="exit">終了</string>
<!--Title of the notification shown while syncthing is running and enabled-->

View file

@ -313,7 +313,6 @@
<string name="syncthing_disabled_title">Syncthing이 비활성화되었습니다</string>
<!--Message of the "syncthing disabled" dialog-->
<!--Button text on the "syncthing disabled" dialog-->
<string name="syncthing_disabled_change_settings">설정 변경</string>
<!--Button text on the "syncthing disabled" dialog, used as menu item to stop syncthing service if "always_run_in_background" is true-->
<string name="exit">나가기</string>
<!--Title of the notification shown while syncthing is running and enabled-->

View file

@ -121,8 +121,6 @@
<!--Sub Folder title-->
<!--SyncthingService-->
<!--Title of the "syncthing disabled" dialog-->
<!--Message of the "syncthing disabled" dialog-->
<!--Button text on the "syncthing disabled" dialog-->
<!--Button text on the "syncthing disabled" dialog, used as menu item to stop syncthing service if "always_run_in_background" is true-->
<!--Title of the notification shown while syncthing is running and enabled-->
<!--Toast shown if syncthing failed to create a config-->

View file

@ -244,7 +244,6 @@
<string name="syncthing_disabled_title">Syncthing er deaktivert</string>
<!--Message of the "syncthing disabled" dialog-->
<!--Button text on the "syncthing disabled" dialog-->
<string name="syncthing_disabled_change_settings">Endre Innstillinger</string>
<!--Button text on the "syncthing disabled" dialog, used as menu item to stop syncthing service if "always_run_in_background" is true-->
<string name="exit">Avslutt</string>
<!--Title of the notification shown while syncthing is running and enabled-->

View file

@ -121,8 +121,6 @@
<!--Sub Folder title-->
<!--SyncthingService-->
<!--Title of the "syncthing disabled" dialog-->
<!--Message of the "syncthing disabled" dialog-->
<!--Button text on the "syncthing disabled" dialog-->
<!--Button text on the "syncthing disabled" dialog, used as menu item to stop syncthing service if "always_run_in_background" is true-->
<!--Title of the notification shown while syncthing is running and enabled-->
<!--Toast shown if syncthing failed to create a config-->

View file

@ -348,7 +348,6 @@ Als je problemen tegenkomt, meld ze dan via GitHub.</string>
<string name="syncthing_disabled_title">Syncthing is uitgeschakeld</string>
<!--Message of the "syncthing disabled" dialog-->
<!--Button text on the "syncthing disabled" dialog-->
<string name="syncthing_disabled_change_settings">Instellingen wijzigen</string>
<!--Button text on the "syncthing disabled" dialog, used as menu item to stop syncthing service if "always_run_in_background" is true-->
<string name="exit">Afsluiten</string>
<!--Title of the notification shown while syncthing is running and enabled-->

View file

@ -244,7 +244,6 @@
<string name="syncthing_disabled_title">Syncthing er ikkje aktivert</string>
<!--Message of the "syncthing disabled" dialog-->
<!--Button text on the "syncthing disabled" dialog-->
<string name="syncthing_disabled_change_settings">Endre innstillingar</string>
<!--Button text on the "syncthing disabled" dialog, used as menu item to stop syncthing service if "always_run_in_background" is true-->
<string name="exit">Avslutt</string>
<!--Title of the notification shown while syncthing is running and enabled-->

View file

@ -97,8 +97,6 @@
<!--Title of the "share log" menu button-->
<!--SyncthingService-->
<!--Title of the "syncthing disabled" dialog-->
<!--Message of the "syncthing disabled" dialog-->
<!--Button text on the "syncthing disabled" dialog-->
<!--Button text on the "syncthing disabled" dialog, used as menu item to stop syncthing service if "always_run_in_background" is true-->
<!--Title of the notification shown while syncthing is running and enabled-->
<!--Toast shown if folder observer fails to traverse a folder-->

View file

@ -321,7 +321,6 @@ Proszę zgłaszać napotkane błędy programu za pośrednictwem serwisu Github.<
<string name="syncthing_disabled_title">Syncthing jest wyłączony</string>
<!--Message of the "syncthing disabled" dialog-->
<!--Button text on the "syncthing disabled" dialog-->
<string name="syncthing_disabled_change_settings">Zmień ustawienia</string>
<!--Button text on the "syncthing disabled" dialog, used as menu item to stop syncthing service if "always_run_in_background" is true-->
<string name="exit">Zakończ</string>
<!--Title of the notification shown while syncthing is running and enabled-->

View file

@ -339,7 +339,6 @@ Por favor, nos avise sobre quaisquer problemas que você encontrar via Github.</
<string name="syncthing_disabled_title">O Syncthing está desabilitado</string>
<!--Message of the "syncthing disabled" dialog-->
<!--Button text on the "syncthing disabled" dialog-->
<string name="syncthing_disabled_change_settings">Alterar configurações</string>
<!--Button text on the "syncthing disabled" dialog, used as menu item to stop syncthing service if "always_run_in_background" is true-->
<string name="exit">Sair</string>
<!--Title of the notification shown while syncthing is running and enabled-->

View file

@ -266,7 +266,6 @@ Reporte, através do Github, quaisquer problemas que encontre, por favor.</strin
<string name="syncthing_disabled_title">O Syncthing está desactivado</string>
<!--Message of the "syncthing disabled" dialog-->
<!--Button text on the "syncthing disabled" dialog-->
<string name="syncthing_disabled_change_settings">Alterar configurações</string>
<!--Button text on the "syncthing disabled" dialog, used as menu item to stop syncthing service if "always_run_in_background" is true-->
<string name="exit">Sair</string>
<!--Title of the notification shown while syncthing is running and enabled-->

View file

@ -370,7 +370,6 @@ Vă rugăm să raportați orice problemă întâlniți, prin intermediul GitHub.
<string name="syncthing_disabled_title">Syncthing este dezactivat</string>
<!--Message of the "syncthing disabled" dialog-->
<!--Button text on the "syncthing disabled" dialog-->
<string name="syncthing_disabled_change_settings">Schimbă setări</string>
<!--Button text on the "syncthing disabled" dialog, used as menu item to stop syncthing service if "always_run_in_background" is true-->
<string name="exit">Ieșire</string>
<!--Title of the notification shown while syncthing is running and enabled-->

View file

@ -354,7 +354,6 @@
<string name="syncthing_disabled_title">Syncthing выключен</string>
<!--Message of the "syncthing disabled" dialog-->
<!--Button text on the "syncthing disabled" dialog-->
<string name="syncthing_disabled_change_settings">Изменить настройки</string>
<!--Button text on the "syncthing disabled" dialog, used as menu item to stop syncthing service if "always_run_in_background" is true-->
<string name="exit">Выход</string>
<!--Title of the notification shown while syncthing is running and enabled-->

View file

@ -229,7 +229,6 @@
<string name="syncthing_disabled_title">Syncthing je zakázaný</string>
<!--Message of the "syncthing disabled" dialog-->
<!--Button text on the "syncthing disabled" dialog-->
<string name="syncthing_disabled_change_settings">Zmeniť Nastavenia</string>
<!--Button text on the "syncthing disabled" dialog, used as menu item to stop syncthing service if "always_run_in_background" is true-->
<string name="exit">Koniec</string>
<!--Title of the notification shown while syncthing is running and enabled-->

View file

@ -121,8 +121,6 @@
<!--Sub Folder title-->
<!--SyncthingService-->
<!--Title of the "syncthing disabled" dialog-->
<!--Message of the "syncthing disabled" dialog-->
<!--Button text on the "syncthing disabled" dialog-->
<!--Button text on the "syncthing disabled" dialog, used as menu item to stop syncthing service if "always_run_in_background" is true-->
<!--Title of the notification shown while syncthing is running and enabled-->
<!--Toast shown if syncthing failed to create a config-->

View file

@ -121,8 +121,6 @@
<!--Sub Folder title-->
<!--SyncthingService-->
<!--Title of the "syncthing disabled" dialog-->
<!--Message of the "syncthing disabled" dialog-->
<!--Button text on the "syncthing disabled" dialog-->
<!--Button text on the "syncthing disabled" dialog, used as menu item to stop syncthing service if "always_run_in_background" is true-->
<!--Title of the notification shown while syncthing is running and enabled-->
<!--Toast shown if syncthing failed to create a config-->

View file

@ -365,7 +365,6 @@ Vänligen rapportera eventuella problem du stöter på via Github.</string>
<string name="syncthing_disabled_title">Syncthing är inaktiverad</string>
<!--Message of the "syncthing disabled" dialog-->
<!--Button text on the "syncthing disabled" dialog-->
<string name="syncthing_disabled_change_settings">Ändra inställningar</string>
<!--Button text on the "syncthing disabled" dialog, used as menu item to stop syncthing service if "always_run_in_background" is true-->
<string name="exit">Avsluta</string>
<!--Title of the notification shown while syncthing is running and enabled-->

View file

@ -264,7 +264,6 @@ Eğer herhangi bir sorunla karşılaşırsan Github aracılığıyla bildir.</st
<string name="syncthing_disabled_title">Syncthing devre dışı</string>
<!--Message of the "syncthing disabled" dialog-->
<!--Button text on the "syncthing disabled" dialog-->
<string name="syncthing_disabled_change_settings">Ayarları Değiştir</string>
<!--Button text on the "syncthing disabled" dialog, used as menu item to stop syncthing service if "always_run_in_background" is true-->
<string name="exit">Çık</string>
<!--Title of the notification shown while syncthing is running and enabled-->

View file

@ -239,9 +239,6 @@
<!--SyncthingService-->
<!--Title of the "syncthing disabled" dialog-->
<string name="syncthing_disabled_title">Syncthing заборонено</string>
<!--Message of the "syncthing disabled" dialog-->
<!--Button text on the "syncthing disabled" dialog-->
<string name="syncthing_disabled_change_settings">Змінити Налаштування</string>
<!--Button text on the "syncthing disabled" dialog, used as menu item to stop syncthing service if "always_run_in_background" is true-->
<string name="exit">Вихід</string>
<!--Title of the notification shown while syncthing is running and enabled-->

View file

@ -240,7 +240,6 @@
<string name="syncthing_disabled_title">Đã tắt Syncthing</string>
<!--Message of the "syncthing disabled" dialog-->
<!--Button text on the "syncthing disabled" dialog-->
<string name="syncthing_disabled_change_settings">Thay đổi cài đặt</string>
<!--Button text on the "syncthing disabled" dialog, used as menu item to stop syncthing service if "always_run_in_background" is true-->
<string name="exit">Thoát</string>
<!--Title of the notification shown while syncthing is running and enabled-->

View file

@ -316,7 +316,6 @@
<string name="syncthing_disabled_title">Syncthing 已禁用</string>
<!--Message of the "syncthing disabled" dialog-->
<!--Button text on the "syncthing disabled" dialog-->
<string name="syncthing_disabled_change_settings">变更设置</string>
<!--Button text on the "syncthing disabled" dialog, used as menu item to stop syncthing service if "always_run_in_background" is true-->
<string name="exit">退出</string>
<!--Title of the notification shown while syncthing is running and enabled-->

View file

@ -313,7 +313,6 @@
<string name="syncthing_disabled_title">Syncthing 已經停用</string>
<!--Message of the "syncthing disabled" dialog-->
<!--Button text on the "syncthing disabled" dialog-->
<string name="syncthing_disabled_change_settings">更改設定</string>
<!--Button text on the "syncthing disabled" dialog, used as menu item to stop syncthing service if "always_run_in_background" is true-->
<string name="exit">離開</string>
<!--Title of the notification shown while syncthing is running and enabled-->

View file

@ -38,6 +38,7 @@ Please report any problems you encounter via Github.</string>
<string name="generic_error">Error</string>
<string name="grant_permission">Grant permission</string>
<string name="permission_granted">Permission granted</string>
<string name="reason">Reason:</string>
<string name="accept">Accept</string>
@ -139,6 +140,13 @@ Please report any problems you encounter via Github.</string>
<!-- Title for current upload rate -->
<string name="upload_title">Upload</string>
<!-- StatusFragment -->
<string name="status_fragment_title">Status</string>
<string name="syncthing_starting">Syncthing is starting.</string>
<string name="syncthing_running">Syncthing is running.</string>
<string name="syncthing_not_running">Syncthing is not running.</string>
<string name="syncthing_has_crashed">Syncthing has crashed.</string>
<!-- DrawerFragment -->
@ -155,7 +163,7 @@ Please report any problems you encounter via Github.</string>
<string name="ram_usage">RAM Usage</string>
<!-- Title for announce server status -->
<string name="announce_server">Announce Server</string>
<string name="announce_server">Configured Announce Server</string>
<string name="restart">Restart</string>
@ -631,18 +639,29 @@ Please report any problems you encounter via Github.</string>
<!-- Sub Folder title -->
<string name="sub_folder">Sub folder</string>
<!-- RunConditionMonitor -->
<!-- Explanations why syncthing is running or not running -->
<string name="reason_not_on_ac_power">Phone is not running on AC power.</string>
<string name="reason_not_on_battery_power">Phone is not running on battery power.</string>
<string name="reason_not_while_power_saving">Syncthing is not running as the phone is currently power saving.</string>
<string name="reason_not_while_auto_sync_data_disabled">Syncthing is not running as Android currently has \'Auto-sync data\' disabled.</string>
<string name="reason_on_mobile_data">Syncthing is running as mobile data is currently connected.</string>
<string name="reason_not_on_mobile_data">Syncthing is allowed to run on mobile data connection but mobile data isn\'t connected.</string>
<string name="reason_on_wifi">Syncthing is allowed to run on WiFi and WiFi is currently connected.</string>
<string name="reason_not_on_wifi">Syncthing is allowed to run on WiFi but WiFi isn\'t connected or the phone is in flight mode.</string>
<string name="reason_on_metered_nonmetered_wifi">Syncthing is allowed to run on metered and non-metered WiFi connections.</string>
<string name="reason_on_whitelisted_wifi">Syncthing is allowed to run on the current WiFi network.</string>
<string name="reason_not_on_whitelisted_wifi">Syncthing is not running as the current WiFi network\'s name is not whitelisted.</string>
<string name="reason_on_nonmetered_wifi">Syncthing is allowed to run on non-metered WiFi connections. The active WiFi connection is non-metered.</string>
<string name="reason_not_nonmetered_wifi">Syncthing is not running as you disallowed it to run on metered WiFi connections.</string>
<string name="reason_on_flight_mode">Syncthing is running as you allowed it to run when flight mode is active.</string>
<!-- SyncthingService -->
<!-- Title of the "syncthing disabled" dialog -->
<string name="syncthing_disabled_title">Syncthing is disabled</string>
<!-- Message of the "syncthing disabled" dialog -->
<string name="syncthing_disabled_message">Do you want to change the run conditions?</string>
<!-- Button text on the "syncthing disabled" dialog -->
<string name="syncthing_disabled_change_settings">Change Settings</string>
<!-- Button text on the "syncthing disabled" dialog, used as menu item to stop syncthing service if "always_run_in_background" is true -->
<string name="exit">Exit</string>