Removed SwapAppListActivity, implemented UI mockup for swap app list.

Still need to hook up the buttons in the app list, but this change
shows the correct status and/or buttons for installable/upgradable/
incompatible/installed apps in the swap list. This change also hooks
up UIL to download icons for apps and thus display them in the list.
This commit is contained in:
Peter Serwylo 2015-07-13 00:31:13 +10:00
parent f236dc3d3e
commit a8dedd8ac2
15 changed files with 140 additions and 200 deletions

View File

@ -359,12 +359,12 @@
</activity>
<activity
android:name=".views.swap.SwapAppListActivity$SwapAppDetails"
android:name=".views.swap.SwapWorkflowActivity$SwapAppDetails"
android:label="@string/app_details"
android:parentActivityName=".views.swap.SwapAppListActivity" >
android:parentActivityName=".views.swap.SwapWorkflowActivity" >
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".views.swap.SwapAppListActivity" />
android:value=".views.swap.SwapWorkflowActivity" />
</activity>
<activity
android:label="@string/menu_preferences"
@ -385,17 +385,6 @@
android:name="android.support.PARENT_ACTIVITY"
android:value=".FDroid" />
</activity>
<activity
android:label="@string/swap"
android:name=".views.swap.SwapAppListActivity"
android:parentActivityName=".FDroid"
android:theme="@style/SwapTheme.AppList"
android:screenOrientation="portrait"
android:configChanges="orientation|keyboardHidden">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".FDroid" />
</activity>
<activity
android:name=".SearchResults"
android:label="@string/search_results"

View File

@ -16,30 +16,47 @@
android:layout_alignParentStart="true"
tools:src="@drawable/ic_launcher" />
<RelativeLayout
<LinearLayout
android:id="@+id/button_or_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerInParent="true"
android:orientation="vertical"
android:gravity="end"
android:layout_marginEnd="?android:attr/listPreferredItemPaddingEnd">
<Button
android:id="@+id/button"
android:id="@+id/btn_install"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:tint="@color/fdroid_green"
android:backgroundTint="@color/swap_light_blue"
android:textColor="@android:color/white"
tools:text="Install"/>
android:text="@string/menu_install"/>
<TextView
android:id="@+id/status"
android:id="@+id/status_installed"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/fdroid_green"
tools:text="Installed" />
android:textStyle="italic"
android:text="@string/inst" />
</RelativeLayout>
<TextView
android:id="@+id/status_incompatible"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textStyle="italic"
android:textColor="@color/swap_incompatible"
android:text="@string/incompatible" />
<TextView
android:id="@+id/btn_attempt_install"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/swap_light_blue"
android:text="@string/swap_attempt_install" />
</LinearLayout>
<TextView
android:id="@+id/name"

View File

@ -8,6 +8,7 @@
<color name="fdroid_blue_dark">#ff4b7195</color>
<color name="fdroid_green">#FFAAD024</color>
<color name="swap_incompatible">#ff7900</color>
<color name="swap_light_blue">#27aae1</color>
<color name="swap_light_blue_pressed">#ff98cce1</color>
<color name="swap_blue">#1c6bbc</color>

View File

@ -348,4 +348,5 @@
<string name="wifi_warning_private">Promising</string>
<string name="wifi_warning_personal">Best bet</string>
<string name="loading">Loading...</string>
<string name="swap_attempt_install">TRY TO INSTALL</string>
</resources>

View File

@ -23,6 +23,7 @@ import android.content.pm.PackageManager;
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
import android.graphics.Bitmap;
import android.net.Uri;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
@ -32,6 +33,9 @@ import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.util.Log;
import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.assist.ImageScaleType;
import com.nostra13.universalimageloader.core.display.FadeInBitmapDisplayer;
import com.nostra13.universalimageloader.utils.StorageUtils;
import org.fdroid.fdroid.compat.FileCompat;
@ -489,6 +493,17 @@ public final class Utils {
}
}
public static DisplayImageOptions.Builder getImageLoadingOptions() {
return new DisplayImageOptions.Builder()
.cacheInMemory(true)
.cacheOnDisk(true)
.imageScaleType(ImageScaleType.NONE)
.showImageOnLoading(R.drawable.ic_repo_app_default)
.showImageForEmptyUri(R.drawable.ic_repo_app_default)
.displayer(new FadeInBitmapDisplayer(200, true, true, false))
.bitmapConfig(Bitmap.Config.RGB_565);
}
// this is all new stuff being added
public static String hashBytes(byte[] input, String algo) {
try {

View File

@ -159,7 +159,7 @@ public class SwapService extends Service {
// Only ask server to swap with us, if we are actually running a local repo service.
// It is possible to have a swap initiated without first starting a swap, in which
// case swapping back is pointless.
if (isEnabled()) {
if (isEnabled() && requestSwapBack) {
askServerToSwapWithUs(peerRepo);
}

View File

@ -45,6 +45,11 @@ public class BluetoothPeer implements Peer {
return "";
}
@Override
public boolean shouldPromptForSwapBack() {
return false;
}
@Override
public int describeContents() {
return 0;

View File

@ -1,5 +1,6 @@
package org.fdroid.fdroid.localrepo.peers;
import android.net.Uri;
import android.os.Parcel;
import javax.jmdns.impl.FDroidServiceInfo;
@ -11,6 +12,8 @@ public class BonjourPeer extends WifiPeer {
public BonjourPeer(ServiceInfo serviceInfo) {
this.serviceInfo = new FDroidServiceInfo(serviceInfo);
this.name = serviceInfo.getDomain();
this.uri = Uri.parse(this.serviceInfo.getRepoAddress());
}
@Override

View File

@ -14,4 +14,6 @@ public interface Peer extends Parcelable {
String getRepoAddress();
String getFingerprint();
boolean shouldPromptForSwapBack();
}

View File

@ -10,18 +10,20 @@ public class WifiPeer implements Peer {
protected String name;
protected Uri uri;
protected boolean shouldPromptForSwapBack;
public WifiPeer() {
}
public WifiPeer(NewRepoConfig config) {
this(config.getRepoUri(), config.getHost());
this(config.getRepoUri(), config.getHost(), !config.preventFurtherSwaps());
}
protected WifiPeer(Uri uri, String name) {
protected WifiPeer(Uri uri, String name, boolean shouldPromptForSwapBack) {
this.name = name;
this.uri = uri;
this.shouldPromptForSwapBack = shouldPromptForSwapBack;
}
@Override
@ -44,6 +46,12 @@ public class WifiPeer implements Peer {
return uri.getQueryParameter("fingerprint");
}
@Override
public boolean shouldPromptForSwapBack() {
return shouldPromptForSwapBack;
}
@Override
public int describeContents() {
return 0;
@ -53,10 +61,11 @@ public class WifiPeer implements Peer {
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
dest.writeString(uri.toString());
dest.writeByte(shouldPromptForSwapBack ? (byte) 1 : (byte) 0);
}
protected WifiPeer(Parcel in) {
this(Uri.parse(in.readString()), in.readString());
this(Uri.parse(in.readString()), in.readString(), in.readByte() == 1);
}
public static final Creator<WifiPeer> CREATOR = new Creator<WifiPeer>() {

View File

@ -18,6 +18,7 @@ import com.nostra13.universalimageloader.core.display.FadeInBitmapDisplayer;
import org.fdroid.fdroid.Preferences;
import org.fdroid.fdroid.R;
import org.fdroid.fdroid.Utils;
import org.fdroid.fdroid.data.App;
abstract public class AppListAdapter extends CursorAdapter {
@ -50,15 +51,7 @@ abstract public class AppListAdapter extends CursorAdapter {
mContext = context;
mInflater = (LayoutInflater) mContext.getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
displayImageOptions = new DisplayImageOptions.Builder()
.cacheInMemory(true)
.cacheOnDisk(true)
.imageScaleType(ImageScaleType.NONE)
.showImageOnLoading(R.drawable.ic_repo_app_default)
.showImageForEmptyUri(R.drawable.ic_repo_app_default)
.displayer(new FadeInBitmapDisplayer(200, true, true, false))
.bitmapConfig(Bitmap.Config.RGB_565)
.build();
displayImageOptions = Utils.getImageLoadingOptions().build();
}

View File

@ -1,137 +0,0 @@
package org.fdroid.fdroid.views.swap;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.support.annotation.Nullable;
import android.support.v4.app.NavUtils;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import org.fdroid.fdroid.AppDetails;
import org.fdroid.fdroid.R;
import org.fdroid.fdroid.data.AppProvider;
import org.fdroid.fdroid.data.Repo;
import org.fdroid.fdroid.data.RepoProvider;
import org.fdroid.fdroid.views.AppListAdapter;
import org.fdroid.fdroid.views.AvailableAppListAdapter;
import org.fdroid.fdroid.views.fragments.AppListFragment;
public class SwapAppListActivity extends ActionBarActivity {
private static final String TAG = "SwapAppListActivity";
public static final String EXTRA_REPO_ID = "repoId";
private Repo repo;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState == null) {
// Necessary to run on an Android 2.3.[something] device.
new Handler().post(new Runnable() {
@Override
public void run() {
getSupportFragmentManager()
.beginTransaction()
.add(android.R.id.content, new SwapAppListFragment())
.commit();
}
});
}
}
@Override
protected void onResume() {
super.onResume();
long repoAddress = getIntent().getLongExtra(EXTRA_REPO_ID, -1);
repo = RepoProvider.Helper.findById(this, repoAddress);
if (repo == null) {
Log.e(TAG, "Couldn't show swap app list for repo " + repoAddress);
finish();
}
}
public Repo getRepo() {
return repo;
}
public static class SwapAppListFragment extends AppListFragment {
private Repo repo;
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
repo = ((SwapAppListActivity)activity).getRepo();
}
@Override
protected int getHeaderLayout() {
return R.layout.swap_success_header;
}
@Override
protected AppListAdapter getAppListAdapter() {
return new AvailableAppListAdapter(getActivity(), null);
}
@Nullable
@Override
protected String getEmptyMessage() {
return getActivity().getString(R.string.empty_swap_app_list);
}
@Override
protected String getFromTitle() {
return getString(R.string.swap);
}
@Override
protected Uri getDataUri() {
return AppProvider.getRepoUri(repo);
}
protected Intent getAppDetailsIntent() {
Intent intent = new Intent(getActivity(), SwapAppDetails.class);
intent.putExtra(EXTRA_REPO_ID, repo.getId());
return intent;
}
}
/**
* Only difference from base class is that it navigates up to a different task.
* It will go to the {@link org.fdroid.fdroid.views.swap.SwapAppListActivity}
* whereas the baseclass will go back to the main list of apps. Need to juggle
* the repoId in order to be able to return to an appropriately configured swap
* list (see {@link org.fdroid.fdroid.views.swap.SwapAppListActivity.SwapAppListFragment#getAppDetailsIntent()}).
*/
public static class SwapAppDetails extends AppDetails {
private long repoId;
@Override
protected void onResume() {
super.onResume();
repoId = getIntent().getLongExtra(EXTRA_REPO_ID, -1);
}
@Override
protected void navigateUp() {
Intent parentIntent = NavUtils.getParentActivityIntent(this);
parentIntent.putExtra(EXTRA_REPO_ID, repoId);
NavUtils.navigateUpTo(this, parentIntent);
}
}
}

View File

@ -32,9 +32,13 @@ import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
import org.fdroid.fdroid.ProgressListener;
import org.fdroid.fdroid.R;
import org.fdroid.fdroid.UpdateService;
import org.fdroid.fdroid.Utils;
import org.fdroid.fdroid.data.App;
import org.fdroid.fdroid.data.AppProvider;
import org.fdroid.fdroid.data.Repo;
@ -48,6 +52,8 @@ public class SwapAppsView extends ListView implements
LoaderManager.LoaderCallbacks<Cursor>,
SearchView.OnQueryTextListener {
private DisplayImageOptions displayImageOptions;
public SwapAppsView(Context context) {
super(context);
}
@ -104,6 +110,8 @@ public class SwapAppsView extends ListView implements
}
});
displayImageOptions = Utils.getImageLoadingOptions().build();
schedulePollForUpdates();
}
@ -279,46 +287,45 @@ public class SwapAppsView extends ListView implements
TextView nameView = (TextView)view.findViewById(R.id.name);
ImageView iconView = (ImageView)view.findViewById(android.R.id.icon);
Button button = (Button)view.findViewById(R.id.button);
TextView status = (TextView)view.findViewById(R.id.status);
Button btnInstall = (Button)view.findViewById(R.id.btn_install);
TextView btnAttemptInstall = (TextView)view.findViewById(R.id.btn_attempt_install);
TextView statusInstalled = (TextView)view.findViewById(R.id.status_installed);
TextView statusIncompatible = (TextView)view.findViewById(R.id.status_incompatible);
final App app = new App(cursor);
nameView.setText(app.name);
iconView.setImageDrawable(getDefaultAppIcon(context)); // TODO: Load icon from repo properly using UIL.
ImageLoader.getInstance().displayImage(app.iconUrl, iconView, displayImageOptions);
btnInstall.setVisibility(View.GONE);
btnAttemptInstall.setVisibility(View.GONE);
statusInstalled.setVisibility(View.GONE);
statusIncompatible.setVisibility(View.GONE);
if (app.hasUpdates()) {
button.setText(R.string.menu_upgrade);
button.setEnabled(true);
button.setBackgroundColor(getResources().getColor(R.color.fdroid_blue));
button.setVisibility(View.VISIBLE);
status.setVisibility(View.GONE);
btnInstall.setText(R.string.menu_upgrade);
btnInstall.setVisibility(View.VISIBLE);
} else if (app.isInstalled()) {
status.setText(R.string.inst);
status.setTextColor(getResources().getColor(R.color.fdroid_green));
status.setVisibility(View.VISIBLE);
button.setVisibility(View.GONE);
statusInstalled.setVisibility(View.VISIBLE);
} else if (!app.compatible) {
status.setText(R.string.incompatible);
status.setTextColor(getResources().getColor(R.color.swap_light_grey_icon));
status.setVisibility(View.VISIBLE);
button.setVisibility(View.GONE);
btnAttemptInstall.setVisibility(View.VISIBLE);
statusIncompatible.setVisibility(View.VISIBLE);
} else {
button.setText(R.string.menu_install);
button.setEnabled(true);
button.setBackgroundColor(getResources().getColor(R.color.fdroid_green));
button.setVisibility(View.VISIBLE);
status.setVisibility(View.GONE);
btnInstall.setText(R.string.menu_install);
btnInstall.setVisibility(View.VISIBLE);
}
button.setOnClickListener(new OnClickListener() {
OnClickListener installListener = new OnClickListener() {
@Override
public void onClick(View v) {
if (app.hasUpdates() || app.compatible) {
getState().install(app);
}
}
});
};
btnInstall.setOnClickListener(installListener);
btnAttemptInstall.setOnClickListener(installListener);
}
}

View File

@ -61,10 +61,10 @@ public class SwapConnecting extends LinearLayout implements SwapWorkflowActivity
return;
}
String heading = getContext().getString(R.string.status_connecting_to_repo, getActivity().getState().getPeer().getName());
String heading = getContext().getString(R.string.status_connecting_to_repo, peer.getName());
((TextView) findViewById(R.id.heading)).setText(heading);
UpdateService.UpdateReceiver receiver = getManager().connectTo(peer, true);
UpdateService.UpdateReceiver receiver = getManager().connectTo(peer, peer.shouldPromptForSwapBack());
receiver.hideDialog();
receiver.setListener(new ProgressListener() {

View File

@ -14,6 +14,7 @@ import android.support.annotation.ColorRes;
import android.support.annotation.LayoutRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.NavUtils;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
@ -27,6 +28,7 @@ import android.widget.Toast;
import com.google.zxing.integration.android.IntentIntegrator;
import com.google.zxing.integration.android.IntentResult;
import org.fdroid.fdroid.AppDetails;
import org.fdroid.fdroid.FDroidApp;
import org.fdroid.fdroid.NfcHelper;
import org.fdroid.fdroid.Preferences;
@ -41,6 +43,11 @@ import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
/**
* This activity will do its best to show the most relevant screen about swapping to the user.
* The problem comes when there are two competing goals - 1) Show the user a list of apps from another
* device to download and install, and 2) Prepare your own list of apps to share.
*/
public class SwapWorkflowActivity extends AppCompatActivity {
/**
@ -52,6 +59,7 @@ public class SwapWorkflowActivity extends AppCompatActivity {
*/
public static final String EXTRA_PREVENT_FURTHER_SWAP_REQUESTS = "preventFurtherSwap";
public static final String EXTRA_CONFIRM = "EXTRA_CONFIRM";
public static final String EXTRA_REPO_ID = "repoId";
private ViewGroup container;
@ -213,6 +221,9 @@ public class SwapWorkflowActivity extends AppCompatActivity {
case SwapService.STEP_WIFI_QR:
showWifiQr();
break;
case SwapService.STEP_SUCCESS:
showSwapConnected();
break;
}
}
@ -375,9 +386,7 @@ public class SwapWorkflowActivity extends AppCompatActivity {
*/
public void swapWith(NewRepoConfig repoConfig) {
getService().swapWith(repoConfig.toPeer());
if (!repoConfig.preventFurtherSwaps()) {
startSwappingWithPeer();
}
startSwappingWithPeer();
}
public void denySwap() {
@ -504,4 +513,30 @@ public class SwapWorkflowActivity extends AppCompatActivity {
}
}
/**
* Only difference from base class is that it navigates up to a different task.
* It will go to the {@link org.fdroid.fdroid.views.swap.SwapWorkflowActivity}
* whereas the base-class will go back to the main list of apps. Need to juggle
* the repoId in order to be able to return to an appropriately configured swap
* list.
*/
public static class SwapAppDetails extends AppDetails {
private long repoId;
@Override
protected void onResume() {
super.onResume();
repoId = getIntent().getLongExtra(EXTRA_REPO_ID, -1);
}
@Override
protected void navigateUp() {
Intent parentIntent = NavUtils.getParentActivityIntent(this);
parentIntent.putExtra(EXTRA_REPO_ID, repoId);
NavUtils.navigateUpTo(this, parentIntent);
}
}
}