Download description in progress

This commit is contained in:
Vitaliy 2020-04-22 21:39:44 +03:00
parent 137e554059
commit f750a7732f
10 changed files with 315 additions and 33 deletions

View file

@ -49,7 +49,7 @@ public class Algorithms {
return map == null || map.size() == 0;
}
public static boolean isEmpty(String s) {
public static boolean isEmpty(CharSequence s) {
return s == null || s.length() == 0;
}

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<net.osmand.plus.widgets.TextViewEx xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/button_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:letterSpacing="@dimen/description_letter_spacing"
android:paddingLeft="@dimen/content_padding_half"
android:paddingTop="@dimen/content_padding_half"
android:paddingRight="@dimen/content_padding_half"
android:paddingBottom="@dimen/content_padding_half"
android:textColor="?attr/active_color_basic"
android:textSize="@dimen/default_desc_text_size"
app:typeface="@string/font_roboto_medium"
tools:text="@string/read_more" />

View file

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/card_and_list_background_basic">
<LinearLayout
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingBottom="@dimen/list_header_settings_top_margin">
<LinearLayout
android:id="@+id/images_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxHeight="132dp"
android:orientation="horizontal" />
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:letterSpacing="@dimen/text_button_letter_spacing"
android:paddingLeft="@dimen/content_padding"
android:paddingTop="@dimen/list_header_settings_top_margin"
android:paddingRight="@dimen/content_padding"
android:textColor="?android:textColorPrimary"
android:textSize="@dimen/default_list_text_size"
app:typeface="@string/font_roboto_regular"
tools:text="@string/plugin_disabled_descr" />
<LinearLayout
android:id="@+id/buttons_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/content_padding_half"
android:layout_marginTop="@dimen/list_header_settings_top_margin"
android:layout_marginRight="@dimen/content_padding_half"
android:orientation="vertical" />
</LinearLayout>
</LinearLayout>

View file

@ -15,7 +15,7 @@
<ImageView
android:id="@+id/plugin_image"
android:layout_width="wrap_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:adjustViewBounds="true"

View file

@ -44,12 +44,16 @@ public class JsonUtils {
}
public static Map<String, String> getLocalizedMapFromJson(String key, JSONObject json) throws JSONException {
Map<String, String> localizedMap = new HashMap<>();
JSONObject jsonObject = json.optJSONObject(key);
if (jsonObject != null) {
for (Iterator<String> it = jsonObject.keys(); it.hasNext(); ) {
return getLocalizedMapFromJson(jsonObject);
}
public static Map<String, String> getLocalizedMapFromJson(JSONObject json) throws JSONException {
Map<String, String> localizedMap = new HashMap<>();
if (json != null) {
for (Iterator<String> it = json.keys(); it.hasNext(); ) {
String localeKey = it.next();
String name = jsonObject.getString(localeKey);
String name = json.getString(localeKey);
localizedMap.put(localeKey, name);
}
}

View file

@ -88,7 +88,8 @@ public class CustomOsmandPlugin extends OsmandPlugin {
@Override
public CharSequence getDescription() {
return Html.fromHtml(JsonUtils.getLocalizedResFromMap(app, descriptions, null));
String description = JsonUtils.getLocalizedResFromMap(app, descriptions, null);
return description != null ? Html.fromHtml(description) : null;
}
public String getResourceDirName() {

View file

@ -1,6 +1,7 @@
package net.osmand.plus;
import androidx.annotation.ColorInt;
import androidx.annotation.Nullable;
import net.osmand.JsonUtils;
import net.osmand.PlatformUtil;
@ -8,6 +9,7 @@ import net.osmand.map.WorldRegion;
import net.osmand.plus.download.CustomIndexItem;
import net.osmand.plus.download.DownloadActivityType;
import net.osmand.plus.download.IndexItem;
import net.osmand.plus.download.ui.DescriptionInfo;
import net.osmand.util.Algorithms;
import org.apache.commons.logging.Log;
@ -31,10 +33,11 @@ public class CustomRegion extends WorldRegion {
private String parentPath;
private String type;
private String subfolder;
private String headerButton;
private JSONArray downloadItemsJson;
private DescriptionInfo descriptionInfo;
private Map<String, String> names = new HashMap<>();
private Map<String, String> icons = new HashMap<>();
private Map<String, String> headers = new HashMap<>();
@ -66,6 +69,11 @@ public class CustomRegion extends WorldRegion {
return headerColor;
}
@Nullable
public DescriptionInfo getDescriptionInfo() {
return descriptionInfo;
}
public static CustomRegion fromJson(JSONObject object) throws JSONException {
String scopeId = object.optString("scope-id", null);
String path = object.optString("path", null);
@ -90,7 +98,6 @@ public class CustomRegion extends WorldRegion {
region.icons = JsonUtils.getLocalizedMapFromJson("icon", object);
region.headers = JsonUtils.getLocalizedMapFromJson("header", object);
region.headerButton = object.optString("header-button", null);
region.downloadItemsJson = object.optJSONArray("items");
String headerColor = object.optString("header-color", null);
@ -99,10 +106,31 @@ public class CustomRegion extends WorldRegion {
} catch (IllegalArgumentException e) {
region.headerColor = 0;
}
region.descriptionInfo = DescriptionInfo.fromJson(object.optJSONObject("description"));
return region;
}
public JSONObject toJson() throws JSONException {
JSONObject jsonObject = new JSONObject();
jsonObject.putOpt("scope-id", scopeId);
jsonObject.putOpt("path", path);
jsonObject.putOpt("type", type);
jsonObject.putOpt("subfolder", subfolder);
JsonUtils.writeLocalizedMapToJson("name", jsonObject, names);
JsonUtils.writeLocalizedMapToJson("icon", jsonObject, icons);
JsonUtils.writeLocalizedMapToJson("header", jsonObject, headers);
if (descriptionInfo != null) {
jsonObject.putOpt("description", descriptionInfo.toJson());
}
jsonObject.putOpt("items", downloadItemsJson);
return jsonObject;
}
public List<IndexItem> loadIndexItems() {
List<IndexItem> items = new ArrayList<>();
if (downloadItemsJson != null) {
@ -152,22 +180,4 @@ public class CustomRegion extends WorldRegion {
}
return items;
}
public JSONObject toJson() throws JSONException {
JSONObject jsonObject = new JSONObject();
jsonObject.putOpt("scope-id", scopeId);
jsonObject.putOpt("path", path);
jsonObject.putOpt("type", type);
jsonObject.putOpt("subfolder", subfolder);
jsonObject.putOpt("header-button", headerButton);
JsonUtils.writeLocalizedMapToJson("name", jsonObject, names);
JsonUtils.writeLocalizedMapToJson("icon", jsonObject, icons);
JsonUtils.writeLocalizedMapToJson("header", jsonObject, headers);
jsonObject.putOpt("items", downloadItemsJson);
return jsonObject;
}
}

View file

@ -470,7 +470,7 @@ public class DownloadResources extends DownloadResourceGroup {
mainGrp.addGroup(flatFiles);
}
}
DownloadResourceGroup subRegions = new DownloadResourceGroup(mainGrp, DownloadResourceGroupType.SUBREGIONS);
DownloadResourceGroup subRegions = new DownloadResourceGroup(mainGrp, DownloadResourceGroupType.EXTRA_MAPS);
mainGrp.addGroup(subRegions);
// add to processing queue
for (WorldRegion rg : subregions) {

View file

@ -0,0 +1,122 @@
package net.osmand.plus.download.ui;
import android.content.Context;
import android.text.Html;
import net.osmand.JsonUtils;
import net.osmand.PlatformUtil;
import org.apache.commons.logging.Log;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class DescriptionInfo {
private static final Log LOG = PlatformUtil.getLog(DescriptionInfo.class);
private JSONArray buttonsJson;
private List<String> imageUrls;
private Map<String, String> texts;
public List<String> getImageUrls() {
return imageUrls;
}
public CharSequence getLocalizedDescription(Context ctx) {
String description = JsonUtils.getLocalizedResFromMap(ctx, texts, null);
return description != null ? Html.fromHtml(description) : null;
}
public List<DownloadActionButton> getDownloadActionButtons(Context ctx) {
List<DownloadActionButton> downloadActionButtons = new ArrayList<>();
if (buttonsJson != null) {
try {
for (int i = 0; i < buttonsJson.length(); i++) {
DescriptionActionButtonType type = null;
String url = null;
JSONObject object = buttonsJson.getJSONObject(i);
if (object.has("url")) {
url = object.optString("url");
} else if (object.has("action")) {
String action = object.optString("action");
for (DescriptionActionButtonType buttonType : DescriptionActionButtonType.values()) {
if (buttonType.name().equalsIgnoreCase(action)) {
type = buttonType;
}
}
}
Map<String, String> localizedMap = JsonUtils.getLocalizedMapFromJson(object);
String name = JsonUtils.getLocalizedResFromMap(ctx, localizedMap, null);
DownloadActionButton actionButton = new DownloadActionButton(type, name, url);
downloadActionButtons.add(actionButton);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
return downloadActionButtons;
}
public static DescriptionInfo fromJson(JSONObject json) {
if (json != null) {
DescriptionInfo descriptionInfo = new DescriptionInfo();
try {
descriptionInfo.texts = JsonUtils.getLocalizedMapFromJson("text", json);
descriptionInfo.imageUrls = JsonUtils.jsonArrayToList("image", json);
descriptionInfo.buttonsJson = json.optJSONArray("button");
} catch (JSONException e) {
LOG.error(e);
}
return descriptionInfo;
}
return null;
}
public JSONObject toJson() throws JSONException {
JSONObject descrJson = new JSONObject();
JsonUtils.writeLocalizedMapToJson("text", descrJson, texts);
JsonUtils.writeStringListToJson("image", descrJson, imageUrls);
descrJson.putOpt("button", buttonsJson);
return descrJson;
}
public enum DescriptionActionButtonType {
DOWNLOAD,
URL
}
public static class DownloadActionButton {
private DescriptionInfo.DescriptionActionButtonType type;
private String name;
private String url;
public DownloadActionButton(DescriptionInfo.DescriptionActionButtonType type, String name, String url) {
this.type = type;
this.name = name;
this.url = url;
}
public DescriptionInfo.DescriptionActionButtonType getType() {
return type;
}
public String getName() {
return name;
}
public String getUrl() {
return url;
}
}
}

View file

@ -5,6 +5,7 @@ import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.TypedValue;
@ -26,10 +27,15 @@ import androidx.appcompat.widget.Toolbar;
import androidx.core.view.MenuItemCompat;
import androidx.fragment.app.DialogFragment;
import com.squareup.picasso.Callback;
import com.squareup.picasso.Picasso;
import com.squareup.picasso.RequestCreator;
import net.osmand.AndroidNetworkUtils;
import net.osmand.AndroidUtils;
import net.osmand.PicassoUtils;
import net.osmand.plus.CustomRegion;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.OsmandSettings;
import net.osmand.plus.R;
import net.osmand.plus.UiUtilities;
import net.osmand.plus.activities.OsmandBaseExpandableListAdapter;
@ -43,9 +49,11 @@ import net.osmand.plus.download.DownloadResourceGroup.DownloadResourceGroupType;
import net.osmand.plus.download.DownloadResources;
import net.osmand.plus.download.DownloadValidationManager;
import net.osmand.plus.download.IndexItem;
import net.osmand.plus.helpers.AndroidUiHelper;
import net.osmand.plus.inapp.InAppPurchaseHelper;
import net.osmand.plus.inapp.InAppPurchaseHelper.InAppPurchaseListener;
import net.osmand.plus.inapp.InAppPurchaseHelper.InAppPurchaseTaskType;
import net.osmand.plus.wikipedia.WikipediaDialogFragment;
import net.osmand.util.Algorithms;
import org.json.JSONException;
@ -77,13 +85,15 @@ public class DownloadResourceGroupFragment extends DialogFragment implements Dow
private View searchView;
private View restorePurchasesView;
private View subscribeEmailView;
private View descriptionView;
private boolean nightMode;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
purchaseHelper = getDownloadActivity().getPurchaseHelper();
boolean isLightTheme = getMyApplication().getSettings().OSMAND_THEME.get() == OsmandSettings.OSMAND_LIGHT_THEME;
int themeId = isLightTheme ? R.style.OsmandLightTheme : R.style.OsmandDarkTheme;
nightMode = !getMyApplication().getSettings().isLightContent();
int themeId = nightMode ? R.style.OsmandDarkTheme : R.style.OsmandLightTheme;
setStyle(STYLE_NO_FRAME, themeId);
setHasOptionsMenu(true);
}
@ -133,6 +143,7 @@ public class DownloadResourceGroupFragment extends DialogFragment implements Dow
addSubscribeEmailRow();
addSearchRow();
addRestorePurchasesRow();
addDescriptionRow();
listView.setOnChildClickListener(this);
listAdapter = new DownloadResourceGroupAdapter(activity);
listView.setAdapter(listAdapter);
@ -180,6 +191,11 @@ public class DownloadResourceGroupFragment extends DialogFragment implements Dow
}
}
private void addDescriptionRow() {
descriptionView = activity.getLayoutInflater().inflate(R.layout.group_description_item, listView, false);
listView.addHeaderView(descriptionView);
}
private void addSearchRow() {
if (!openAsDialog() ) {
searchView = activity.getLayoutInflater().inflate(R.layout.simple_list_menu_item, null);
@ -231,6 +247,68 @@ public class DownloadResourceGroupFragment extends DialogFragment implements Dow
}
}
private void updateDescriptionView() {
if (descriptionView != null) {
if (group != null && group.getRegion() instanceof CustomRegion) {
CustomRegion customRegion = (CustomRegion) group.getRegion();
net.osmand.plus.download.ui.DescriptionInfo descriptionInfo = customRegion.getDescriptionInfo();
if (descriptionInfo != null) {
TextView description = descriptionView.findViewById(R.id.description);
CharSequence descr = descriptionInfo.getLocalizedDescription(activity);
description.setText(descr);
AndroidUiHelper.updateVisibility(description, !Algorithms.isEmpty(descr));
ViewGroup buttonsContainer = descriptionView.findViewById(R.id.buttons_container);
buttonsContainer.removeAllViews();
for (final DescriptionInfo.DownloadActionButton actionButton : descriptionInfo.getDownloadActionButtons(activity)) {
String name = actionButton.getName();
if (!Algorithms.isEmpty(name)) {
TextView buttonText = (TextView) activity.getLayoutInflater().inflate(R.layout.download_description_button, buttonsContainer, false);
buttonText.setText(name);
buttonText.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (actionButton.getUrl() != null) {
WikipediaDialogFragment.showFullArticle(activity, Uri.parse(actionButton.getUrl()), nightMode);
}
}
});
buttonsContainer.addView(buttonText);
}
}
ViewGroup imagesContainer = descriptionView.findViewById(R.id.images_container);
imagesContainer.removeAllViews();
final PicassoUtils picassoUtils = PicassoUtils.getPicasso(getMyApplication());
Picasso picasso = Picasso.get();
for (final String imageUrl : descriptionInfo.getImageUrls()) {
final ImageView image = new ImageView(getContext());
imagesContainer.addView(image);
RequestCreator rc = picasso.load(imageUrl);
rc.into(image, new Callback() {
@Override
public void onSuccess() {
image.setVisibility(View.VISIBLE);
picassoUtils.setResultLoaded(imageUrl, true);
}
@Override
public void onError(Exception e) {
image.setVisibility(View.GONE);
picassoUtils.setResultLoaded(imageUrl, false);
}
});
}
descriptionView.findViewById(R.id.container).setVisibility(View.VISIBLE);
return;
}
}
descriptionView.findViewById(R.id.container).setVisibility(View.GONE);
}
}
private void hideSubscribeEmailView() {
if (subscribeEmailView != null && subscribeEmailView.findViewById(R.id.container).getVisibility() == View.VISIBLE) {
subscribeEmailView.findViewById(R.id.container).setVisibility(View.GONE);
@ -389,12 +467,15 @@ public class DownloadResourceGroupFragment extends DialogFragment implements Dow
}
private void reloadData() {
DownloadResources indexes = activity.getDownloadThread().getIndexes();
group = indexes.getGroupById(groupId);
if (!openAsDialog()) {
updateSearchView();
}
updateSubscribeEmailView();
DownloadResources indexes = activity.getDownloadThread().getIndexes();
group = indexes.getGroupById(groupId);
updateDescriptionView();
if (group != null) {
listAdapter.update(group);
toolbar.setTitle(group.getName(activity));