mirror of
https://github.com/syncthing/syncthing-android.git
synced 2024-11-26 06:11:19 +00:00
Added native main activity with tabs for repos and nodes.
This commit is contained in:
parent
7e69c3a354
commit
d524461634
22 changed files with 792 additions and 112 deletions
|
@ -18,7 +18,7 @@
|
||||||
android:theme="@style/Theme.AppCompat" >
|
android:theme="@style/Theme.AppCompat" >
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".gui.WebGuiActivity"
|
android:name=".gui.MainActivity"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:launchMode="singleTop" >
|
android:launchMode="singleTop" >
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
|
@ -27,12 +27,20 @@
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name=".gui.WebGuiActivity"
|
||||||
|
android:label="@string/web_gui_title" >
|
||||||
|
<meta-data
|
||||||
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
|
android:value=".gui.MainActivity" />
|
||||||
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".gui.SettingsActivity"
|
android:name=".gui.SettingsActivity"
|
||||||
android:label="@string/settings_title" >
|
android:label="@string/settings_title" >
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value=".WebGuiActivity" />
|
android:value=".gui.MainActivity" />
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<service android:name=".syncthing.SyncthingService" />
|
<service android:name=".syncthing.SyncthingService" />
|
||||||
|
|
45
src/main/java/com/nutomic/syncthingandroid/NodeAdapter.java
Normal file
45
src/main/java/com/nutomic/syncthingandroid/NodeAdapter.java
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
package com.nutomic.syncthingandroid;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.ArrayAdapter;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.nutomic.syncthingandroid.syncthing.RestApi;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates item views for node items.
|
||||||
|
*/
|
||||||
|
public class NodeAdapter extends ArrayAdapter<RestApi.Node> {
|
||||||
|
|
||||||
|
public NodeAdapter(Context context) {
|
||||||
|
super(context, R.layout.node_list_item);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View getView(int position, View convertView, ViewGroup parent) {
|
||||||
|
if (convertView == null) {
|
||||||
|
LayoutInflater inflater = (LayoutInflater) getContext()
|
||||||
|
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||||
|
convertView = inflater.inflate(R.layout.node_list_item, parent, false);
|
||||||
|
}
|
||||||
|
TextView name = (TextView) convertView.findViewById(R.id.name);
|
||||||
|
name.setText(getItem(position).Name);
|
||||||
|
return convertView;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replacement for addAll, which is not implemented on lower API levels.
|
||||||
|
*/
|
||||||
|
public void add(List<RestApi.Node> nodes) {
|
||||||
|
for (RestApi.Node n : nodes) {
|
||||||
|
add(n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
package com.nutomic.syncthingandroid;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.ArrayAdapter;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.nutomic.syncthingandroid.syncthing.RestApi;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates item views for repository items.
|
||||||
|
*/
|
||||||
|
public class RepositoryAdapter extends ArrayAdapter<RestApi.Repository> {
|
||||||
|
|
||||||
|
public RepositoryAdapter(Context context) {
|
||||||
|
super(context, R.layout.node_list_item);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View getView(int position, View convertView, ViewGroup parent) {
|
||||||
|
if (convertView == null) {
|
||||||
|
LayoutInflater inflater = (LayoutInflater) getContext()
|
||||||
|
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||||
|
convertView = inflater.inflate(R.layout.repository_list_item, parent, false);
|
||||||
|
}
|
||||||
|
TextView id = (TextView) convertView.findViewById(R.id.id);
|
||||||
|
id.setText(getItem(position).ID);
|
||||||
|
return convertView;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replacement for addAll, which is not implemented on lower API levels.
|
||||||
|
*/
|
||||||
|
public void add(List<RestApi.Repository> nodes) {
|
||||||
|
for (RestApi.Repository r : nodes) {
|
||||||
|
add(r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,126 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2011 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.nutomic.syncthingandroid.gui;
|
||||||
|
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.support.v4.app.Fragment;
|
||||||
|
import android.support.v4.app.FragmentManager;
|
||||||
|
import android.support.v4.app.ListFragment;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.ListAdapter;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.nutomic.syncthingandroid.R;
|
||||||
|
import com.nutomic.syncthingandroid.syncthing.RestApi;
|
||||||
|
import com.nutomic.syncthingandroid.syncthing.SyncthingService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link android.support.v4.app.ListFragment} that shows a configurable loading text.
|
||||||
|
*/
|
||||||
|
public abstract class LoadingListFragment extends Fragment implements RestApi.OnApiAvailableListener {
|
||||||
|
|
||||||
|
private boolean mInitialized = false;
|
||||||
|
|
||||||
|
private ListFragment mListFragment;
|
||||||
|
|
||||||
|
private View mListFragmentHolder;
|
||||||
|
|
||||||
|
private View mLoading;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (savedInstanceState != null) {
|
||||||
|
mListFragment = (ListFragment) getChildFragmentManager()
|
||||||
|
.getFragment(savedInstanceState, ListFragment.class.getName());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
mListFragment = new ListFragment();
|
||||||
|
}
|
||||||
|
getChildFragmentManager()
|
||||||
|
.beginTransaction()
|
||||||
|
.add(R.id.list_fragment, mListFragment)
|
||||||
|
.commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||||
|
Bundle savedInstanceState) {
|
||||||
|
View view = inflater.inflate(R.layout.loading_list_fragment, container, false);
|
||||||
|
mListFragmentHolder = view.findViewById(R.id.list_fragment);
|
||||||
|
mLoading = view.findViewById(R.id.loading);
|
||||||
|
TextView loadingTextView = (TextView) view.findViewById(R.id.loading_text);
|
||||||
|
|
||||||
|
if (SyncthingService.isFirstStart(getActivity())) {
|
||||||
|
loadingTextView.setText(getString(R.string.web_gui_creating_key));
|
||||||
|
}
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSaveInstanceState(Bundle outState) {
|
||||||
|
super.onSaveInstanceState(outState);
|
||||||
|
getChildFragmentManager().putFragment(outState, ListFragment.class.getName(), mListFragment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets adapter and empty text for {@link ListFragment}
|
||||||
|
* @param adapter Adapter to be used for {@link}ListFragment#setListAdapter}
|
||||||
|
* @param emptyText Resource id for text to be shown in the
|
||||||
|
* {@link ListFragment#setEmptyText(CharSequence)}.
|
||||||
|
*/
|
||||||
|
public void setListAdapter(ListAdapter adapter, int emptyText) {
|
||||||
|
mListFragment.setListAdapter(adapter);
|
||||||
|
|
||||||
|
mLoading.setVisibility(View.INVISIBLE);
|
||||||
|
mListFragmentHolder.setVisibility(View.VISIBLE);
|
||||||
|
mListFragment.setEmptyText(getString(emptyText));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStart() {
|
||||||
|
super.onStart();
|
||||||
|
onApiAvailable();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calls onInitAdapter if it has not yet been called, ListFragment is initialized,
|
||||||
|
* and SyncthingService is not null, and
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void onApiAvailable() {
|
||||||
|
MainActivity activity = (MainActivity) getActivity();
|
||||||
|
if (!mInitialized && getActivity() != null &&
|
||||||
|
activity.getApi() != null && mListFragment != null) {
|
||||||
|
onInitAdapter(activity);
|
||||||
|
mInitialized = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the list adapter should be set.
|
||||||
|
* @param activity
|
||||||
|
*/
|
||||||
|
public abstract void onInitAdapter(MainActivity activity);
|
||||||
|
|
||||||
|
}
|
206
src/main/java/com/nutomic/syncthingandroid/gui/MainActivity.java
Normal file
206
src/main/java/com/nutomic/syncthingandroid/gui/MainActivity.java
Normal file
|
@ -0,0 +1,206 @@
|
||||||
|
package com.nutomic.syncthingandroid.gui;
|
||||||
|
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.content.ComponentName;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.ServiceConnection;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.IBinder;
|
||||||
|
import android.support.v4.app.Fragment;
|
||||||
|
import android.support.v4.app.FragmentManager;
|
||||||
|
import android.support.v4.app.FragmentStatePagerAdapter;
|
||||||
|
import android.support.v4.app.FragmentTransaction;
|
||||||
|
import android.support.v4.view.ViewPager;
|
||||||
|
import android.support.v7.app.ActionBar;
|
||||||
|
import android.support.v7.app.ActionBar.Tab;
|
||||||
|
import android.support.v7.app.ActionBar.TabListener;
|
||||||
|
import android.support.v7.app.ActionBarActivity;
|
||||||
|
import android.view.Menu;
|
||||||
|
import android.view.MenuItem;
|
||||||
|
|
||||||
|
import com.nutomic.syncthingandroid.R;
|
||||||
|
import com.nutomic.syncthingandroid.syncthing.RestApi;
|
||||||
|
import com.nutomic.syncthingandroid.syncthing.SyncthingService;
|
||||||
|
import com.nutomic.syncthingandroid.syncthing.SyncthingServiceBinder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows {@link RepositoriesFragment} and {@link NodesFragment} in different tabs.
|
||||||
|
*/
|
||||||
|
public class MainActivity extends ActionBarActivity
|
||||||
|
implements SyncthingService.OnWebGuiAvailableListener{
|
||||||
|
|
||||||
|
private SyncthingService mSyncthingService;
|
||||||
|
|
||||||
|
private final ServiceConnection mSyncthingServiceConnection = new ServiceConnection() {
|
||||||
|
|
||||||
|
public void onServiceConnected(ComponentName className, IBinder service) {
|
||||||
|
SyncthingServiceBinder binder = (SyncthingServiceBinder) service;
|
||||||
|
mSyncthingService = binder.getService();
|
||||||
|
mSyncthingService.registerOnWebGuiAvailableListener(MainActivity.this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onServiceDisconnected(ComponentName className) {
|
||||||
|
mSyncthingService = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onWebGuiAvailable() {
|
||||||
|
mSyncthingService.getApi().registerOnApiAvailableListener(mRepositoriesFragment);
|
||||||
|
mSyncthingService.getApi().registerOnApiAvailableListener(mNodesFragment);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final FragmentStatePagerAdapter mSectionsPagerAdapter =
|
||||||
|
new FragmentStatePagerAdapter(getSupportFragmentManager()) {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Fragment getItem(int position) {
|
||||||
|
switch (position) {
|
||||||
|
case 0: return mRepositoriesFragment;
|
||||||
|
case 1: return mNodesFragment;
|
||||||
|
default: return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getCount() {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
private RepositoriesFragment mRepositoriesFragment;
|
||||||
|
|
||||||
|
private NodesFragment mNodesFragment;
|
||||||
|
|
||||||
|
ViewPager mViewPager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes tab navigation.
|
||||||
|
*/
|
||||||
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
final ActionBar actionBar = getSupportActionBar();
|
||||||
|
|
||||||
|
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
|
||||||
|
setContentView(R.layout.main_activity);
|
||||||
|
|
||||||
|
mViewPager = (ViewPager) findViewById(R.id.pager);
|
||||||
|
mViewPager.setAdapter(mSectionsPagerAdapter);
|
||||||
|
mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
|
||||||
|
@Override
|
||||||
|
public void onPageSelected(int position) {
|
||||||
|
actionBar.setSelectedNavigationItem(position);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
TabListener tabListener = new TabListener() {
|
||||||
|
public void onTabSelected(Tab tab, FragmentTransaction ft) {
|
||||||
|
mViewPager.setCurrentItem(tab.getPosition());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTabReselected(Tab tab, FragmentTransaction ft) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
actionBar.addTab(actionBar.newTab()
|
||||||
|
.setText(R.string.repositories_fragment_title)
|
||||||
|
.setTabListener(tabListener));
|
||||||
|
actionBar.addTab(actionBar.newTab()
|
||||||
|
.setText(R.string.nodes_fragment_title)
|
||||||
|
.setTabListener(tabListener));
|
||||||
|
|
||||||
|
if (savedInstanceState != null) {
|
||||||
|
FragmentManager fm = getSupportFragmentManager();
|
||||||
|
mRepositoriesFragment = (RepositoriesFragment) fm.getFragment(
|
||||||
|
savedInstanceState, RepositoriesFragment.class.getName());
|
||||||
|
mNodesFragment = (NodesFragment) fm.getFragment(
|
||||||
|
savedInstanceState, NodesFragment.class.getName());
|
||||||
|
mViewPager.setCurrentItem(savedInstanceState.getInt("currentTab"));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
mRepositoriesFragment = new RepositoriesFragment();
|
||||||
|
mNodesFragment = new NodesFragment();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SyncthingService.isFirstStart(this)) {
|
||||||
|
new AlertDialog.Builder(this)
|
||||||
|
.setTitle(R.string.welcome_title)
|
||||||
|
.setMessage(R.string.welcome_text)
|
||||||
|
.setNeutralButton(android.R.string.ok, null)
|
||||||
|
.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
getApplicationContext().startService(
|
||||||
|
new Intent(this, SyncthingService.class));
|
||||||
|
bindService(new Intent(this, SyncthingService.class),
|
||||||
|
mSyncthingServiceConnection, Context.BIND_AUTO_CREATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroy() {
|
||||||
|
super.onDestroy();
|
||||||
|
unbindService(mSyncthingServiceConnection);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves fragment states.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void onSaveInstanceState(Bundle outState) {
|
||||||
|
super.onSaveInstanceState(outState);
|
||||||
|
// Avoid crash if called during startup.
|
||||||
|
if (mRepositoriesFragment != null && mNodesFragment != null) {
|
||||||
|
FragmentManager fm = getSupportFragmentManager();
|
||||||
|
fm.putFragment(outState, RepositoriesFragment.class.getName(), mRepositoriesFragment);
|
||||||
|
fm.putFragment(outState, NodesFragment.class.getName(), mNodesFragment);
|
||||||
|
outState.putInt("currentTab", mViewPager.getCurrentItem());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCreateOptionsMenu(Menu menu) {
|
||||||
|
getMenuInflater().inflate(R.menu.menu, menu);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onPrepareOptionsMenu(Menu menu) {
|
||||||
|
return mSyncthingService != null && mSyncthingService.isWebGuiAvailable();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
|
switch (item.getItemId()) {
|
||||||
|
case R.id.web_gui:
|
||||||
|
startActivity(new Intent(this, WebGuiActivity.class));
|
||||||
|
return true;
|
||||||
|
case R.id.settings:
|
||||||
|
startActivity(new Intent(this, SettingsActivity.class));
|
||||||
|
return true;
|
||||||
|
case R.id.exit:
|
||||||
|
// Make sure we unbind first.
|
||||||
|
finish();
|
||||||
|
getApplicationContext().stopService(new Intent(this, SyncthingService.class));
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return super.onOptionsItemSelected(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns RestApi instance, or null if SyncthingService is not yet connected.
|
||||||
|
*/
|
||||||
|
public RestApi getApi() {
|
||||||
|
return (mSyncthingService != null)
|
||||||
|
? mSyncthingService.getApi()
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
package com.nutomic.syncthingandroid.gui;
|
||||||
|
|
||||||
|
import com.nutomic.syncthingandroid.NodeAdapter;
|
||||||
|
import com.nutomic.syncthingandroid.R;
|
||||||
|
import com.nutomic.syncthingandroid.syncthing.RestApi;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays a list of all existing nodes.
|
||||||
|
*/
|
||||||
|
public class NodesFragment extends LoadingListFragment implements
|
||||||
|
RestApi.OnApiAvailableListener {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onInitAdapter(MainActivity activity) {
|
||||||
|
NodeAdapter adapter = new NodeAdapter(activity);
|
||||||
|
adapter.add(activity.getApi().getNodes());
|
||||||
|
setListAdapter(adapter, R.string.nodes_list_empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
package com.nutomic.syncthingandroid.gui;
|
||||||
|
|
||||||
|
import com.nutomic.syncthingandroid.R;
|
||||||
|
import com.nutomic.syncthingandroid.RepositoryAdapter;
|
||||||
|
import com.nutomic.syncthingandroid.syncthing.RestApi;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays a list of all existing repositories.
|
||||||
|
*/
|
||||||
|
public class RepositoriesFragment extends LoadingListFragment implements
|
||||||
|
RestApi.OnApiAvailableListener {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onInitAdapter(MainActivity activity) {
|
||||||
|
RepositoryAdapter adapter = new RepositoryAdapter(activity);
|
||||||
|
adapter.add(activity.getApi().getRepositories());
|
||||||
|
setListAdapter(adapter, R.string.repositories_list_empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -5,7 +5,6 @@ import android.content.ComponentName;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.ServiceConnection;
|
import android.content.ServiceConnection;
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
|
@ -43,7 +42,7 @@ public class SettingsActivity extends PreferenceActivity
|
||||||
/**
|
/**
|
||||||
* Binds to service and sets syncthing preferences from Rest API.
|
* Binds to service and sets syncthing preferences from Rest API.
|
||||||
*/
|
*/
|
||||||
private ServiceConnection mSyncthingServiceConnection = new ServiceConnection() {
|
private final ServiceConnection mSyncthingServiceConnection = new ServiceConnection() {
|
||||||
|
|
||||||
public void onServiceConnected(ComponentName className, IBinder service) {
|
public void onServiceConnected(ComponentName className, IBinder service) {
|
||||||
SyncthingServiceBinder binder = (SyncthingServiceBinder) service;
|
SyncthingServiceBinder binder = (SyncthingServiceBinder) service;
|
||||||
|
|
|
@ -1,16 +1,13 @@
|
||||||
package com.nutomic.syncthingandroid.gui;
|
package com.nutomic.syncthingandroid.gui;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.app.Activity;
|
|
||||||
import android.app.AlertDialog;
|
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.ServiceConnection;
|
import android.content.ServiceConnection;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.view.Menu;
|
import android.support.v7.app.ActionBarActivity;
|
||||||
import android.view.MenuItem;
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.webkit.WebView;
|
import android.webkit.WebView;
|
||||||
import android.webkit.WebViewClient;
|
import android.webkit.WebViewClient;
|
||||||
|
@ -24,16 +21,15 @@ import com.nutomic.syncthingandroid.syncthing.SyncthingServiceBinder;
|
||||||
/**
|
/**
|
||||||
* Holds a WebView that shows the web ui of the local syncthing instance.
|
* Holds a WebView that shows the web ui of the local syncthing instance.
|
||||||
*/
|
*/
|
||||||
public class WebGuiActivity extends Activity implements SyncthingService.OnWebGuiAvailableListener {
|
public class WebGuiActivity extends ActionBarActivity implements SyncthingService.OnWebGuiAvailableListener {
|
||||||
|
|
||||||
private static final String TAG = "WebGuiActivity";
|
|
||||||
|
|
||||||
private WebView mWebView;
|
private WebView mWebView;
|
||||||
|
|
||||||
private View mLoadingView;
|
private View mLoadingView;
|
||||||
|
|
||||||
private SyncthingService mSyncthingService;
|
private SyncthingService mSyncthingService;
|
||||||
|
|
||||||
private ServiceConnection mSyncthingServiceConnection = new ServiceConnection() {
|
private final ServiceConnection mSyncthingServiceConnection = new ServiceConnection() {
|
||||||
|
|
||||||
public void onServiceConnected(ComponentName className, IBinder service) {
|
public void onServiceConnected(ComponentName className, IBinder service) {
|
||||||
SyncthingServiceBinder binder = (SyncthingServiceBinder) service;
|
SyncthingServiceBinder binder = (SyncthingServiceBinder) service;
|
||||||
|
@ -49,7 +45,7 @@ public class WebGuiActivity extends Activity implements SyncthingService.OnWebGu
|
||||||
/**
|
/**
|
||||||
* Hides the loading screen and shows the WebView once it is fully loaded.
|
* Hides the loading screen and shows the WebView once it is fully loaded.
|
||||||
*/
|
*/
|
||||||
private WebViewClient mWebViewClient = new WebViewClient() {
|
private final WebViewClient mWebViewClient = new WebViewClient() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPageFinished(WebView view, String url) {
|
public void onPageFinished(WebView view, String url) {
|
||||||
|
@ -68,7 +64,8 @@ public class WebGuiActivity extends Activity implements SyncthingService.OnWebGu
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
setContentView(R.layout.main);
|
setContentView(R.layout.web_gui_activity);
|
||||||
|
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||||
|
|
||||||
mLoadingView = findViewById(R.id.loading);
|
mLoadingView = findViewById(R.id.loading);
|
||||||
ProgressBar pb = (ProgressBar) mLoadingView.findViewById(R.id.progress);
|
ProgressBar pb = (ProgressBar) mLoadingView.findViewById(R.id.progress);
|
||||||
|
@ -81,15 +78,8 @@ public class WebGuiActivity extends Activity implements SyncthingService.OnWebGu
|
||||||
if (SyncthingService.isFirstStart(this)) {
|
if (SyncthingService.isFirstStart(this)) {
|
||||||
TextView loadingText = (TextView) mLoadingView.findViewById(R.id.loading_text);
|
TextView loadingText = (TextView) mLoadingView.findViewById(R.id.loading_text);
|
||||||
loadingText.setText(R.string.web_gui_creating_key);
|
loadingText.setText(R.string.web_gui_creating_key);
|
||||||
new AlertDialog.Builder(this)
|
|
||||||
.setTitle(R.string.welcome_title)
|
|
||||||
.setMessage(R.string.welcome_text)
|
|
||||||
.setNeutralButton(android.R.string.ok, null)
|
|
||||||
.show();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getApplicationContext().startService(
|
|
||||||
new Intent(this, SyncthingService.class));
|
|
||||||
bindService(
|
bindService(
|
||||||
new Intent(this, SyncthingService.class),
|
new Intent(this, SyncthingService.class),
|
||||||
mSyncthingServiceConnection, Context.BIND_AUTO_CREATE);
|
mSyncthingServiceConnection, Context.BIND_AUTO_CREATE);
|
||||||
|
@ -109,31 +99,4 @@ public class WebGuiActivity extends Activity implements SyncthingService.OnWebGu
|
||||||
unbindService(mSyncthingServiceConnection);
|
unbindService(mSyncthingServiceConnection);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onCreateOptionsMenu(Menu menu) {
|
|
||||||
getMenuInflater().inflate(R.menu.menu, menu);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onPrepareOptionsMenu(Menu menu) {
|
|
||||||
return mSyncthingService != null && mSyncthingService.isWebGuiAvailable();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onOptionsItemSelected(MenuItem item) {
|
|
||||||
switch (item.getItemId()) {
|
|
||||||
case R.id.settings:
|
|
||||||
startActivity(new Intent(this, SettingsActivity.class));
|
|
||||||
return true;
|
|
||||||
case R.id.exit:
|
|
||||||
// Make sure we unbind first.
|
|
||||||
finish();
|
|
||||||
getApplicationContext().stopService(new Intent(this, SyncthingService.class));
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return super.onOptionsItemSelected(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,7 @@ public class GetTask extends AsyncTask<String, Void, String> {
|
||||||
HttpClient httpclient = new DefaultHttpClient();
|
HttpClient httpclient = new DefaultHttpClient();
|
||||||
HttpGet get = new HttpGet(fullUri);
|
HttpGet get = new HttpGet(fullUri);
|
||||||
get.addHeader(new BasicHeader("X-API-Key", params[2]));
|
get.addHeader(new BasicHeader("X-API-Key", params[2]));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
HttpResponse response = httpclient.execute(get);
|
HttpResponse response = httpclient.execute(get);
|
||||||
HttpEntity entity = response.getEntity();
|
HttpEntity entity = response.getEntity();
|
||||||
|
|
|
@ -3,7 +3,6 @@ package com.nutomic.syncthingandroid.syncthing;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import org.apache.http.HttpResponse;
|
|
||||||
import org.apache.http.client.HttpClient;
|
import org.apache.http.client.HttpClient;
|
||||||
import org.apache.http.client.methods.HttpPost;
|
import org.apache.http.client.methods.HttpPost;
|
||||||
import org.apache.http.entity.StringEntity;
|
import org.apache.http.entity.StringEntity;
|
||||||
|
@ -38,6 +37,7 @@ public class PostTask extends AsyncTask<String, Void, Void> {
|
||||||
HttpClient httpclient = new DefaultHttpClient();
|
HttpClient httpclient = new DefaultHttpClient();
|
||||||
HttpPost post = new HttpPost(fullUri);
|
HttpPost post = new HttpPost(fullUri);
|
||||||
post.addHeader(new BasicHeader("X-API-Key", params[2]));
|
post.addHeader(new BasicHeader("X-API-Key", params[2]));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
post.setEntity(new StringEntity(params[3]));
|
post.setEntity(new StringEntity(params[3]));
|
||||||
httpclient.execute(post);
|
httpclient.execute(post);
|
||||||
|
|
|
@ -14,6 +14,12 @@ import org.json.JSONArray;
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides functions to interact with the syncthing REST API.
|
* Provides functions to interact with the syncthing REST API.
|
||||||
*/
|
*/
|
||||||
|
@ -31,19 +37,62 @@ public class RestApi implements SyncthingService.OnWebGuiAvailableListener {
|
||||||
*/
|
*/
|
||||||
public static final String TYPE_GUI = "GUI";
|
public static final String TYPE_GUI = "GUI";
|
||||||
|
|
||||||
|
public static class Node {
|
||||||
|
public String Addresses;
|
||||||
|
public String Name;
|
||||||
|
public String NodeID;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Repository {
|
||||||
|
public String Directory;
|
||||||
|
public String ID;
|
||||||
|
public final boolean IgnorePerms = true;
|
||||||
|
public String Invalid;
|
||||||
|
public List<Node> Nodes;
|
||||||
|
public boolean ReadOnly;
|
||||||
|
public Versioning Versioning;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Versioning {
|
||||||
|
protected final Map<String, String> mParams = new HashMap<String, String>();
|
||||||
|
public String getType() {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
public Map<String, String> getParams() {
|
||||||
|
return mParams;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class SimpleVersioning extends Versioning {
|
||||||
|
@Override
|
||||||
|
public String getType() {
|
||||||
|
return "simple";
|
||||||
|
}
|
||||||
|
public void setParams(int keep) {
|
||||||
|
mParams.put("keep", Integer.toString(keep));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface OnApiAvailableListener {
|
||||||
|
public void onApiAvailable();
|
||||||
|
}
|
||||||
|
|
||||||
|
private final LinkedList<OnApiAvailableListener> mOnApiAvailableListeners =
|
||||||
|
new LinkedList<OnApiAvailableListener>();
|
||||||
|
|
||||||
private static final int NOTIFICATION_RESTART = 2;
|
private static final int NOTIFICATION_RESTART = 2;
|
||||||
|
|
||||||
private Context mContext;
|
private final Context mContext;
|
||||||
|
|
||||||
private String mVersion;
|
private String mVersion;
|
||||||
|
|
||||||
private String mUrl;
|
private final String mUrl;
|
||||||
|
|
||||||
private String mApiKey;
|
private String mApiKey;
|
||||||
|
|
||||||
private JSONObject mConfig;
|
private JSONObject mConfig;
|
||||||
|
|
||||||
private NotificationManager mNotificationManager;
|
private final NotificationManager mNotificationManager;
|
||||||
|
|
||||||
public RestApi(Context context, String url, String apiKey) {
|
public RestApi(Context context, String url, String apiKey) {
|
||||||
mContext = context;
|
mContext = context;
|
||||||
|
@ -60,6 +109,9 @@ public class RestApi implements SyncthingService.OnWebGuiAvailableListener {
|
||||||
return mUrl;
|
return mUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets version and config, then calls any OnApiAvailableListeners.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void onWebGuiAvailable() {
|
public void onWebGuiAvailable() {
|
||||||
new GetTask() {
|
new GetTask() {
|
||||||
|
@ -74,6 +126,10 @@ public class RestApi implements SyncthingService.OnWebGuiAvailableListener {
|
||||||
protected void onPostExecute(String config) {
|
protected void onPostExecute(String config) {
|
||||||
try {
|
try {
|
||||||
mConfig = new JSONObject(config);
|
mConfig = new JSONObject(config);
|
||||||
|
for (OnApiAvailableListener listener : mOnApiAvailableListeners) {
|
||||||
|
listener.onApiAvailable();
|
||||||
|
}
|
||||||
|
mOnApiAvailableListeners.clear();
|
||||||
}
|
}
|
||||||
catch (JSONException e) {
|
catch (JSONException e) {
|
||||||
Log.w(TAG, "Failed to parse config", e);
|
Log.w(TAG, "Failed to parse config", e);
|
||||||
|
@ -139,16 +195,9 @@ public class RestApi implements SyncthingService.OnWebGuiAvailableListener {
|
||||||
*/
|
*/
|
||||||
public <T> void setValue(String name, String key, T value, boolean isArray) {
|
public <T> void setValue(String name, String key, T value, boolean isArray) {
|
||||||
try {
|
try {
|
||||||
if (isArray) {
|
mConfig.getJSONObject(name).put(key, (isArray)
|
||||||
JSONArray json = new JSONArray();
|
? listToJson(((String) value).split(" "))
|
||||||
for (String s : ((String) value).split(" ")) {
|
: value);
|
||||||
json.put(s);
|
|
||||||
}
|
|
||||||
mConfig.getJSONObject(name).put(key, json);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
mConfig.getJSONObject(name).put(key, value);
|
|
||||||
}
|
|
||||||
configUpdated();
|
configUpdated();
|
||||||
}
|
}
|
||||||
catch (JSONException e) {
|
catch (JSONException e) {
|
||||||
|
@ -156,6 +205,18 @@ public class RestApi implements SyncthingService.OnWebGuiAvailableListener {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts an array of strings to JSON array. Like JSONArray#JSONArray(Object array), but
|
||||||
|
* works on all API levels.
|
||||||
|
*/
|
||||||
|
private JSONArray listToJson(String[] list) {
|
||||||
|
JSONArray json = new JSONArray();
|
||||||
|
for (String s : list) {
|
||||||
|
json.put(s);
|
||||||
|
}
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends the updated mConfig via Rest API to syncthing and displays a "restart" notification.
|
* Sends the updated mConfig via Rest API to syncthing and displays a "restart" notification.
|
||||||
*/
|
*/
|
||||||
|
@ -176,4 +237,90 @@ public class RestApi implements SyncthingService.OnWebGuiAvailableListener {
|
||||||
mNotificationManager.notify(NOTIFICATION_RESTART, n);
|
mNotificationManager.notify(NOTIFICATION_RESTART, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of all existing nodes.
|
||||||
|
*/
|
||||||
|
public List<Node> getNodes() {
|
||||||
|
try {
|
||||||
|
return getNodes(mConfig.getJSONArray("Nodes"));
|
||||||
|
}
|
||||||
|
catch (JSONException e) {
|
||||||
|
Log.w(TAG, "Failed to read nodes", e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of all nodes in the array nodes.
|
||||||
|
*/
|
||||||
|
private List<Node> getNodes(JSONArray nodes) throws JSONException {
|
||||||
|
List<Node> ret;
|
||||||
|
ret = new ArrayList<Node>(nodes.length());
|
||||||
|
for (int i = 0; i < nodes.length(); i++) {
|
||||||
|
JSONObject json = nodes.getJSONObject(i);
|
||||||
|
Node n = new Node();
|
||||||
|
if (!json.isNull("Addresses")) {
|
||||||
|
n.Addresses = json.getJSONArray("Addresses").join(" ").replace("\"", "");
|
||||||
|
}
|
||||||
|
n.Name = json.getString("Name");
|
||||||
|
n.NodeID = json.getString("NodeID");
|
||||||
|
ret.add(n);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of all existing repositores.
|
||||||
|
*/
|
||||||
|
public List<Repository> getRepositories() {
|
||||||
|
List<Repository> ret = null;
|
||||||
|
try {
|
||||||
|
JSONArray repos = mConfig.getJSONArray("Repositories");
|
||||||
|
ret = new ArrayList<Repository>(repos.length());
|
||||||
|
for (int i = 0; i < repos.length(); i++) {
|
||||||
|
JSONObject json = repos.getJSONObject(i);
|
||||||
|
Repository r = new Repository();
|
||||||
|
r.Directory = json.getString("Directory");
|
||||||
|
r.ID = json.getString("ID");
|
||||||
|
// Hardcoded to true because missing permissions support.
|
||||||
|
// r.IgnorePerms = json.getBoolean("IgnorePerms");
|
||||||
|
r.Invalid = json.getString("Invalid");
|
||||||
|
r.Nodes = getNodes(json.getJSONArray("Nodes"));
|
||||||
|
|
||||||
|
r.ReadOnly = json.getBoolean("ReadOnly");
|
||||||
|
JSONObject versioning = json.getJSONObject("Versioning");
|
||||||
|
if (versioning.getString("Type").equals("simple")) {
|
||||||
|
SimpleVersioning sv = new SimpleVersioning();
|
||||||
|
JSONObject params = versioning.getJSONObject("Params");
|
||||||
|
sv.setParams(params.getInt("keep"));
|
||||||
|
r.Versioning = sv;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
r.Versioning = new Versioning();
|
||||||
|
}
|
||||||
|
|
||||||
|
ret.add(r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (JSONException e) {
|
||||||
|
Log.w(TAG, "Failed to read nodes", e);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a listener for the web gui becoming available..
|
||||||
|
*
|
||||||
|
* If the web gui is already available, listener will be called immediately.
|
||||||
|
* Listeners are unregistered automatically after being called.
|
||||||
|
*/
|
||||||
|
public void registerOnApiAvailableListener(OnApiAvailableListener listener) {
|
||||||
|
if (mConfig != null) {
|
||||||
|
listener.onApiAvailable();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
mOnApiAvailableListeners.addLast(listener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ import android.util.Log;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
|
|
||||||
import com.nutomic.syncthingandroid.R;
|
import com.nutomic.syncthingandroid.R;
|
||||||
import com.nutomic.syncthingandroid.gui.WebGuiActivity;
|
import com.nutomic.syncthingandroid.gui.MainActivity;
|
||||||
|
|
||||||
import org.apache.http.HttpResponse;
|
import org.apache.http.HttpResponse;
|
||||||
import org.apache.http.HttpStatus;
|
import org.apache.http.HttpStatus;
|
||||||
|
@ -104,7 +104,7 @@ public class SyncthingService extends Service {
|
||||||
public void onWebGuiAvailable();
|
public void onWebGuiAvailable();
|
||||||
}
|
}
|
||||||
|
|
||||||
private LinkedList<OnWebGuiAvailableListener> mOnWebGuiAvailableListeners =
|
private final LinkedList<OnWebGuiAvailableListener> mOnWebGuiAvailableListeners =
|
||||||
new LinkedList<OnWebGuiAvailableListener>();
|
new LinkedList<OnWebGuiAvailableListener>();
|
||||||
|
|
||||||
private boolean mIsWebGuiAvailable = false;
|
private boolean mIsWebGuiAvailable = false;
|
||||||
|
@ -292,10 +292,9 @@ public class SyncthingService extends Service {
|
||||||
* Creates notification, starts native binary.
|
* Creates notification, starts native binary.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
|
|
||||||
public void onCreate() {
|
public void onCreate() {
|
||||||
PendingIntent pi = PendingIntent.getActivity(
|
PendingIntent pi = PendingIntent.getActivity(
|
||||||
this, 0, new Intent(this, WebGuiActivity.class),
|
this, 0, new Intent(this, MainActivity.class),
|
||||||
PendingIntent.FLAG_UPDATE_CURRENT);
|
PendingIntent.FLAG_UPDATE_CURRENT);
|
||||||
Notification n = new NotificationCompat.Builder(this)
|
Notification n = new NotificationCompat.Builder(this)
|
||||||
.setContentTitle(getString(R.string.app_name))
|
.setContentTitle(getString(R.string.app_name))
|
||||||
|
@ -498,7 +497,7 @@ public class SyncthingService extends Service {
|
||||||
in = getResources().openRawResource(R.raw.config_default);
|
in = getResources().openRawResource(R.raw.config_default);
|
||||||
out = new FileOutputStream(getConfigFile());
|
out = new FileOutputStream(getConfigFile());
|
||||||
byte[] buff = new byte[1024];
|
byte[] buff = new byte[1024];
|
||||||
int read = 0;
|
int read;
|
||||||
|
|
||||||
while ((read = in.read(buff)) > 0) {
|
while ((read = in.read(buff)) > 0) {
|
||||||
out.write(buff, 0, read);
|
out.write(buff, 0, read);
|
||||||
|
|
|
@ -4,7 +4,7 @@ import android.os.Binder;
|
||||||
|
|
||||||
public class SyncthingServiceBinder extends Binder {
|
public class SyncthingServiceBinder extends Binder {
|
||||||
|
|
||||||
SyncthingService mService;
|
private final SyncthingService mService;
|
||||||
|
|
||||||
public SyncthingServiceBinder(SyncthingService service) {
|
public SyncthingServiceBinder(SyncthingService service) {
|
||||||
mService = service;
|
mService = service;
|
||||||
|
|
39
src/main/res/layout/loading_list_fragment.xml
Normal file
39
src/main/res/layout/loading_list_fragment.xml
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent" >
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/list_fragment"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:id="@+id/loading"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent" >
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/progress"
|
||||||
|
android:layout_centerInParent="true"
|
||||||
|
style="?android:attr/progressBarStyleLarge"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="10dip" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/loading_text"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_centerInParent="true"
|
||||||
|
android:layout_below="@id/progress"
|
||||||
|
android:text="@string/web_gui_loading" />
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
7
src/main/res/layout/main_activity.xml
Normal file
7
src/main/res/layout/main_activity.xml
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
|
<android.support.v4.view.ViewPager
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/pager"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent" />
|
17
src/main/res/layout/node_list_item.xml
Normal file
17
src/main/res/layout/node_list_item.xml
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="?android:attr/listPreferredItemHeight" >
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/name"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||||
|
android:lines="1"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:padding="4dip" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
17
src/main/res/layout/repository_list_item.xml
Normal file
17
src/main/res/layout/repository_list_item.xml
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="?android:attr/listPreferredItemHeight" >
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/id"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||||
|
android:lines="1"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:padding="4dip" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
|
@ -1,6 +1,10 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/web_gui"
|
||||||
|
android:title="@string/web_gui_title" />
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/settings"
|
android:id="@+id/settings"
|
||||||
android:title="@string/settings_title" />
|
android:title="@string/settings_title" />
|
||||||
|
|
|
@ -9,8 +9,25 @@
|
||||||
<!-- Text of the notification shown when a restart is needed -->
|
<!-- Text of the notification shown when a restart is needed -->
|
||||||
<string name="restart_notif_text">Click here to restart syncthing now</string>
|
<string name="restart_notif_text">Click here to restart syncthing now</string>
|
||||||
|
|
||||||
|
<!-- RepositoriesFragment -->
|
||||||
|
|
||||||
|
<string name="repositories_fragment_title">Repositories</string>
|
||||||
|
|
||||||
|
<!-- Shown if no repos exist -->
|
||||||
|
<string name="repositories_list_empty">No repositories found</string>
|
||||||
|
|
||||||
|
<!-- NodesFragment -->
|
||||||
|
|
||||||
|
<string name="nodes_fragment_title">Nodes</string>
|
||||||
|
|
||||||
|
<!-- Shown if no nodes exist -->
|
||||||
|
<string name="nodes_list_empty">No nodes found</string>
|
||||||
|
|
||||||
<!-- WebGuiActivity -->
|
<!-- WebGuiActivity -->
|
||||||
|
|
||||||
|
<!-- Title of the web gui activity -->
|
||||||
|
<string name="web_gui_title">Web GUI</string>
|
||||||
|
|
||||||
<!-- Text for WebGuiActivity loading view -->
|
<!-- Text for WebGuiActivity loading view -->
|
||||||
<string name="web_gui_loading">Waiting for GUI</string>
|
<string name="web_gui_loading">Waiting for GUI</string>
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue