Merge branch 'new-ui--minor-ui-tweaks' into 'master'

Minor ui tweaks

Closes #896, #894, and #839

See merge request !453
This commit is contained in:
Peter Serwylo 2017-03-26 07:32:16 +00:00
commit befdc4a850
25 changed files with 212 additions and 102 deletions

3
.gitignore vendored
View File

@ -43,3 +43,6 @@ extern/*/*/libs/
# Tests
junit-report.xml
# Screen dumps from Android Studio/DDMS
captures/

View File

@ -107,7 +107,6 @@ public class AppDetails extends AppCompatActivity {
private static final int REQUEST_PERMISSION_DIALOG = 3;
private static final int REQUEST_UNINSTALL_DIALOG = 4;
public static final String EXTRA_APPID = "appid";
public static final String EXTRA_FROM = "from";
public static final String EXTRA_HINT_SEARCHING = "searching";
@ -351,12 +350,12 @@ public class AppDetails extends AppCompatActivity {
* and not externally.
*/
private String getPackageNameFromIntent(Intent intent) {
if (!intent.hasExtra(EXTRA_APPID)) {
if (!intent.hasExtra(AppDetails2.EXTRA_APPID)) {
Log.e(TAG, "No package name found in the intent!");
return null;
}
return intent.getStringExtra(EXTRA_APPID);
return intent.getStringExtra(AppDetails2.EXTRA_APPID);
}
@Override

View File

@ -53,6 +53,7 @@ import org.fdroid.fdroid.views.apps.FeatureImage;
public class AppDetails2 extends AppCompatActivity implements ShareChooserDialog.ShareChooserDialogListener, AppDetailsRecyclerViewAdapter.AppDetailsRecyclerViewAdapterCallbacks {
public static final String EXTRA_APPID = "appid";
private static final String TAG = "AppDetails2";
private static final int REQUEST_ENABLE_BLUETOOTH = 2;
@ -170,11 +171,11 @@ public class AppDetails2 extends AppCompatActivity implements ShareChooserDialog
}
private String getPackageNameFromIntent(Intent intent) {
if (!intent.hasExtra(AppDetails.EXTRA_APPID)) {
if (!intent.hasExtra(EXTRA_APPID)) {
Log.e(TAG, "No package name found in the intent!");
return null;
}
return intent.getStringExtra(AppDetails.EXTRA_APPID);
return intent.getStringExtra(EXTRA_APPID);
}
/**

View File

@ -392,16 +392,16 @@ public final class AppUpdateStatusManager {
/**
* Get a {@link PendingIntent} for a {@link Notification} to send when it
* is clicked. {@link AppDetails} handles {@code Intent}s that are missing
* or bad {@link AppDetails#EXTRA_APPID}, so it does not need to be checked
* is clicked. {@link AppDetails2} handles {@code Intent}s that are missing
* or bad {@link AppDetails2#EXTRA_APPID}, so it does not need to be checked
* here.
*/
private PendingIntent getAppDetailsIntent(Apk apk) {
Intent notifyIntent = new Intent(context, AppDetails.class)
.putExtra(AppDetails.EXTRA_APPID, apk.packageName);
Intent notifyIntent = new Intent(context, AppDetails2.class)
.putExtra(AppDetails2.EXTRA_APPID, apk.packageName);
return TaskStackBuilder.create(context)
.addParentStack(AppDetails.class)
.addParentStack(AppDetails2.class)
.addNextIntent(notifyIntent)
.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
}

View File

@ -12,6 +12,7 @@ import org.fdroid.fdroid.data.App;
import org.fdroid.fdroid.data.AppProvider;
import org.fdroid.fdroid.data.Schema;
import org.fdroid.fdroid.installer.ApkCache;
import org.fdroid.fdroid.installer.InstallManagerService;
import java.util.ArrayList;
import java.util.List;
@ -53,5 +54,6 @@ public class AppUpdateStatusService extends IntentService {
}
AppUpdateStatusManager.getInstance(this).addApks(apksReadyToInstall, AppUpdateStatusManager.Status.ReadyToInstall);
InstallManagerService.managePreviouslyDownloadedApks(this);
}
}

View File

@ -243,7 +243,7 @@ public class FDroid extends AppCompatActivity implements SearchView.OnQueryTextL
if (!TextUtils.isEmpty(packageName)) {
Utils.debugLog(TAG, "FDroid launched via app link for '" + packageName + "'");
Intent intentToInvoke = new Intent(this, AppDetails2.class);
intentToInvoke.putExtra(AppDetails.EXTRA_APPID, packageName);
intentToInvoke.putExtra(AppDetails2.EXTRA_APPID, packageName);
startActivity(intentToInvoke);
finish();
} else if (!TextUtils.isEmpty(query)) {

View File

@ -185,7 +185,7 @@ class NotificationHelper {
if (entry.status == AppUpdateStatusManager.Status.Unknown) {
return true;
} else if ((entry.status == AppUpdateStatusManager.Status.Downloading || entry.status == AppUpdateStatusManager.Status.ReadyToInstall || entry.status == AppUpdateStatusManager.Status.InstallError) &&
(AppDetails.isAppVisible(entry.app.packageName) || AppDetails2.isAppVisible(entry.app.packageName))) {
AppDetails2.isAppVisible(entry.app.packageName)) {
// Ignore downloading, readyToInstall and installError if we are showing the details screen for this app
return true;
}

View File

@ -68,6 +68,16 @@ public class InstallManagerService extends Service {
private static final String ACTION_INSTALL = "org.fdroid.fdroid.installer.action.INSTALL";
private static final String ACTION_CANCEL = "org.fdroid.fdroid.installer.action.CANCEL";
/**
* The install manager service needs to monitor downloaded apks so that it can wait for a user to
* install them and respond accordingly. Usually the thing which starts listening for such events
* does so directly after a download is complete. This works great, except when the user then
* subsequently closes F-Droid and opens it at a later date. Under these circumstances, a background
* service will scan all downloaded apks and notify the user about them. When it does so, the
* install manager service needs to add listeners for if the apks get installed.
*/
private static final String ACTION_MANAGE_DOWNLOADED_APKS = "org.fdroid.fdroid.installer.action.ACTION_MANAGE_DOWNLOADED_APKS";
private static final String EXTRA_APP = "org.fdroid.fdroid.installer.extra.APP";
private static final String EXTRA_APK = "org.fdroid.fdroid.installer.extra.APK";
@ -108,13 +118,19 @@ public class InstallManagerService extends Service {
public int onStartCommand(Intent intent, int flags, int startId) {
Utils.debugLog(TAG, "onStartCommand " + intent);
String action = intent.getAction();
if (ACTION_MANAGE_DOWNLOADED_APKS.equals(action)) {
registerInstallerReceiversForDownlaodedApks();
return START_NOT_STICKY;
}
String urlString = intent.getDataString();
if (TextUtils.isEmpty(urlString)) {
Utils.debugLog(TAG, "empty urlString, nothing to do");
return START_NOT_STICKY;
}
String action = intent.getAction();
if (ACTION_CANCEL.equals(action)) {
DownloaderService.cancel(this, urlString);
Apk apk = appUpdateStatusManager.getApk(urlString);
@ -292,6 +308,20 @@ public class InstallManagerService extends Service {
DownloaderService.getIntentFilter(urlString));
}
/**
* For each app in the {@link AppUpdateStatusManager.Status#ReadyToInstall} state, setup listeners
* so that if the user installs it then we can respond accordingly. This makes sure that whether
* the user just finished downloading it, or whether they downloaded it a day ago but have not yet
* installed it, we get the same experience upon completing an install.
*/
private void registerInstallerReceiversForDownlaodedApks() {
for (AppUpdateStatusManager.AppUpdateStatus appStatus : AppUpdateStatusManager.getInstance(this).getAll()) {
if (appStatus.status == AppUpdateStatusManager.Status.ReadyToInstall) {
registerInstallerReceivers(Uri.parse(appStatus.getUniqueKey()));
}
}
}
private void registerInstallerReceivers(Uri downloadUri) {
BroadcastReceiver installReceiver = new BroadcastReceiver() {
@ -363,4 +393,10 @@ public class InstallManagerService extends Service {
intent.setData(Uri.parse(urlString));
context.startService(intent);
}
public static void managePreviouslyDownloadedApks(Context context) {
Intent intent = new Intent(context, InstallManagerService.class);
intent.setAction(ACTION_MANAGE_DOWNLOADED_APKS);
context.startService(intent);
}
}

View File

@ -26,6 +26,7 @@ public class AppListActivity extends AppCompatActivity implements LoaderManager.
public static final String EXTRA_CATEGORY = "org.fdroid.fdroid.views.apps.AppListActivity.EXTRA_CATEGORY";
public static final String EXTRA_SEARCH_TERMS = "org.fdroid.fdroid.views.apps.AppListActivity.EXTRA_SEARCH_TERMS";
private RecyclerView appView;
private AppListAdapter appAdapter;
private String category;
@ -78,12 +79,11 @@ public class AppListActivity extends AppCompatActivity implements LoaderManager.
appView.setHasFixedSize(true);
appView.setLayoutManager(new LinearLayoutManager(this));
appView.setAdapter(appAdapter);
parseIntentForSearchQuery();
}
@Override
protected void onResume() {
super.onResume();
private void parseIntentForSearchQuery() {
Intent intent = getIntent();
category = intent.hasExtra(EXTRA_CATEGORY) ? intent.getStringExtra(EXTRA_CATEGORY) : null;
searchTerms = intent.hasExtra(EXTRA_SEARCH_TERMS) ? intent.getStringExtra(EXTRA_SEARCH_TERMS) : null;

View File

@ -29,7 +29,6 @@ import android.widget.TextView;
import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
import org.fdroid.fdroid.AppDetails;
import org.fdroid.fdroid.AppDetails2;
import org.fdroid.fdroid.AppUpdateStatusManager;
import org.fdroid.fdroid.R;
@ -254,6 +253,18 @@ public class AppListItemController extends RecyclerView.ViewHolder {
return false;
}
/**
* Queries the {@link AppUpdateStatusManager} and asks if the app was just successfully installed.
*/
private boolean wasSuccessfullyInstalled(@NonNull App app) {
for (AppUpdateStatusManager.AppUpdateStatus appStatus : AppUpdateStatusManager.getInstance(activity).getByPackageName(app.packageName)) {
if (appStatus.status == AppUpdateStatusManager.Status.Installed) {
return true;
}
}
return false;
}
/**
* The app name {@link TextView} is used for a few reasons:
* * Display name + summary of the app (most common).
@ -277,6 +288,8 @@ public class AppListItemController extends RecyclerView.ViewHolder {
}
} else if (isDownloading(app)) {
name.setText(activity.getString(R.string.app_list__name__downloading_in_progress, app.name));
} else if (wasSuccessfullyInstalled(app)) {
name.setText(activity.getString(R.string.app_list__name__successfully_installed, app.name));
} else {
name.setText(Utils.formatAppNameAndSummary(app.name, app.summary));
}
@ -396,7 +409,7 @@ public class AppListItemController extends RecyclerView.ViewHolder {
}
Intent intent = new Intent(activity, AppDetails2.class);
intent.putExtra(AppDetails.EXTRA_APPID, currentApp.packageName);
intent.putExtra(AppDetails2.EXTRA_APPID, currentApp.packageName);
if (Build.VERSION.SDK_INT >= 21) {
Pair<View, String> iconTransitionPair = Pair.create((View) icon, activity.getString(R.string.transition_app_item_icon));
Bundle bundle = ActivityOptionsCompat.makeSceneTransitionAnimation(activity, iconTransitionPair).toBundle();

View File

@ -22,7 +22,6 @@ import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.assist.FailReason;
import com.nostra13.universalimageloader.core.listener.ImageLoadingListener;
import org.fdroid.fdroid.AppDetails;
import org.fdroid.fdroid.AppDetails2;
import org.fdroid.fdroid.R;
import org.fdroid.fdroid.Utils;
@ -129,7 +128,7 @@ public class AppCardController extends RecyclerView.ViewHolder implements ImageL
}
Intent intent = new Intent(activity, AppDetails2.class);
intent.putExtra(AppDetails.EXTRA_APPID, currentApp.packageName);
intent.putExtra(AppDetails2.EXTRA_APPID, currentApp.packageName);
if (Build.VERSION.SDK_INT >= 21) {
Pair<View, String> iconTransitionPair = Pair.create((View) icon, activity.getString(R.string.transition_app_item_icon));

View File

@ -169,7 +169,7 @@ public abstract class AppListFragment extends ListFragment implements
if (cursor != null) {
final App app = new App(cursor);
Intent intent = getAppDetailsIntent(useNewDetailsActivity);
intent.putExtra(AppDetails.EXTRA_APPID, app.packageName);
intent.putExtra(AppDetails2.EXTRA_APPID, app.packageName);
intent.putExtra(AppDetails.EXTRA_FROM, getFromTitle());
if (Build.VERSION.SDK_INT >= 21) {
Pair<View, String> iconTransitionPair = Pair.create(view.findViewById(R.id.icon),

View File

@ -13,12 +13,13 @@ import android.preference.PreferenceCategory;
import android.support.v4.preference.PreferenceFragment;
import android.text.TextUtils;
import org.fdroid.fdroid.AppDetails;
import org.fdroid.fdroid.AppDetails2;
import org.fdroid.fdroid.CleanCacheService;
import org.fdroid.fdroid.FDroidApp;
import org.fdroid.fdroid.Preferences;
import org.fdroid.fdroid.PreferencesActivity;
import org.fdroid.fdroid.R;
import org.fdroid.fdroid.UpdateService;
import org.fdroid.fdroid.installer.InstallHistoryService;
import org.fdroid.fdroid.installer.PrivilegedInstaller;
@ -261,8 +262,8 @@ public class PreferencesFragment extends PreferenceFragment
@Override
public boolean onPreferenceClick(Preference preference) {
// Open details of F-Droid Privileged
Intent intent = new Intent(getActivity(), AppDetails.class);
intent.putExtra(AppDetails.EXTRA_APPID,
Intent intent = new Intent(getActivity(), AppDetails2.class);
intent.putExtra(AppDetails2.EXTRA_APPID,
PrivilegedInstaller.PRIVILEGED_EXTENSION_PACKAGE_NAME);
startActivity(intent);
@ -271,21 +272,34 @@ public class PreferencesFragment extends PreferenceFragment
});
}
@Override
public void onResume() {
super.onResume();
/**
* If a user specifies they want to fetch updates automatically, then start the download of relevant
* updates as soon as they enable the feature.
* Also, if the user has the priv extention installed then change the label to indicate that it
* will actually _install_ apps, not just fetch their .apk file automatically.
*/
private void initAutoFetchUpdatesPreference() {
updateAutoDownloadPref.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
if (newValue instanceof Boolean && (boolean) newValue) {
UpdateService.autoDownloadUpdates(getContext());
}
return true;
}
});
for (final String key : SUMMARIES_TO_UPDATE) {
updateSummary(key, false);
if (PrivilegedInstaller.isDefault(getContext())) {
updateAutoDownloadPref.setTitle(R.string.update_auto_install);
updateAutoDownloadPref.setSummary(R.string.update_auto_install_summary);
}
}
currentKeepCacheTime = Preferences.get().getKeepCacheTime();
initPrivilegedInstallerPreference();
initUpdatePrivilegedExtensionPreference();
// this pref's default is dynamically set based on whether Orbot is installed
/**
* The default for "Use Tor" is dynamically set based on whether Orbot is installed.
*/
private void initUseTorPreference() {
boolean useTor = Preferences.get().isTorEnabled();
useTorCheckPref.setDefaultValue(useTor);
useTorCheckPref.setChecked(useTor);
@ -308,11 +322,24 @@ public class PreferencesFragment extends PreferenceFragment
return true;
}
});
}
if (PrivilegedInstaller.isDefault(getContext())) {
updateAutoDownloadPref.setTitle(R.string.update_auto_install);
updateAutoDownloadPref.setSummary(R.string.update_auto_install_summary);
@Override
public void onResume() {
super.onResume();
getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
for (final String key : SUMMARIES_TO_UPDATE) {
updateSummary(key, false);
}
currentKeepCacheTime = Preferences.get().getKeepCacheTime();
initAutoFetchUpdatesPreference();
initPrivilegedInstallerPreference();
initUpdatePrivilegedExtensionPreference();
initUseTorPreference();
}
@Override

View File

@ -23,7 +23,6 @@ import com.ashokvarma.bottomnavigation.BadgeItem;
import com.ashokvarma.bottomnavigation.BottomNavigationBar;
import com.ashokvarma.bottomnavigation.BottomNavigationItem;
import org.fdroid.fdroid.AppDetails;
import org.fdroid.fdroid.AppDetails2;
import org.fdroid.fdroid.AppUpdateStatusManager;
import org.fdroid.fdroid.FDroidApp;
@ -281,7 +280,7 @@ public class MainActivity extends AppCompatActivity implements BottomNavigationB
if (!TextUtils.isEmpty(packageName)) {
Utils.debugLog(TAG, "FDroid launched via app link for '" + packageName + "'");
Intent intentToInvoke = new Intent(this, AppDetails2.class);
intentToInvoke.putExtra(AppDetails.EXTRA_APPID, packageName);
intentToInvoke.putExtra(AppDetails2.EXTRA_APPID, packageName);
startActivity(intentToInvoke);
finish();
} else if (!TextUtils.isEmpty(query)) {

View File

@ -69,7 +69,8 @@ class MainViewAdapter extends RecyclerView.Adapter<MainViewController> {
holder.bindSwapView();
break;
case R.id.updates:
holder.bindUpdates();
// Hold of until onViewAttachedToWindow, because that is where we want to start listening
// for broadcast events (which is what the data binding does).
break;
case R.id.settings:
holder.bindSettingsView();

View File

@ -8,6 +8,7 @@ import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.TextView;
import org.fdroid.fdroid.R;
import org.fdroid.fdroid.views.fragments.PreferencesFragment;
@ -75,6 +76,11 @@ class MainViewController extends RecyclerView.ViewHolder {
public void bindSwapView() {
View swapView = activity.getLayoutInflater().inflate(R.layout.main_tab_swap, frame, true);
// To allow for whitelabel versions of F-Droid, make sure not to hardcode "F-Droid" into our
// translation here.
TextView subtext = (TextView) swapView.findViewById(R.id.text2);
subtext.setText(activity.getString(R.string.nearby_splash__both_parties_need_fdroid, activity.getString(R.string.app_name)));
Button startButton = (Button) swapView.findViewById(R.id.button);
startButton.setOnClickListener(new View.OnClickListener() {
@Override

View File

@ -57,6 +57,9 @@ import java.util.List;
* repopulate it from the original source lists of data. When this is done, the adapter will notify
* the recycler view that its data has changed. Sometimes it will also ask the recycler view to
* scroll to the newly added item (if attached to the recycler view).
*
* TODO: If a user downloads an old version of an app (resulting in a new update being available
* instantly), then we need to refresh the list of apps to update.
*/
public class UpdatesAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> implements LoaderManager.LoaderCallbacks<Cursor> {
@ -84,16 +87,12 @@ public class UpdatesAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
.addDelegate(new UpdateableApp.Delegate(activity))
.addDelegate(new UpdateableAppsHeader.Delegate(activity));
populateAppStatuses();
notifyDataSetChanged();
activity.getSupportLoaderManager().initLoader(0, null, this);
}
/**
* There are some statuses managed by {@link AppUpdateStatusManager} which we don't care about
* for the "Updates" view. For example {@link org.fdroid.fdroid.AppUpdateStatusManager.Status#Installed}
* apps are not interesting in the Updates" view at this point in time. Also, although this
* for the "Updates" view. For example Also, although this
* adapter does know about apps with updates availble, it does so by querying the database not
* by querying the app update status manager. As such, apps with the status
* {@link org.fdroid.fdroid.AppUpdateStatusManager.Status#UpdateAvailable} are not interesting here.
@ -101,6 +100,7 @@ public class UpdatesAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
private boolean shouldShowStatus(AppUpdateStatusManager.AppUpdateStatus status) {
return status.status == AppUpdateStatusManager.Status.Unknown ||
status.status == AppUpdateStatusManager.Status.Downloading ||
status.status == AppUpdateStatusManager.Status.Installed ||
status.status == AppUpdateStatusManager.Status.ReadyToInstall;
}
@ -245,11 +245,18 @@ public class UpdatesAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
public void onLoaderReset(Loader<Cursor> loader) { }
/**
* If this adapter is "active" then it is part of the current UI that the user is looking to.
* Under those circumstances, we want to make sure it is up to date, and also listen to the
* correct set of broadcasts.
* Doesn't listen for {@link AppUpdateStatusManager#BROADCAST_APPSTATUS_CHANGED} because the
* individual items in the recycler view will listen for the appropriate changes in state and
* update themselves accordingly (if they are displayed).
*/
public void listenForStatusUpdates() {
public void setIsActive() {
appsToShowStatus.clear();
populateAppStatuses();
notifyDataSetChanged();
IntentFilter filter = new IntentFilter();
filter.addAction(AppUpdateStatusManager.BROADCAST_APPSTATUS_ADDED);
filter.addAction(AppUpdateStatusManager.BROADCAST_APPSTATUS_REMOVED);

View File

@ -24,7 +24,7 @@ public class UpdatesViewBinder {
}
public void bind() {
adapter.listenForStatusUpdates();
adapter.setIsActive();
}
public void unbind() {

View File

@ -0,0 +1,6 @@
<vector android:height="24dp" android:viewportHeight="634.0"
android:viewportWidth="720.0" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillAlpha="1" android:fillColor="#f9f9f9"
android:pathData="M105,0L105,321.3L0,387.7L0,405.9L105,339.5L105,392L104.6,392L104.6,407.5L105,407.5L105,633L120,633L120,407.5L209,407.5L209,633L224,633L224,407.5L393,407.5L498.7,633.1L514.6,633.6L408.7,407.5L624.5,407.5L624.5,633L639.5,633L639.5,470.5L720,435.9L720,419L639.5,453.6L639.5,67.1L720,67.1L720,51.5L120,51.5L120,0L105,0zM120,67.1L233.4,67.1L385.7,392L120,392L120,67.1zM249.1,67.1L624.5,67.1L624.5,392L401.4,392L249.1,67.1z"
android:strokeColor="#00000000" android:strokeWidth="1"/>
</vector>

View File

@ -151,7 +151,6 @@
android:layout_marginStart="8dp"
android:layout_weight="1"
android:ellipsize="marquee"
android:padding="12dp"
tools:text="THIS IS 2" />
</LinearLayout>

View File

@ -4,60 +4,66 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="@drawable/swap_start_header"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent" />
android:layout_height="match_parent"
android:background="#FAFAFA">
<TextView
android:id="@+id/text1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Download apps from people near you."
android:layout_marginEnd="48dp"
android:layout_marginLeft="48dp"
android:layout_marginRight="48dp"
android:layout_marginStart="48dp"
android:layout_marginTop="48dp"
android:text="@string/nearby_splash__download_apps_from_people_nearby"
android:textAlignment="center"
android:textSize="20sp"
android:textAlignment="center"
app:layout_constraintTop_toBottomOf="@+id/image"
app:layout_constraintRight_toRightOf="parent"
android:textColor="#4a4a4a"
app:layout_constraintLeft_toLeftOf="parent"
android:layout_marginTop="32dp"
android:layout_marginEnd="48dp"
android:layout_marginRight="48dp"
android:layout_marginStart="48dp"
android:layout_marginLeft="48dp" />
<!-- TODO: Use @string/app_name instead of "F-Droid". -->
<!-- TODO: The swap process helps to get F-Droid to the other user. That should probably be made a bit clearer here. -->
<TextView
android:id="@+id/text2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Participants must have F-Droid installed."
android:textSize="14sp"
android:textAlignment="center"
app:layout_constraintTop_toBottomOf="@+id/text1"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
android:layout_marginTop="16dp"
android:layout_marginEnd="48dp"
android:layout_marginRight="48dp"
android:layout_marginStart="48dp"
android:layout_marginLeft="48dp" />
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Find people near me"
android:text="@string/nearby_splash__find_people_button"
style="@style/DetailsSecondaryButtonStyle"
app:layout_constraintTop_toBottomOf="@+id/text2"
app:layout_constraintTop_toBottomOf="@+id/text1"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
android:layout_marginTop="16dp" />
android:layout_marginTop="24dp" />
<TextView
android:id="@+id/text2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="@string/nearby_splash__both_parties_need_fdroid"
android:textSize="15sp"
android:textAlignment="center"
android:textColor="#5B5B5B"
app:layout_constraintTop_toBottomOf="@+id/button"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
android:layout_marginTop="24dp"
android:layout_marginEnd="48dp"
android:layout_marginRight="48dp"
android:layout_marginStart="48dp"
android:layout_marginLeft="48dp" />
<ImageView
android:id="@+id/image"
android:layout_width="0dp"
android:layout_height="0dp"
app:srcCompat="@drawable/nearby_splash"
android:importantForAccessibility="no"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@+id/text2"
android:layout_marginTop="36dp"
android:tint="#f5f5f5"
android:scaleType="fitXY" />
</android.support.constraint.ConstraintLayout>

View File

@ -72,7 +72,7 @@
<Button
android:id="@+id/action_button"
style="@style/DetailsPrimaryButtonStyle"
style="@style/DetailsPrimaryButtonStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"

View File

@ -23,6 +23,10 @@
<dimen name="whats_new__padding__app_card__horizontal">12dp</dimen>
<dimen name="whats_new__padding__app_card__vertical">10dp</dimen>
<!-- Used by the BottomNavigation library so that our text labels are not truncated so easily.
The default is 12dp or something like that which only really allows for very short labels. -->
<dimen name="fixed_width_padding">2dp</dimen>
<dimen name="category_preview__app_list__padding__horizontal">4dp</dimen>
<dimen name="category_preview__app_list__padding__horizontal__first">72dp</dimen>
<dimen name="category_preview__app_list__padding__vertical">18dp</dimen>

View File

@ -22,8 +22,8 @@
<string name="update_interval_zero">No automatic app list updates</string>
<string name="automatic_scan_wifi">Only on Wi-Fi</string>
<string name="automatic_scan_wifi_on">Only update automatically on unmetered networks like Wi-Fi</string>
<string name="update_auto_download">Automatically download updates</string>
<string name="update_auto_download_summary">Download the update files in the background</string>
<string name="update_auto_download">Automatically fetch updates</string>
<string name="update_auto_download_summary">Updates are downloaded automatically and you are notified to install them</string>
<string name="update_auto_install">Automatically install updates</string>
<string name="update_auto_install_summary">Download and install update apps in the background</string>
<string name="notify">Update notifications</string>
@ -73,6 +73,7 @@
<string name="app_list__name__downloaded_and_ready_to_update">Update %1$s</string>
<string name="app_list__name__downloaded_and_ready_to_install">Install %1$s</string>
<string name="app_list__name__downloading_in_progress">Downloading %1$s</string>
<string name="app_list__name__successfully_installed">%1$s successfully installed</string>
<plurals name="app_list__age__released_x_days_ago">
<item quantity="one">Released %1$d day ago</item>
<item quantity="other">Released %1$d days ago</item>
@ -342,6 +343,10 @@
<string name="system_uninstall_button">Uninstall</string>
<string name="system_install_not_supported">Installation of F-Droid Privileged Extension is currently not supported on Android 5.1 or later.</string>
<string name="nearby_splash__download_apps_from_people_nearby">No internet? Download apps from people near you!</string>
<string name="nearby_splash__find_people_button">Find people near me</string>
<string name="nearby_splash__both_parties_need_fdroid">Both parties need %1$s to use nearby.</string>
<string name="swap_nfc_title">Touch to swap</string>
<string name="swap_nfc_description">If your friend has F-Droid and NFC turned on touch your devices together.</string>
<string name="swap_join_same_wifi">Join the same Wi-Fi as your friend</string>

View File

@ -1,30 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="DetailsButtonStyleBase">
<item name="android:paddingTop">5dp</item>
<item name="android:paddingBottom">5dp</item>
<item name="android:paddingLeft">20dp</item>
<item name="android:paddingRight">20dp</item>
<item name="android:textSize">12sp</item>
<item name="android:textStyle">normal</item>
</style>
<item name="android:minHeight">32dp</item>
<item name="android:minWidth">0dp</item>
<item name="android:padding">12dp</item>
</style>qgi
<style name="DetailsButtonStyle" parent="DetailsButtonStyleBase" />
<style name="DetailsPrimaryButtonStyle" parent="DetailsButtonStyle">
<item name="android:textColor">#ffffff</item>
<item name="android:background">@drawable/button_primary_background_selector</item>
</style>
<style name="DetailsPrimaryButtonStyleSmall" parent="DetailsPrimaryButtonStyle">
<item name="android:padding">8dp</item>
<item name="android:minHeight">32dp</item>
<item name="android:minWidth">0dp</item>
</style>
<style name="DetailsSecondaryButtonStyle" parent="DetailsButtonStyle">
<item name="android:textColor">@color/fdroid_blue</item>
<item name="android:background">@drawable/button_secondary_background_selector</item>
<item name="android:padding">8dp</item>
<item name="android:minHeight">32dp</item>
<item name="android:minWidth">0dp</item>
</style>
<style name="DetailsMoreButtonStyle">