Add loading dialog on API load (after start or restart).

ref #47
This commit is contained in:
Felix Ableitner 2014-06-24 18:02:38 +02:00
parent d0e7f57812
commit 9d041d0bb3
12 changed files with 210 additions and 246 deletions

View File

@ -1,125 +0,0 @@
/*
* 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.ListFragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.TextView;
import com.nutomic.syncthingandroid.R;
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
SyncthingService.OnApiAvailableListener, AdapterView.OnItemClickListener {
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 (getActivity() != null &&
activity.getApi() != null && mListFragment != null) {
onInitAdapter(activity);
getListView().setOnItemClickListener(this);
}
}
/**
* Called when the list adapter should be set.
*/
public abstract void onInitAdapter(MainActivity activity);
public ListView getListView() {
return mListFragment.getListView();
}
}

View File

@ -26,7 +26,7 @@ import java.util.TimerTask;
*/ */
public class LocalNodeInfoFragment extends Fragment public class LocalNodeInfoFragment extends Fragment
implements RestApi.OnReceiveSystemInfoListener, RestApi.OnReceiveConnectionsListener, implements RestApi.OnReceiveSystemInfoListener, RestApi.OnReceiveConnectionsListener,
SyncthingService.OnApiAvailableListener { SyncthingService.OnApiChangeListener {
private TextView mNodeId; private TextView mNodeId;
@ -97,7 +97,10 @@ public class LocalNodeInfoFragment extends Fragment
} }
@Override @Override
public void onApiAvailable() { public void onApiChange(boolean isAvailable) {
if (!isAvailable)
return;
updateGui(); updateGui();
} }

View File

@ -1,8 +1,10 @@
package com.nutomic.syncthingandroid.gui; package com.nutomic.syncthingandroid.gui;
import android.annotation.SuppressLint;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.content.ServiceConnection; import android.content.ServiceConnection;
import android.content.res.Configuration; import android.content.res.Configuration;
@ -19,8 +21,13 @@ import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBar.Tab; import android.support.v7.app.ActionBar.Tab;
import android.support.v7.app.ActionBar.TabListener; import android.support.v7.app.ActionBar.TabListener;
import android.support.v7.app.ActionBarActivity; import android.support.v7.app.ActionBarActivity;
import android.view.LayoutInflater;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.nutomic.syncthingandroid.R; import com.nutomic.syncthingandroid.R;
import com.nutomic.syncthingandroid.syncthing.RestApi; import com.nutomic.syncthingandroid.syncthing.RestApi;
@ -32,7 +39,7 @@ import com.nutomic.syncthingandroid.syncthing.SyncthingServiceBinder;
* {@link LocalNodeInfoFragment} in the navigation drawer. * {@link LocalNodeInfoFragment} in the navigation drawer.
*/ */
public class MainActivity extends ActionBarActivity public class MainActivity extends ActionBarActivity
implements SyncthingService.OnWebGuiAvailableListener { implements SyncthingService.OnApiChangeListener {
private SyncthingService mSyncthingService; private SyncthingService mSyncthingService;
@ -41,7 +48,10 @@ public class MainActivity extends ActionBarActivity
public void onServiceConnected(ComponentName className, IBinder service) { public void onServiceConnected(ComponentName className, IBinder service) {
SyncthingServiceBinder binder = (SyncthingServiceBinder) service; SyncthingServiceBinder binder = (SyncthingServiceBinder) service;
mSyncthingService = binder.getService(); mSyncthingService = binder.getService();
mSyncthingService.registerOnWebGuiAvailableListener(MainActivity.this); mSyncthingService.registerOnApiChangeListener(MainActivity.this);
mSyncthingService.registerOnApiChangeListener(mRepositoriesFragment);
mSyncthingService.registerOnApiChangeListener(mNodesFragment);
mSyncthingService.registerOnApiChangeListener(mLocalNodeInfoFragment);
} }
public void onServiceDisconnected(ComponentName className) { public void onServiceDisconnected(ComponentName className) {
@ -49,14 +59,32 @@ public class MainActivity extends ActionBarActivity
} }
}; };
private AlertDialog mLoadingDialog;
/** /**
* Causes population of repo and node lists, unlocks info drawer. * Causes population of repo and node lists, unlocks info drawer.
*/ */
@Override @Override
public void onWebGuiAvailable() { @SuppressLint("InflateParams")
mSyncthingService.registerOnApiAvailableListener(mRepositoriesFragment); public void onApiChange(boolean isAvailable) {
mSyncthingService.registerOnApiAvailableListener(mNodesFragment); if (!isAvailable) {
mSyncthingService.registerOnApiAvailableListener(mLocalNodeInfoFragment); LayoutInflater inflater = getLayoutInflater();
View dialogLayout = inflater.inflate(R.layout.loading_dialog, null);
TextView loadingText = (TextView) dialogLayout.findViewById(R.id.loading_text);
loadingText.setText((SyncthingService.isFirstStart(this)
? R.string.web_gui_creating_key
: R.string.api_loading));
mLoadingDialog = new AlertDialog.Builder(this)
.setCancelable(false)
.setView(dialogLayout)
.show();
return;
}
if (mLoadingDialog != null) {
mLoadingDialog.dismiss();
}
mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED); mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
mDrawerLayout.setDrawerListener(mDrawerToggle); mDrawerLayout.setDrawerListener(mDrawerToggle);
getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setDisplayHomeAsUpEnabled(true);
@ -170,13 +198,15 @@ public class MainActivity extends ActionBarActivity
.commit(); .commit();
mDrawerToggle = mLocalNodeInfoFragment.new Toggle(this, mDrawerLayout, mDrawerToggle = mLocalNodeInfoFragment.new Toggle(this, mDrawerLayout,
R.drawable.ic_drawer); R.drawable.ic_drawer);
mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
} }
@Override @Override
public void onDestroy() { public void onDestroy() {
super.onDestroy(); super.onDestroy();
unbindService(mSyncthingServiceConnection); unbindService(mSyncthingServiceConnection);
if (mLoadingDialog != null) {
mLoadingDialog.dismiss();
}
} }
/** /**
@ -209,7 +239,7 @@ public class MainActivity extends ActionBarActivity
public boolean onPrepareOptionsMenu(Menu menu) { public boolean onPrepareOptionsMenu(Menu menu) {
boolean drawerOpen = mDrawerLayout.isDrawerOpen(findViewById(R.id.drawer)); boolean drawerOpen = mDrawerLayout.isDrawerOpen(findViewById(R.id.drawer));
menu.findItem(R.id.share_node_id).setVisible(drawerOpen); menu.findItem(R.id.share_node_id).setVisible(drawerOpen);
return mSyncthingService != null && mSyncthingService.isWebGuiAvailable(); return true;
} }
@Override @Override

View File

@ -28,7 +28,7 @@ import java.util.Map;
*/ */
public class NodeSettingsActivity extends PreferenceActivity implements public class NodeSettingsActivity extends PreferenceActivity implements
Preference.OnPreferenceChangeListener, Preference.OnPreferenceClickListener, Preference.OnPreferenceChangeListener, Preference.OnPreferenceClickListener,
RestApi.OnReceiveConnectionsListener, SyncthingService.OnApiAvailableListener { RestApi.OnReceiveConnectionsListener, SyncthingService.OnApiChangeListener {
public static final String ACTION_CREATE = "create"; public static final String ACTION_CREATE = "create";
@ -43,7 +43,7 @@ public class NodeSettingsActivity extends PreferenceActivity implements
public void onServiceConnected(ComponentName className, IBinder service) { public void onServiceConnected(ComponentName className, IBinder service) {
SyncthingServiceBinder binder = (SyncthingServiceBinder) service; SyncthingServiceBinder binder = (SyncthingServiceBinder) service;
mSyncthingService = binder.getService(); mSyncthingService = binder.getService();
mSyncthingService.registerOnApiAvailableListener(NodeSettingsActivity.this); mSyncthingService.registerOnApiChangeListener(NodeSettingsActivity.this);
} }
public void onServiceDisconnected(ComponentName className) { public void onServiceDisconnected(ComponentName className) {
@ -89,7 +89,12 @@ public class NodeSettingsActivity extends PreferenceActivity implements
} }
@Override @Override
public void onApiAvailable() { public void onApiChange(boolean isAvailable) {
if (!isAvailable) {
finish();
return;
}
if (getIntent().getAction().equals(ACTION_CREATE)) { if (getIntent().getAction().equals(ACTION_CREATE)) {
setTitle(R.string.create_node); setTitle(R.string.create_node);
mNode = new RestApi.Node(); mNode = new RestApi.Node();

View File

@ -1,7 +1,11 @@
package com.nutomic.syncthingandroid.gui; package com.nutomic.syncthingandroid.gui;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.ListFragment;
import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView; import android.widget.AdapterView;
import android.widget.ListView; import android.widget.ListView;
@ -15,31 +19,52 @@ import java.util.TimerTask;
/** /**
* Displays a list of all existing nodes. * Displays a list of all existing nodes.
*/ */
public class NodesFragment extends LoadingListFragment implements public class NodesFragment extends ListFragment implements SyncthingService.OnApiChangeListener,
SyncthingService.OnApiAvailableListener, ListView.OnItemClickListener { ListView.OnItemClickListener {
private NodesAdapter mAdapter; private NodesAdapter mAdapter;
private Timer mTimer; private Timer mTimer;
private boolean mInitialized = false; @Override
public void onResume() {
super.onResume();
setListShown(true);
}
@Override @Override
public void onInitAdapter(MainActivity activity) { public void onApiChange(boolean isAvailable) {
if (!isAvailable)
return;
initAdapter();
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
initAdapter();
}
private void initAdapter() {
MainActivity activity = (MainActivity) getActivity();
if (activity == null || activity.getApi() == null)
return;
mAdapter = new NodesAdapter(activity); mAdapter = new NodesAdapter(activity);
mAdapter.add(activity.getApi().getNodes()); mAdapter.add(activity.getApi().getNodes());
setListAdapter(mAdapter, R.string.nodes_list_empty); setListAdapter(mAdapter);
mInitialized = true; setEmptyText(getString(R.string.nodes_list_empty));
getListView().setOnItemClickListener(this);
} }
private void updateList() { private void updateList() {
if (!mInitialized) if (mAdapter == null || getView() == null)
return; return;
MainActivity activity = (MainActivity) getActivity(); MainActivity activity = (MainActivity) getActivity();
if (activity != null) { mAdapter.updateConnections(activity.getApi(), getListView());
mAdapter.updateConnections(activity.getApi(), getListView());
}
} }
@Override @Override

View File

@ -31,7 +31,7 @@ import java.util.List;
*/ */
public class RepoSettingsActivity extends PreferenceActivity public class RepoSettingsActivity extends PreferenceActivity
implements Preference.OnPreferenceChangeListener, Preference.OnPreferenceClickListener, implements Preference.OnPreferenceChangeListener, Preference.OnPreferenceClickListener,
SyncthingService.OnApiAvailableListener { SyncthingService.OnApiChangeListener {
public static final String ACTION_CREATE = "create"; public static final String ACTION_CREATE = "create";
@ -48,7 +48,7 @@ public class RepoSettingsActivity extends PreferenceActivity
public void onServiceConnected(ComponentName className, IBinder service) { public void onServiceConnected(ComponentName className, IBinder service) {
SyncthingServiceBinder binder = (SyncthingServiceBinder) service; SyncthingServiceBinder binder = (SyncthingServiceBinder) service;
mSyncthingService = binder.getService(); mSyncthingService = binder.getService();
mSyncthingService.registerOnApiAvailableListener(RepoSettingsActivity.this); mSyncthingService.registerOnApiChangeListener(RepoSettingsActivity.this);
} }
public void onServiceDisconnected(ComponentName className) { public void onServiceDisconnected(ComponentName className) {
@ -97,7 +97,12 @@ public class RepoSettingsActivity extends PreferenceActivity
} }
@Override @Override
public void onApiAvailable() { public void onApiChange(boolean isAvailable) {
if (!isAvailable) {
finish();
return;
}
if (getIntent().getAction().equals(ACTION_CREATE)) { if (getIntent().getAction().equals(ACTION_CREATE)) {
setTitle(R.string.create_repo); setTitle(R.string.create_repo);
mRepo = new RestApi.Repository(); mRepo = new RestApi.Repository();

View File

@ -1,7 +1,11 @@
package com.nutomic.syncthingandroid.gui; package com.nutomic.syncthingandroid.gui;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.ListFragment;
import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView; import android.widget.AdapterView;
import com.nutomic.syncthingandroid.R; import com.nutomic.syncthingandroid.R;
@ -14,31 +18,52 @@ import java.util.TimerTask;
/** /**
* Displays a list of all existing repositories. * Displays a list of all existing repositories.
*/ */
public class ReposFragment extends LoadingListFragment implements public class ReposFragment extends ListFragment implements SyncthingService.OnApiChangeListener,
SyncthingService.OnApiAvailableListener, AdapterView.OnItemClickListener { AdapterView.OnItemClickListener {
private ReposAdapter mAdapter; private ReposAdapter mAdapter;
private Timer mTimer; private Timer mTimer;
private boolean mInitialized = false; @Override
public void onResume() {
super.onResume();
setListShown(true);
}
@Override @Override
public void onInitAdapter(MainActivity activity) { public void onApiChange(boolean isAvailable) {
if (!isAvailable)
return;
initAdapter();
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
initAdapter();
}
private void initAdapter() {
MainActivity activity = (MainActivity) getActivity();
if (activity == null || activity.getApi() == null)
return;
mAdapter = new ReposAdapter(activity); mAdapter = new ReposAdapter(activity);
mAdapter.add(activity.getApi().getRepos()); mAdapter.add(activity.getApi().getRepos());
setListAdapter(mAdapter, R.string.repositories_list_empty); setListAdapter(mAdapter);
mInitialized = true; setEmptyText(getString(R.string.repositories_list_empty));
getListView().setOnItemClickListener(this);
} }
private void updateList() { private void updateList() {
if (!mInitialized) if (mAdapter == null || getView() == null)
return; return;
MainActivity activity = (MainActivity) getActivity(); MainActivity activity = (MainActivity) getActivity();
if (activity != null) { mAdapter.updateModel(activity.getApi(), getListView());
mAdapter.updateModel(activity.getApi(), getListView());
}
} }
@Override @Override

View File

@ -24,7 +24,7 @@ import com.nutomic.syncthingandroid.syncthing.SyncthingService;
import com.nutomic.syncthingandroid.syncthing.SyncthingServiceBinder; import com.nutomic.syncthingandroid.syncthing.SyncthingServiceBinder;
public class SettingsActivity extends PreferenceActivity public class SettingsActivity extends PreferenceActivity
implements Preference.OnPreferenceChangeListener { implements SyncthingService.OnApiChangeListener, Preference.OnPreferenceChangeListener {
private static final String SYNCTHING_OPTIONS_KEY = "syncthing_options"; private static final String SYNCTHING_OPTIONS_KEY = "syncthing_options";
@ -48,23 +48,7 @@ public class SettingsActivity extends PreferenceActivity
public void onServiceConnected(ComponentName className, IBinder service) { public void onServiceConnected(ComponentName className, IBinder service) {
SyncthingServiceBinder binder = (SyncthingServiceBinder) service; SyncthingServiceBinder binder = (SyncthingServiceBinder) service;
mSyncthingService = binder.getService(); mSyncthingService = binder.getService();
mVersion.setSummary(mSyncthingService.getApi().getVersion()); mSyncthingService.registerOnApiChangeListener(SettingsActivity.this);
for (int i = 0; i < mOptionsScreen.getPreferenceCount(); i++) {
Preference pref = mOptionsScreen.getPreference(i);
pref.setOnPreferenceChangeListener(SettingsActivity.this);
String value = mSyncthingService.getApi()
.getValue(RestApi.TYPE_OPTIONS, pref.getKey());
applyPreference(pref, value);
}
for (int i = 0; i < mGuiScreen.getPreferenceCount(); i++) {
Preference pref = mGuiScreen.getPreference(i);
pref.setOnPreferenceChangeListener(SettingsActivity.this);
String value = mSyncthingService.getApi()
.getValue(RestApi.TYPE_GUI, pref.getKey());
applyPreference(pref, value);
}
} }
public void onServiceDisconnected(ComponentName className) { public void onServiceDisconnected(ComponentName className) {
@ -72,6 +56,33 @@ public class SettingsActivity extends PreferenceActivity
} }
}; };
@Override
public void onApiChange(boolean isAvailable) {
if (!isAvailable) {
finish();
return;
}
mVersion.setSummary(mSyncthingService.getApi().getVersion());
for (int i = 0; i < mOptionsScreen.getPreferenceCount(); i++) {
Preference pref = mOptionsScreen.getPreference(i);
pref.setOnPreferenceChangeListener(SettingsActivity.this);
String value = mSyncthingService.getApi()
.getValue(RestApi.TYPE_OPTIONS, pref.getKey());
applyPreference(pref, value);
}
for (int i = 0; i < mGuiScreen.getPreferenceCount(); i++) {
Preference pref = mGuiScreen.getPreference(i);
pref.setOnPreferenceChangeListener(SettingsActivity.this);
String value = mSyncthingService.getApi()
.getValue(RestApi.TYPE_GUI, pref.getKey());
applyPreference(pref, value);
}
}
/** /**
* Applies the given value to the preference. * Applies the given value to the preference.
* *

View File

@ -209,12 +209,12 @@ public class RestApi implements SyncthingService.OnWebGuiAvailableListener {
/** /**
* Increments mAvailableCount by one, and, if it reached TOTAL_STARTUP_CALLS, * Increments mAvailableCount by one, and, if it reached TOTAL_STARTUP_CALLS,
* calls {@link SyncthingService#onApiAvailable()}. * calls {@link SyncthingService#onApiChange(boolean)}.
*/ */
private void tryIsAvailable() { private void tryIsAvailable() {
int value = mAvailableCount.incrementAndGet(); int value = mAvailableCount.incrementAndGet();
if (value == TOTAL_STARTUP_CALLS) { if (value == TOTAL_STARTUP_CALLS) {
mSyncthingService.onApiAvailable(); mSyncthingService.onApiChange(true);
} }
} }

View File

@ -32,7 +32,9 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.util.LinkedList; import java.util.HashSet;
import java.util.Iterator;
import java.util.concurrent.ConcurrentSkipListSet;
import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantLock;
/** /**
@ -95,22 +97,25 @@ public class SyncthingService extends Service {
public void onWebGuiAvailable(); public void onWebGuiAvailable();
} }
private final LinkedList<OnWebGuiAvailableListener> mOnWebGuiAvailableListeners = private final ReentrantLock mOnWebGuiAvailableListenersLock = new ReentrantLock();
new LinkedList<OnWebGuiAvailableListener>();
private final HashSet<OnWebGuiAvailableListener> mOnWebGuiAvailableListeners =
new HashSet<OnWebGuiAvailableListener>();
private boolean mIsWebGuiAvailable = false; private boolean mIsWebGuiAvailable = false;
public interface OnApiAvailableListener { public interface OnApiChangeListener {
public void onApiAvailable(); public void onApiChange(boolean isAvailable);
} }
private final LinkedList<WeakReference<OnApiAvailableListener>> mOnApiAvailableListeners = private final HashSet<WeakReference<OnApiChangeListener>> mOnApiAvailableListeners =
new LinkedList<WeakReference<OnApiAvailableListener>>(); new HashSet<WeakReference<OnApiChangeListener>>();
@Override @Override
public int onStartCommand(Intent intent, int flags, int startId) { public int onStartCommand(Intent intent, int flags, int startId) {
if (intent != null && ACTION_RESTART.equals(intent.getAction())) { if (intent != null && ACTION_RESTART.equals(intent.getAction())) {
mIsWebGuiAvailable = false; mIsWebGuiAvailable = false;
onApiChange(false);
new PostTask() { new PostTask() {
@Override @Override
protected void onPostExecute(Void aVoid) { protected void onPostExecute(Void aVoid) {
@ -377,7 +382,7 @@ public class SyncthingService extends Service {
listener.onWebGuiAvailable(); listener.onWebGuiAvailable();
} }
else { else {
mOnWebGuiAvailableListeners.addLast(listener); mOnWebGuiAvailableListeners.add(listener);
} }
} }
@ -429,34 +434,29 @@ public class SyncthingService extends Service {
} }
/** /**
* Register a listener for the syncthing API becoming available.. * Register a listener for the syncthing API state changing.
* *
* If the API is already available, listener will be called immediately. * The listener is called immediately with the current state, and again whenever the state
* * changes.
* Listeners are kept around (as weak reference) and called again after any configuration
* changes to allow a data refresh.
*/ */
public void registerOnApiAvailableListener(OnApiAvailableListener listener) { public void registerOnApiChangeListener(OnApiChangeListener listener) {
if (mApi.isApiAvailable()) { listener.onApiChange((mApi != null) ? mApi.isApiAvailable() : false);
listener.onApiAvailable(); mOnApiAvailableListeners.add(new WeakReference<OnApiChangeListener>(listener));
}
else {
mOnApiAvailableListeners.addLast(new WeakReference<OnApiAvailableListener>(listener));
}
} }
/** /**
* Called by {@link RestApi} once it is fully initialized. * Called when the state of the API changes.
* *
* Must not be called from anywhere else. * Must only be called from SyncthingService or {@link RestApi}.
*/ */
public void onApiAvailable() { public void onApiChange(boolean isAvailable) {
for (WeakReference<OnApiAvailableListener> listener : mOnApiAvailableListeners) { for (Iterator<WeakReference<OnApiChangeListener>> i = mOnApiAvailableListeners.iterator(); i.hasNext();) {
WeakReference<OnApiChangeListener> listener = i.next();
if (listener.get() != null) { if (listener.get() != null) {
listener.get().onApiAvailable(); listener.get().onApiChange(isAvailable);
} }
else { else {
mOnApiAvailableListeners.remove(listener); i.remove();
} }
} }
} }

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_gravity="center"
android:padding="10dip"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<ProgressBar
style="?android:attr/progressBarStyleLarge"
android:id="@+id/progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/loading_text"
android:layout_toRightOf="@id/progress"
android:layout_alignBottom="@id/progress"
android:layout_alignTop="@id/progress"
android:gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>

View File

@ -1,39 +0,0 @@
<?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/api_loading" />
</RelativeLayout>
</LinearLayout>