SwapView base class so all swap views can just be XML

Almost all of the nearby/swap view classes could be condensed into a single
base class that is instantiated in the view XML.  This is the first step
towards making that happen.

It also lays the groundwork where "steps" are all SwapViews.  The
original concept of "steps" put all steps together, whether
F-Droid could control them or not.  For example, the Views were
mixed with the system Bluetooth prompts.  This is the first step
towards converting the steps to always be SwapViews, which are
always under control of this app.

When coming back to a SwapView/step, it does not seem feasible to handle
automatically restarting things like permissions and Bluetooth prompts. If
there is a way, it should be possible to first load the proper SwapView
instance, then trigger the system prompt.  The makes the SwapView a pure
View, without any Controller in it.
This commit is contained in:
Hans-Christoph Steiner 2018-08-07 13:38:16 +02:00
parent 6a8f5fb4a7
commit fe59522666
24 changed files with 280 additions and 559 deletions

View File

@ -15,7 +15,7 @@ import android.net.Uri;
import android.net.wifi.WifiManager;
import android.os.AsyncTask;
import android.os.IBinder;
import android.support.annotation.IntDef;
import android.support.annotation.LayoutRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.NotificationCompat;
@ -46,8 +46,6 @@ import rx.schedulers.Schedulers;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Collections;
@ -129,43 +127,21 @@ public class SwapService extends Service {
return peerFinder;
}
// ==========================================================
// Manage the current step
// ("Step" refers to the current view being shown in the UI)
// ==========================================================
public static final int STEP_INTRO = 1;
public static final int STEP_SELECT_APPS = 2;
public static final int STEP_JOIN_WIFI = 3;
public static final int STEP_SHOW_NFC = 4;
public static final int STEP_WIFI_QR = 5;
public static final int STEP_CONNECTING = 6;
public static final int STEP_SWAP_SUCCESS = 7;
public static final int STEP_CONFIRM_SWAP = 8;
/**
* Special view, that we don't really want to actually store against the
* {@link SwapService#step}. Rather, we use it for the purpose of specifying
* we are in the state waiting for the {@link SwapService} to get started and
* bound to the {@link SwapWorkflowActivity}.
*/
public static final int STEP_INITIAL_LOADING = 9;
@SwapStep
private int step = STEP_INTRO;
@LayoutRes
private int currentView = STEP_INTRO;
/**
* Current screen that the swap process is up to.
* Will be one of the SwapState.STEP_* values.
*/
@SwapStep
public int getStep() {
return step;
@LayoutRes
public int getCurrentView() {
return currentView;
}
public SwapService setStep(@SwapStep int step) {
this.step = step;
return this;
public void setCurrentView(@LayoutRes int currentView) {
this.currentView = currentView;
}
@NonNull
@ -269,18 +245,6 @@ public class SwapService extends Service {
return peerRepo;
}
/**
* Ensure that we don't get put into an incorrect state, by forcing people to pass valid
* states to setStep. Ideally this would be done by requiring an enum or something to
* be passed rather than in integer, however that is harder to persist on disk than an int.
* This is the same as, e.g. {@link Context#getSystemService(String)}
*/
@IntDef({STEP_INTRO, STEP_SELECT_APPS, STEP_JOIN_WIFI, STEP_SHOW_NFC, STEP_WIFI_QR,
STEP_CONNECTING, STEP_SWAP_SUCCESS, STEP_CONFIRM_SWAP, STEP_INITIAL_LOADING})
@Retention(RetentionPolicy.SOURCE)
public @interface SwapStep {
}
// =================================================
// Have selected a specific peer to swap with
// (Rather than showing a generic QR code to scan)

View File

@ -0,0 +1,76 @@
package org.fdroid.fdroid.localrepo;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.support.annotation.ColorInt;
import android.support.annotation.LayoutRes;
import android.util.AttributeSet;
import android.view.Menu;
import android.view.MenuInflater;
import android.widget.RelativeLayout;
import org.fdroid.fdroid.R;
import org.fdroid.fdroid.views.swap.SwapWorkflowActivity;
/**
* A {@link android.view.View} that registers to handle the swap events from
* {@link SwapService}.
*/
public class SwapView extends RelativeLayout {
public static final String TAG = "SwapView";
@ColorInt
public final int toolbarColor;
public final String toolbarTitle;
private int layoutResId;
public SwapView(Context context) {
this(context, null);
}
public SwapView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SwapView(Context context, AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
@TargetApi(21)
public SwapView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
final TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.SwapView, 0, 0);
toolbarColor = a.getColor(R.styleable.SwapView_toolbarColor,
getResources().getColor(R.color.swap_blue));
toolbarTitle = a.getString(R.styleable.SwapView_toolbarTitle);
a.recycle();
}
@Override
public boolean buildMenu(Menu menu, @NonNull MenuInflater inflater) {
return false;
}
@LayoutRes
public int getLayoutResId() {
return layoutResId;
}
public void setLayoutResId(@LayoutRes int layoutResId) {
this.layoutResId = layoutResId;
}
public SwapWorkflowActivity getActivity() {
return (SwapWorkflowActivity) getContext();
}
@ColorInt
public int getToolbarColour() {
return toolbarColor;
}
public String getToolbarTitle() {
return toolbarTitle;
}
}

View File

@ -2,19 +2,13 @@ package org.fdroid.fdroid.views.swap;
import android.annotation.TargetApi;
import android.content.Context;
import android.support.annotation.ColorRes;
import android.support.annotation.NonNull;
import android.util.AttributeSet;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.View;
import android.widget.RelativeLayout;
import android.widget.TextView;
import org.fdroid.fdroid.R;
import org.fdroid.fdroid.data.NewRepoConfig;
import org.fdroid.fdroid.localrepo.SwapService;
import org.fdroid.fdroid.localrepo.SwapView;
public class ConfirmReceiveView extends RelativeLayout implements SwapWorkflowActivity.InnerView {
public class ConfirmReceiveView extends SwapView {
private NewRepoConfig config;
@ -35,10 +29,6 @@ public class ConfirmReceiveView extends RelativeLayout implements SwapWorkflowAc
super(context, attrs, defStyleAttr, defStyleRes);
}
private SwapWorkflowActivity getActivity() {
return (SwapWorkflowActivity) getContext();
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
@ -58,34 +48,7 @@ public class ConfirmReceiveView extends RelativeLayout implements SwapWorkflowAc
});
}
@Override
public boolean buildMenu(Menu menu, @NonNull MenuInflater inflater) {
return true;
}
@Override
public int getStep() {
return SwapService.STEP_CONFIRM_SWAP;
}
@Override
public int getPreviousStep() {
return SwapService.STEP_INTRO;
}
@ColorRes
public int getToolbarColour() {
return R.color.swap_blue;
}
@Override
public String getToolbarTitle() {
return getResources().getString(R.string.swap_confirm);
}
public void setup(NewRepoConfig config) {
this.config = config;
TextView descriptionTextView = (TextView) findViewById(R.id.text_description);
descriptionTextView.setText(getResources().getString(R.string.swap_confirm_connect, config.getHost()));
}
}

View File

@ -5,23 +5,17 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.support.annotation.ColorRes;
import android.support.annotation.NonNull;
import android.support.v4.content.LocalBroadcastManager;
import android.util.AttributeSet;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
import org.fdroid.fdroid.R;
import org.fdroid.fdroid.UpdateService;
import org.fdroid.fdroid.localrepo.SwapService;
import org.fdroid.fdroid.localrepo.SwapView;
// TODO: Use this for the "Preparing local repo" dialog also.
public class ConnectingView extends LinearLayout implements SwapWorkflowActivity.InnerView {
public class ConnectingView extends SwapView {
@SuppressWarnings("unused")
private static final String TAG = "ConnectingView";
@ -44,10 +38,6 @@ public class ConnectingView extends LinearLayout implements SwapWorkflowActivity
super(context, attrs, defStyleAttr, defStyleRes);
}
private SwapWorkflowActivity getActivity() {
return (SwapWorkflowActivity) getContext();
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
@ -83,9 +73,9 @@ public class ConnectingView extends LinearLayout implements SwapWorkflowActivity
/**
* Listens for feedback about a local repository being prepared:
* * Apk files copied to the LocalHTTPD webroot
* * index.html file prepared
* * Icons will be copied to the webroot in the background and so are not part of this process.
* * Apk files copied to the LocalHTTPD webroot
* * index.html file prepared
* * Icons will be copied to the webroot in the background and so are not part of this process.
*/
class PrepareSwapReceiver extends Receiver {
@ -116,7 +106,7 @@ public class ConnectingView extends LinearLayout implements SwapWorkflowActivity
/**
* Listens for feedback about a repo update process taking place.
* * Tracks an index.jar download and show the progress messages
* Tracks an index.jar download and show the progress messages
*/
class ConnectSwapReceiver extends Receiver {
@ -146,7 +136,7 @@ public class ConnectingView extends LinearLayout implements SwapWorkflowActivity
@Override
protected void onComplete() {
getActivity().showSwapSuccess();
getActivity().inflateSwapView(R.layout.swap_success);
}
}
@ -165,8 +155,9 @@ public class ConnectingView extends LinearLayout implements SwapWorkflowActivity
public void onReceive(Context context, Intent intent) {
TextView progressText = (TextView) findViewById(R.id.heading);
TextView errorText = (TextView) findViewById(R.id.error);
Button backButton = (Button) findViewById(R.id.back);
ProgressBar progressBar = findViewById(R.id.progress_bar);
TextView errorText = (TextView) findViewById(R.id.error);
Button backButton = (Button) findViewById(R.id.back);
String message;
if (intent.hasExtra(getMessageExtra())) {
@ -177,11 +168,13 @@ public class ConnectingView extends LinearLayout implements SwapWorkflowActivity
}
progressText.setVisibility(View.VISIBLE);
progressBar.setVisibility(View.VISIBLE);
errorText.setVisibility(View.GONE);
backButton.setVisibility(View.GONE);
if (isError(intent)) {
progressText.setVisibility(View.GONE);
progressBar.setVisibility(View.GONE);
errorText.setVisibility(View.VISIBLE);
backButton.setVisibility(View.VISIBLE);
return;
@ -192,29 +185,4 @@ public class ConnectingView extends LinearLayout implements SwapWorkflowActivity
}
}
}
@Override
public boolean buildMenu(Menu menu, @NonNull MenuInflater inflater) {
return true;
}
@Override
public int getStep() {
return SwapService.STEP_CONNECTING;
}
@Override
public int getPreviousStep() {
return SwapService.STEP_SELECT_APPS;
}
@ColorRes
public int getToolbarColour() {
return R.color.swap_bright_blue;
}
@Override
public String getToolbarTitle() {
return getResources().getString(R.string.swap_connecting);
}
}

View File

@ -1,58 +0,0 @@
package org.fdroid.fdroid.views.swap;
import android.annotation.TargetApi;
import android.content.Context;
import android.support.annotation.ColorRes;
import android.support.annotation.NonNull;
import android.util.AttributeSet;
import android.view.Menu;
import android.view.MenuInflater;
import android.widget.RelativeLayout;
import org.fdroid.fdroid.R;
import org.fdroid.fdroid.localrepo.SwapService;
public class InitialLoadingView extends RelativeLayout implements SwapWorkflowActivity.InnerView {
public InitialLoadingView(Context context) {
super(context);
}
public InitialLoadingView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public InitialLoadingView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@TargetApi(21)
public InitialLoadingView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@Override
public boolean buildMenu(Menu menu, @NonNull MenuInflater inflater) {
return true;
}
@Override
public int getStep() {
return SwapService.STEP_INITIAL_LOADING;
}
@Override
public int getPreviousStep() {
return SwapService.STEP_JOIN_WIFI;
}
@ColorRes
public int getToolbarColour() {
return R.color.swap_blue;
}
@Override
public String getToolbarTitle() {
return getResources().getString(R.string.swap);
}
}

View File

@ -6,7 +6,6 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.wifi.WifiManager;
import android.support.annotation.ColorRes;
import android.support.annotation.NonNull;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v4.view.MenuItemCompat;
@ -17,14 +16,13 @@ import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import org.fdroid.fdroid.FDroidApp;
import org.fdroid.fdroid.R;
import org.fdroid.fdroid.localrepo.SwapService;
import org.fdroid.fdroid.localrepo.SwapView;
import org.fdroid.fdroid.net.WifiStateChangeService;
public class JoinWifiView extends RelativeLayout implements SwapWorkflowActivity.InnerView {
public class JoinWifiView extends SwapView {
public JoinWifiView(Context context) {
super(context);
@ -43,10 +41,6 @@ public class JoinWifiView extends RelativeLayout implements SwapWorkflowActivity
super(context, attrs, defStyleAttr, defStyleRes);
}
private SwapWorkflowActivity getActivity() {
return (SwapWorkflowActivity) getContext();
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
@ -115,33 +109,13 @@ public class JoinWifiView extends RelativeLayout implements SwapWorkflowActivity
next.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
getActivity().showSelectApps();
getActivity().inflateInnerView(R.layout.swap_select_apps);
return true;
}
});
return true;
}
@Override
public int getStep() {
return SwapService.STEP_JOIN_WIFI;
}
@Override
public int getPreviousStep() {
return SwapService.STEP_INTRO;
}
@ColorRes
public int getToolbarColour() {
return R.color.swap_blue;
}
@Override
public String getToolbarTitle() {
return getResources().getString(R.string.swap_join_same_wifi);
}
private final BroadcastReceiver onWifiStateChange = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {

View File

@ -2,7 +2,6 @@ package org.fdroid.fdroid.views.swap;
import android.annotation.TargetApi;
import android.content.Context;
import android.support.annotation.ColorRes;
import android.support.annotation.NonNull;
import android.support.v4.view.MenuItemCompat;
import android.util.AttributeSet;
@ -11,12 +10,11 @@ import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.RelativeLayout;
import org.fdroid.fdroid.Preferences;
import org.fdroid.fdroid.R;
import org.fdroid.fdroid.localrepo.SwapService;
import org.fdroid.fdroid.localrepo.SwapView;
public class NfcView extends RelativeLayout implements SwapWorkflowActivity.InnerView {
public class NfcView extends SwapView {
public NfcView(Context context) {
super(context);
@ -35,10 +33,6 @@ public class NfcView extends RelativeLayout implements SwapWorkflowActivity.Inne
super(context, attrs, defStyleAttr, defStyleRes);
}
private SwapWorkflowActivity getActivity() {
return (SwapWorkflowActivity) getContext();
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
@ -60,30 +54,10 @@ public class NfcView extends RelativeLayout implements SwapWorkflowActivity.Inne
next.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
getActivity().showWifiQr();
getActivity().inflateInnerView(R.layout.swap_wifi_qr);
return true;
}
});
return true;
}
@Override
public int getStep() {
return SwapService.STEP_SHOW_NFC;
}
@Override
public int getPreviousStep() {
return SwapService.STEP_JOIN_WIFI;
}
@ColorRes
public int getToolbarColour() {
return R.color.swap_blue;
}
@Override
public String getToolbarTitle() {
return getResources().getString(R.string.swap_nfc_title);
}
}

View File

@ -8,7 +8,6 @@ import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.ColorRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.LoaderManager;
@ -32,14 +31,13 @@ import android.widget.CompoundButton;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import org.fdroid.fdroid.R;
import org.fdroid.fdroid.data.InstalledAppProvider;
import org.fdroid.fdroid.data.Schema.InstalledAppTable;
import org.fdroid.fdroid.localrepo.SwapService;
import org.fdroid.fdroid.localrepo.SwapView;
public class SelectAppsView extends ListView implements
SwapWorkflowActivity.InnerView,
public class SelectAppsView extends SwapView implements
LoaderManager.LoaderCallbacks<Cursor>,
SearchView.OnQueryTextListener {
@ -60,33 +58,31 @@ public class SelectAppsView extends ListView implements
super(context, attrs, defStyleAttr, defStyleRes);
}
private SwapWorkflowActivity getActivity() {
return (SwapWorkflowActivity) getContext();
}
private SwapService getState() {
return getActivity().getState();
}
private static final int LOADER_INSTALLED_APPS = 253341534;
private ListView listView;
private AppListAdapter adapter;
private String currentFilterString;
@Override
protected void onFinishInflate() {
super.onFinishInflate();
adapter = new AppListAdapter(this, getContext(),
listView = findViewById(R.id.list);
adapter = new AppListAdapter(listView, getContext(),
getContext().getContentResolver().query(InstalledAppProvider.getContentUri(),
InstalledAppTable.Cols.ALL, null, null, null));
setAdapter(adapter);
setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
listView.setAdapter(adapter);
listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
// either reconnect with an existing loader or start a new one
getActivity().getSupportLoaderManager().initLoader(LOADER_INSTALLED_APPS, null, this);
setOnItemClickListener(new AdapterView.OnItemClickListener() {
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
toggleAppSelected(position);
}
@ -118,28 +114,6 @@ public class SelectAppsView extends ListView implements
return true;
}
@Override
public int getStep() {
return SwapService.STEP_SELECT_APPS;
}
@Override
public int getPreviousStep() {
// TODO: The STEP_JOIN_WIFI step isn't shown first, need to make it
// so that it is, or so that this doesn't go back there.
return getState().isConnectingWithPeer() ? SwapService.STEP_INTRO : SwapService.STEP_JOIN_WIFI;
}
@ColorRes
public int getToolbarColour() {
return R.color.swap_bright_blue;
}
@Override
public String getToolbarTitle() {
return getResources().getString(R.string.swap_choose_apps);
}
private void toggleAppSelected(int position) {
Cursor c = (Cursor) adapter.getItem(position);
String packageName = c.getString(c.getColumnIndex(InstalledAppTable.Cols.Package.NAME));
@ -174,13 +148,13 @@ public class SelectAppsView extends ListView implements
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
adapter.swapCursor(cursor);
for (int i = 0; i < getCount(); i++) {
Cursor c = (Cursor) getItemAtPosition(i);
for (int i = 0; i < listView.getCount(); i++) {
Cursor c = (Cursor) listView.getItemAtPosition(i);
String packageName = c.getString(c.getColumnIndex(InstalledAppTable.Cols.Package.NAME));
getState().ensureFDroidSelected();
for (String selected : getState().getAppsToSwap()) {
if (TextUtils.equals(packageName, selected)) {
setItemChecked(i, true);
listView.setItemChecked(i, true);
}
}
}

View File

@ -7,28 +7,23 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.LightingColorFilter;
import android.support.annotation.ColorRes;
import android.support.annotation.NonNull;
import android.support.v4.content.LocalBroadcastManager;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ScrollView;
import android.widget.TextView;
import org.fdroid.fdroid.FDroidApp;
import org.fdroid.fdroid.Preferences;
import org.fdroid.fdroid.QrGenAsyncTask;
import org.fdroid.fdroid.R;
import org.fdroid.fdroid.Utils;
import org.fdroid.fdroid.localrepo.SwapService;
import org.fdroid.fdroid.localrepo.SwapView;
import org.fdroid.fdroid.net.WifiStateChangeService;
import org.fdroid.fdroid.views.swap.device.camera.CameraCharacteristicsChecker;
public class SendFDroidView extends ScrollView implements SwapWorkflowActivity.InnerView {
public class SendFDroidView extends SwapView {
private static final String TAG = "SendFDroidView";
@ -49,10 +44,6 @@ public class SendFDroidView extends ScrollView implements SwapWorkflowActivity.I
super(context, attrs, defStyleAttr, defStyleRes);
}
private SwapWorkflowActivity getActivity() {
return (SwapWorkflowActivity) getContext();
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
@ -96,31 +87,6 @@ public class SendFDroidView extends ScrollView implements SwapWorkflowActivity.I
LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(onWifiStateChanged);
}
@Override
public boolean buildMenu(Menu menu, @NonNull MenuInflater inflater) {
return false;
}
@Override
public int getStep() {
return SwapService.STEP_INTRO;
}
@Override
public int getPreviousStep() {
return SwapService.STEP_INTRO;
}
@ColorRes
public int getToolbarColour() {
return R.color.swap_blue;
}
@Override
public String getToolbarTitle() {
return getResources().getString(R.string.swap_send_fdroid);
}
@SuppressLint("HardwareIds")
private void setUIFromWifi() {
if (TextUtils.isEmpty(FDroidApp.repo.address)) {

View File

@ -7,16 +7,12 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.wifi.WifiConfiguration;
import android.support.annotation.ColorRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.widget.SwitchCompat;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
@ -25,13 +21,13 @@ import android.widget.CompoundButton;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.TextView;
import cc.mvdan.accesspoint.WifiApControl;
import org.fdroid.fdroid.FDroidApp;
import org.fdroid.fdroid.R;
import org.fdroid.fdroid.Utils;
import org.fdroid.fdroid.localrepo.SwapService;
import org.fdroid.fdroid.localrepo.SwapView;
import org.fdroid.fdroid.localrepo.peers.Peer;
import org.fdroid.fdroid.net.WifiStateChangeService;
import rx.Subscriber;
@ -40,7 +36,7 @@ import rx.Subscription;
import java.util.ArrayList;
@SuppressWarnings("LineLength")
public class StartSwapView extends RelativeLayout implements SwapWorkflowActivity.InnerView {
public class StartSwapView extends SwapView {
private static final String TAG = "StartSwapView";
@ -58,7 +54,6 @@ public class StartSwapView extends RelativeLayout implements SwapWorkflowActivit
super(context, attrs);
}
@TargetApi(11)
public StartSwapView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@ -91,10 +86,6 @@ public class StartSwapView extends RelativeLayout implements SwapWorkflowActivit
}
private SwapWorkflowActivity getActivity() {
return (SwapWorkflowActivity) getContext();
}
private SwapService getManager() {
return getActivity().getState();
}
@ -456,35 +447,4 @@ public class StartSwapView extends RelativeLayout implements SwapWorkflowActivit
private void onPeerSelected(Peer peer) {
getActivity().swapWith(peer);
}
@Override
public boolean buildMenu(Menu menu, @NonNull MenuInflater inflater) {
return false;
}
@Override
public int getStep() {
return SwapService.STEP_INTRO;
}
@Override
public int getPreviousStep() {
// TODO: Currently this is handleed by the SwapWorkflowActivity as a special case, where
// if getStep is STEP_INTRO, don't even bother asking for getPreviousStep. But that is a
// bit messy. It would be nicer if this was handled using the same mechanism as everything
// else.
return SwapService.STEP_INTRO;
}
@Override
@ColorRes
public int getToolbarColour() {
return R.color.swap_bright_blue;
}
@Override
public String getToolbarTitle() {
return getResources().getString(R.string.swap_nearby);
}
}

View File

@ -12,7 +12,6 @@ import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.support.annotation.ColorRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.LoaderManager;
@ -47,7 +46,7 @@ import org.fdroid.fdroid.data.App;
import org.fdroid.fdroid.data.AppProvider;
import org.fdroid.fdroid.data.Repo;
import org.fdroid.fdroid.data.Schema.AppMetadataTable;
import org.fdroid.fdroid.localrepo.SwapService;
import org.fdroid.fdroid.localrepo.SwapView;
import org.fdroid.fdroid.net.Downloader;
import org.fdroid.fdroid.net.DownloaderService;
@ -55,8 +54,7 @@ import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
public class SwapSuccessView extends ListView implements
SwapWorkflowActivity.InnerView,
public class SwapSuccessView extends SwapView implements
LoaderManager.LoaderCallbacks<Cursor>,
SearchView.OnQueryTextListener {
@ -77,10 +75,6 @@ public class SwapSuccessView extends ListView implements
super(context, attrs, defStyleAttr, defStyleRes);
}
private SwapWorkflowActivity getActivity() {
return (SwapWorkflowActivity) getContext();
}
private static final int LOADER_SWAPABLE_APPS = 759283741;
private static final String TAG = "SwapAppsView";
@ -102,8 +96,8 @@ public class SwapSuccessView extends ListView implements
adapter = new AppListAdapter(getContext(), getContext().getContentResolver().query(
AppProvider.getRepoUri(repo), AppMetadataTable.Cols.ALL, null, null, null));
setAdapter(adapter);
ListView listView = findViewById(R.id.list);
listView.setAdapter(adapter);
// either reconnect with an existing loader or start a new one
getActivity().getSupportLoaderManager().initLoader(LOADER_SWAPABLE_APPS, null, this);
@ -163,26 +157,6 @@ public class SwapSuccessView extends ListView implements
return true;
}
@Override
public int getStep() {
return SwapService.STEP_SWAP_SUCCESS;
}
@Override
public int getPreviousStep() {
return SwapService.STEP_INTRO;
}
@ColorRes
public int getToolbarColour() {
return R.color.swap_bright_blue;
}
@Override
public String getToolbarTitle() {
return getResources().getString(R.string.swap_success);
}
@Override
public CursorLoader onCreateLoader(int id, Bundle args) {
Uri uri = TextUtils.isEmpty(currentFilterString)

View File

@ -17,7 +17,6 @@ import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.provider.Settings;
import android.support.annotation.ColorRes;
import android.support.annotation.LayoutRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
@ -28,9 +27,9 @@ import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;
import cc.mvdan.accesspoint.WifiApControl;
import com.google.zxing.integration.android.IntentIntegrator;
@ -48,6 +47,7 @@ import org.fdroid.fdroid.installer.InstallManagerService;
import org.fdroid.fdroid.installer.Installer;
import org.fdroid.fdroid.localrepo.LocalRepoManager;
import org.fdroid.fdroid.localrepo.SwapService;
import org.fdroid.fdroid.localrepo.SwapView;
import org.fdroid.fdroid.localrepo.peers.Peer;
import org.fdroid.fdroid.net.BluetoothDownloader;
import org.fdroid.fdroid.net.HttpDownloader;
@ -68,6 +68,7 @@ import java.util.TimerTask;
*/
@SuppressWarnings("LineLength")
public class SwapWorkflowActivity extends AppCompatActivity {
private static final String TAG = "SwapWorkflowActivity";
/**
* When connecting to a swap, we then go and initiate a connection with that
@ -87,28 +88,6 @@ public class SwapWorkflowActivity extends AppCompatActivity {
private ViewGroup container;
/**
* A UI component (subclass of {@link View}) which forms part of the swap workflow.
* There is a one to one mapping between an {@link org.fdroid.fdroid.views.swap.SwapWorkflowActivity.InnerView}
* and a {@link SwapService.SwapStep}, and these views know what
* the previous view before them should be.
*/
public interface InnerView {
/** @return True if the menu should be shown. */
boolean buildMenu(Menu menu, @NonNull MenuInflater inflater);
/** @return The step that this view represents. */
@SwapService.SwapStep int getStep();
@SwapService.SwapStep int getPreviousStep();
@ColorRes int getToolbarColour();
String getToolbarTitle();
}
private static final String TAG = "SwapWorkflowActivity";
private static final int CONNECT_TO_SWAP = 1;
private static final int REQUEST_BLUETOOTH_ENABLE_FOR_SWAP = 2;
private static final int REQUEST_BLUETOOTH_DISCOVERABLE = 3;
@ -116,7 +95,7 @@ public class SwapWorkflowActivity extends AppCompatActivity {
private static final int REQUEST_WRITE_SETTINGS_PERMISSION = 5;
private Toolbar toolbar;
private InnerView currentView;
private SwapView currentView;
private boolean hasPreparedLocalRepo;
private PrepareSwapRepo updateSwappableAppsTask;
private NewRepoConfig confirmSwapConfig;
@ -165,12 +144,50 @@ public class SwapWorkflowActivity extends AppCompatActivity {
@Override
public void onBackPressed() {
if (currentView.getStep() == SwapService.STEP_INTRO) {
SwapService.stop(this);
if (currentView.getLayoutResId() == SwapService.STEP_INTRO) {
SwapService.stop(this); // TODO SwapService should always be running, while swap is running
finish();
} else {
int nextStep = currentView.getPreviousStep();
getService().setStep(nextStep);
// TODO: Currently StartSwapView is handleed by the SwapWorkflowActivity as a special case, where
// if getLayoutResId is STEP_INTRO, don't even bother asking for getPreviousStep. But that is a
// bit messy. It would be nicer if this was handled using the same mechanism as everything
// else.
int nextStep = -1;
switch (currentView.getLayoutResId()) {
case R.layout.swap_confirm_receive:
nextStep = SwapService.STEP_INTRO;
break;
case R.layout.swap_connecting:
nextStep = R.layout.swap_select_apps;
break;
case R.layout.swap_initial_loading:
nextStep = R.layout.swap_join_wifi;
break;
case R.layout.swap_join_wifi:
nextStep = SwapService.STEP_INTRO;
break;
case R.layout.swap_nfc:
nextStep = R.layout.swap_join_wifi;
break;
case R.layout.swap_select_apps:
// TODO: The STEP_JOIN_WIFI step isn't shown first, need to make it
// so that it is, or so that this doesn't go back there.
nextStep = getState().isConnectingWithPeer() ? SwapService.STEP_INTRO : R.layout.swap_join_wifi;
break;
case R.layout.swap_send_fdroid:
nextStep = SwapService.STEP_INTRO;
break;
case R.layout.swap_start_swap:
nextStep = SwapService.STEP_INTRO;
break;
case R.layout.swap_success:
nextStep = SwapService.STEP_INTRO;
break;
case R.layout.swap_wifi_qr:
nextStep = R.layout.swap_join_wifi;
break;
}
getService().setCurrentView(nextStep);
showRelevantView();
}
}
@ -310,7 +327,7 @@ public class SwapWorkflowActivity extends AppCompatActivity {
private void showRelevantView(boolean forceReload) {
if (service == null) {
showInitialLoading();
inflateSwapView(R.layout.swap_initial_loading);
return;
}
@ -323,62 +340,50 @@ public class SwapWorkflowActivity extends AppCompatActivity {
return;
}
if (!forceReload && (container.getVisibility() == View.GONE || currentView != null && currentView.getStep() == service.getStep())) {
if (!forceReload && (container.getVisibility() == View.GONE || currentView != null && currentView.getLayoutResId() == service.getCurrentView())) {
// Already showing the correct step, so don't bother changing anything.
return;
}
switch (service.getStep()) {
int currentView = service.getCurrentView();
switch (currentView) {
case SwapService.STEP_INTRO:
showIntro();
return;
case R.layout.swap_nfc:
if (!attemptToShowNfc()) {
inflateSwapView(R.layout.swap_wifi_qr);
return;
}
break;
case SwapService.STEP_SELECT_APPS:
showSelectApps();
break;
case SwapService.STEP_SHOW_NFC:
showNfc();
break;
case SwapService.STEP_JOIN_WIFI:
showJoinWifi();
break;
case SwapService.STEP_WIFI_QR:
showWifiQr();
break;
case SwapService.STEP_SWAP_SUCCESS:
showSwapSuccess();
break;
case SwapService.STEP_CONNECTING:
case R.layout.swap_connecting:
// TODO: Properly decide what to do here (i.e. returning to the activity after it was connecting)...
inflateInnerView(R.layout.swap_start_swap);
break;
inflateSwapView(R.layout.swap_start_swap);
return;
}
inflateSwapView(currentView);
}
public SwapService getState() {
return service;
}
private void showNfc() {
if (!attemptToShowNfc()) {
showWifiQr();
}
}
private InnerView inflateInnerView(@LayoutRes int viewRes) {
public SwapView inflateSwapView(@LayoutRes int viewRes) {
container.removeAllViews();
View view = ((LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE)).inflate(viewRes, container, false);
currentView = (InnerView) view;
currentView = (SwapView) view;
currentView.setLayoutResId(viewRes);
// Don't actually set the step to STEP_INITIAL_LOADING, as we are going to use this view
// purely as a placeholder for _whatever view is meant to be shown_.
if (currentView.getStep() != SwapService.STEP_INITIAL_LOADING) {
if (currentView.getLayoutResId() != R.layout.swap_initial_loading) {
if (service == null) {
throw new IllegalStateException("We are not in the STEP_INITIAL_LOADING state, but the service is not ready.");
}
service.setStep(currentView.getStep());
service.setCurrentView(currentView.getLayoutResId());
}
toolbar.setBackgroundColor(getResources().getColor(currentView.getToolbarColour()));
toolbar.setBackgroundColor(currentView.getToolbarColour());
toolbar.setTitle(currentView.getToolbarTitle());
toolbar.setNavigationIcon(R.drawable.ic_close_white_24dp);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@ -398,10 +403,6 @@ public class SwapWorkflowActivity extends AppCompatActivity {
finish();
}
private void showInitialLoading() {
inflateInnerView(R.layout.swap_initial_loading);
}
public void showIntro() {
// If we were previously swapping with a specific client, forget that we were doing that,
// as we are starting over now.
@ -414,11 +415,13 @@ public class SwapWorkflowActivity extends AppCompatActivity {
}
}
inflateInnerView(R.layout.swap_start_swap);
inflateSwapView(R.layout.swap_start_swap);
}
private void showConfirmSwap(@NonNull NewRepoConfig config) {
((ConfirmReceive) inflateInnerView(R.layout.swap_confirm_receive)).setup(config);
((ConfirmReceiveView) inflateSwapView(R.layout.swap_confirm_receive)).setup(config);
TextView descriptionTextView = (TextView) findViewById(R.id.text_description);
descriptionTextView.setText(getResources().getString(R.string.swap_confirm_connect, config.getHost()));
}
public void startQrWorkflow() {
@ -435,14 +438,10 @@ public class SwapWorkflowActivity extends AppCompatActivity {
})
.create().show();
} else {
showWifiQr();
inflateSwapView(R.layout.swap_wifi_qr);
}
}
public void showSelectApps() {
inflateInnerView(R.layout.swap_select_apps);
}
/**
* On {@code android-26}, only apps with privileges can access
* {@code WRITE_SETTINGS}. So this just shows the tethering settings
@ -471,7 +470,7 @@ public class SwapWorkflowActivity extends AppCompatActivity {
if (adapter == null
|| Build.VERSION.SDK_INT >= 23 // TODO make Bluetooth work with content:// URIs
|| (!adapter.isEnabled() && getService().getWifiSwap().isConnected())) {
showSendFDroid();
inflateSwapView(R.layout.swap_send_fdroid);
} else {
sendFDroidBluetooth();
}
@ -503,8 +502,8 @@ public class SwapWorkflowActivity extends AppCompatActivity {
if (updateSwappableAppsTask == null && !hasPreparedLocalRepo) {
updateSwappableAppsTask = new PrepareSwapRepo(getService().getAppsToSwap());
updateSwappableAppsTask.execute();
getService().setStep(SwapService.STEP_CONNECTING);
inflateInnerView(R.layout.swap_connecting);
getService().setCurrentView(R.layout.swap_connecting);
inflateSwapView(R.layout.swap_connecting);
} else {
onLocalRepoPrepared();
}
@ -513,10 +512,10 @@ public class SwapWorkflowActivity extends AppCompatActivity {
/**
* Once the UpdateAsyncTask has finished preparing our repository index, we can
* show the next screen to the user. This will be one of two things:
* * If we directly selected a peer to swap with initially, we will skip straight to getting
* the list of apps from that device.
* * Alternatively, if we didn't have a person to connect to, and instead clicked "Scan QR Code",
* then we want to show a QR code or NFC dialog.
* * If we directly selected a peer to swap with initially, we will skip straight to getting
* the list of apps from that device.
* * Alternatively, if we didn't have a person to connect to, and instead clicked "Scan QR Code",
* then we want to show a QR code or NFC dialog.
*/
public void onLocalRepoPrepared() {
updateSwappableAppsTask = null;
@ -524,29 +523,13 @@ public class SwapWorkflowActivity extends AppCompatActivity {
if (getService().isConnectingWithPeer()) {
startSwappingWithPeer();
} else if (!attemptToShowNfc()) {
showWifiQr();
inflateSwapView(R.layout.swap_wifi_qr);
}
}
private void startSwappingWithPeer() {
getService().connectToPeer();
inflateInnerView(R.layout.swap_connecting);
}
private void showJoinWifi() {
inflateInnerView(R.layout.swap_join_wifi);
}
public void showWifiQr() {
inflateInnerView(R.layout.swap_wifi_qr);
}
public void showSendFDroid() {
inflateInnerView(R.layout.swap_send_fdroid);
}
public void showSwapSuccess() {
inflateInnerView(R.layout.swap_success);
inflateSwapView(R.layout.swap_connecting);
}
private boolean attemptToShowNfc() {
@ -559,7 +542,7 @@ public class SwapWorkflowActivity extends AppCompatActivity {
boolean nfcMessageReady = NfcHelper.setPushMessage(this, Utils.getSharingUri(FDroidApp.repo));
if (Preferences.get().showNfcDuringSwap() && nfcMessageReady) {
inflateInnerView(R.layout.swap_nfc);
inflateSwapView(R.layout.swap_nfc);
return true;
}
return false;
@ -567,20 +550,20 @@ public class SwapWorkflowActivity extends AppCompatActivity {
public void swapWith(Peer peer) {
getService().swapWith(peer);
showSelectApps();
inflateSwapView(R.layout.swap_select_apps);
}
/**
* This is for when we initiate a swap by viewing the "Are you sure you want to swap with" view
* This can arise either:
* * As a result of scanning a QR code (in which case we likely already have a repo setup) or
* * As a result of the other device selecting our device in the "start swap" screen, in which
* case we are likely just sitting on the start swap screen also, and haven't configured
* anything yet.
* * As a result of scanning a QR code (in which case we likely already have a repo setup) or
* * As a result of the other device selecting our device in the "start swap" screen, in which
* case we are likely just sitting on the start swap screen also, and haven't configured
* anything yet.
*/
public void swapWith(NewRepoConfig repoConfig) {
Peer peer = repoConfig.toPeer();
if (getService().getStep() == SwapService.STEP_INTRO || getService().getStep() == SwapService.STEP_CONFIRM_SWAP) {
if (getService().getCurrentView() == SwapService.STEP_INTRO || getService().getCurrentView() == R.layout.swap_confirm_receive) {
// This will force the "Select apps to swap" workflow to begin.
// TODO: Find a better way to decide whether we need to select the apps. Not sure if we
// can or cannot be in STEP_INTRO with a full blown repo ready to swap.
@ -784,15 +767,14 @@ public class SwapWorkflowActivity extends AppCompatActivity {
* the harder it becomes to reason about and debug the whole thing. Thus,this class
* will periodically dump the state to logcat so that it is easier to see when certain
* protocols are enabled/disabled.
*
* <p>
* To view only this output from logcat:
*
* adb logcat | grep 'Swap Status'
*
* <p>
* adb logcat | grep 'Swap Status'
* <p>
* To exclude this output from logcat (it is very noisy):
*
* adb logcat | grep -v 'Swap Status'
*
* <p>
* adb logcat | grep -v 'Swap Status'
*/
class SwapDebug {
@ -826,11 +808,11 @@ public class SwapWorkflowActivity extends AppCompatActivity {
Utils.debugLog("Swap Status", now.getHours() + ":" + now.getMinutes() + ":" + now.getSeconds() + " " + message);
new Timer().schedule(new TimerTask() {
@Override
public void run() {
new SwapDebug().logStatus();
}
}, 1000
@Override
public void run() {
new SwapDebug().logStatus();
}
}, 1000
);
}
}

View File

@ -7,31 +7,26 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.LightingColorFilter;
import android.net.Uri;
import android.support.annotation.ColorRes;
import android.support.annotation.NonNull;
import android.support.v4.content.LocalBroadcastManager;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ScrollView;
import android.widget.TextView;
import org.fdroid.fdroid.FDroidApp;
import org.fdroid.fdroid.Preferences;
import org.fdroid.fdroid.QrGenAsyncTask;
import org.fdroid.fdroid.R;
import org.fdroid.fdroid.Utils;
import org.fdroid.fdroid.localrepo.SwapService;
import org.fdroid.fdroid.localrepo.SwapView;
import org.fdroid.fdroid.net.WifiStateChangeService;
import org.fdroid.fdroid.views.swap.device.camera.CameraCharacteristicsChecker;
import java.util.Locale;
import java.util.Set;
public class WifiQrView extends ScrollView implements SwapWorkflowActivity.InnerView {
public class WifiQrView extends SwapView {
private static final String TAG = "WifiQrView";
@ -52,10 +47,6 @@ public class WifiQrView extends ScrollView implements SwapWorkflowActivity.Inner
super(context, attrs, defStyleAttr, defStyleRes);
}
private SwapWorkflowActivity getActivity() {
return (SwapWorkflowActivity) getContext();
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
@ -98,32 +89,6 @@ public class WifiQrView extends ScrollView implements SwapWorkflowActivity.Inner
LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(onWifiStateChanged);
}
@Override
public boolean buildMenu(Menu menu, @NonNull MenuInflater inflater) {
return false;
}
@Override
public int getStep() {
return SwapService.STEP_WIFI_QR;
}
@Override
public int getPreviousStep() {
// TODO: Find a way to make this optionally go back to the NFC screen if appropriate.
return SwapService.STEP_JOIN_WIFI;
}
@ColorRes
public int getToolbarColour() {
return R.color.swap_blue;
}
@Override
public String getToolbarTitle() {
return getResources().getString(R.string.swap_scan_qr);
}
private void setUIFromWifi() {
if (TextUtils.isEmpty(FDroidApp.repo.address)) {

View File

@ -3,6 +3,8 @@
<org.fdroid.fdroid.views.swap.ConfirmReceiveView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:swap="http://schemas.android.com/apk/res-auto"
swap:toolbarTitle="@string/swap_confirm"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"

View File

@ -2,7 +2,9 @@
<org.fdroid.fdroid.views.swap.ConnectingView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:swap="http://schemas.android.com/apk/res-auto"
swap:toolbarColor="@color/swap_bright_blue"
swap:toolbarTitle="@string/swap_connecting"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
@ -11,40 +13,40 @@
android:id="@+id/heading"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:textSize="20sp"
android:padding="30dp"
android:textAlignment="center"
android:gravity="center"
tools:text="Connecting with Nexus 4"
tools:ignore="UnusedAttribute"/>
android:gravity="center"/>
<ProgressBar
android:id="@+id/progress_bar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:indeterminate="true"
android:layout_gravity="center"/>
android:layout_centerInParent="true"
android:layout_below="@+id/heading"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:id="@+id/error"
android:textSize="20sp"
android:textAlignment="center"
android:gravity="center"
android:text="@string/swap_connection_misc_error"
android:visibility="gone"
android:padding="30dp"
tools:ignore="UnusedAttribute"/>
android:padding="30dp"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_below="@+id/error"
android:id="@+id/back"
android:backgroundTint="@color/swap_light_blue"
android:textColor="@android:color/white"
android:layout_gravity="center_horizontal"
android:visibility="gone"
android:text="@string/back"
tools:ignore="UnusedAttribute"/>
android:text="@string/back"/>
</org.fdroid.fdroid.views.swap.ConnectingView>

View File

@ -1,7 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<org.fdroid.fdroid.views.swap.InitialLoadingView
<org.fdroid.fdroid.localrepo.SwapView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:swap="http://schemas.android.com/apk/res-auto"
swap:toolbarTitle="@string/swap"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
@ -24,4 +26,4 @@
android:textColor="@android:color/white"
android:layout_centerHorizontal="true"/>
</org.fdroid.fdroid.views.swap.InitialLoadingView>
</org.fdroid.fdroid.localrepo.SwapView>

View File

@ -3,6 +3,8 @@
<org.fdroid.fdroid.views.swap.JoinWifiView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:swap="http://schemas.android.com/apk/res-auto"
swap:toolbarTitle="@string/swap_join_same_wifi"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"

View File

@ -2,6 +2,8 @@
<org.fdroid.fdroid.views.swap.NfcView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:swap="http://schemas.android.com/apk/res-auto"
swap:toolbarTitle="@string/swap_nfc_title"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"

View File

@ -2,8 +2,16 @@
<org.fdroid.fdroid.views.swap.SelectAppsView
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
xmlns:swap="http://schemas.android.com/apk/res-auto"
swap:toolbarColor="@color/swap_bright_blue"
swap:toolbarTitle="@string/swap_choose_apps"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"/>
</org.fdroid.fdroid.views.swap.SelectAppsView>

View File

@ -3,10 +3,13 @@
<org.fdroid.fdroid.views.swap.SendFDroidView
xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:swap="http://schemas.android.com/apk/res-auto"
swap:toolbarTitle="@string/swap_send_fdroid"
android:background="@color/swap_blue"
android:layout_height="match_parent"
android:layout_width="wrap_content">
<ScrollView android:layout_width="match_parent" android:layout_height="match_parent">
<LinearLayout android:orientation="vertical"
android:gravity="center"
android:layout_width="wrap_content"
@ -46,5 +49,5 @@
style="@style/SwapTheme.Wizard.QRScanWarningText"/>
</LinearLayout>
</ScrollView>
</org.fdroid.fdroid.views.swap.SendFDroidView>

View File

@ -7,6 +7,9 @@
<org.fdroid.fdroid.views.swap.StartSwapView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:swap="http://schemas.android.com/apk/res-auto"
swap:toolbarColor="@color/swap_bright_blue"
swap:toolbarTitle="@string/swap_nearby"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"

View File

@ -2,8 +2,16 @@
<org.fdroid.fdroid.views.swap.SwapSuccessView
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
xmlns:swap="http://schemas.android.com/apk/res-auto"
swap:toolbarColor="@color/swap_bright_blue"
swap:toolbarTitle="@string/swap_success"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"/>
</org.fdroid.fdroid.views.swap.SwapSuccessView>

View File

@ -3,10 +3,13 @@
<org.fdroid.fdroid.views.swap.WifiQrView
xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:swap="http://schemas.android.com/apk/res-auto"
swap:toolbarTitle="@string/swap_scan_qr"
android:background="@color/swap_blue"
android:layout_height="match_parent"
android:layout_width="wrap_content">
<ScrollView android:layout_width="match_parent" android:layout_height="match_parent">
<LinearLayout android:orientation="vertical"
android:gravity="center"
android:layout_width="wrap_content"
@ -53,5 +56,5 @@
style="@style/SwapTheme.Wizard.QRScanWarningText"/>
</LinearLayout>
</ScrollView>
</org.fdroid.fdroid.views.swap.WifiQrView>

View File

@ -3,4 +3,8 @@
<integer name="unhidePin">1337</integer>
<declare-styleable name="SwapView">
<attr name="toolbarColor" format="color"/>
<attr name="toolbarTitle" format="string"/>
</declare-styleable>
</resources>