Merge branch 'develop' into 'master'

Release version 0.3

See merge request ChronosX88/VRCatalog!5
This commit is contained in:
ChronosX88 2019-02-15 16:36:09 +00:00
commit b6200a39d9
31 changed files with 809 additions and 244 deletions

View File

@ -18,7 +18,7 @@
<PersistentState>
<option name="values">
<map>
<entry key="url" value="jar:file:/home/WORK/android-studio/plugins/android/lib/android.jar!/images/material_design_icons/action/ic_search_black_24dp.xml" />
<entry key="url" value="jar:file:/home/chronosx/%D0%94%D0%BE%D0%BA%D1%83%D0%BC%D0%B5%D0%BD%D1%82%D1%8B/bin/Android%20Studio/plugins/android/lib/android.jar!/images/material_design_icons/file/ic_cloud_off_black_24dp.xml" />
</map>
</option>
</PersistentState>
@ -28,8 +28,8 @@
</option>
<option name="values">
<map>
<entry key="color" value="ffffff" />
<entry key="outputName" value="ic_search_white_24dp" />
<entry key="color" value="a9a9a9" />
<entry key="outputName" value="ic_cloud_off_black_24dp" />
<entry key="sourceFile" value="$USER_HOME$" />
</map>
</option>

Binary file not shown.

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RenderSettings">
<option name="showDecorations" value="true" />
</component>
</project>

View File

@ -2,5 +2,6 @@
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

View File

@ -6,8 +6,8 @@ android {
applicationId "ru.volgorobot.vrcatalog"
minSdkVersion 19
targetSdkVersion 27
versionCode 1
versionName "1.0"
versionCode 4
versionName "0.3"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
compileOptions {
@ -33,4 +33,5 @@ dependencies {
implementation 'com.squareup.retrofit2:retrofit:2.4.0'
implementation 'com.squareup.retrofit2:converter-gson:2.4.0'
implementation 'com.android.support:recyclerview-v7:27.1.1'
}
implementation 'com.squareup.picasso:picasso:2.71828'
}

View File

@ -23,7 +23,9 @@
</activity>
<activity android:name=".view.SettingsActivity" />
<activity android:name=".view.AboutActivity" />
<activity android:name=".view.DetailActivity" />
<activity
android:name=".view.DetailActivity"
android:theme="@style/ItemActivityTheme"/>
<activity
android:name=".view.SearchableActivity"
android:label="Поиск"

View File

@ -0,0 +1,106 @@
package ru.volgorobot.vrcatalog;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.AsyncTask;
import android.util.Base64;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.UUID;
import ru.volgorobot.vrcatalog.additional.NetworkErrorException;
import ru.volgorobot.vrcatalog.additional.ResultWithErrorCode;
import ru.volgorobot.vrcatalog.model.CoreModel;
import ru.volgorobot.vrcatalog.model.ImageItemModel;
public class ItemPresenter implements MainContract.ItemPresenter {
// TODO
private MainContract.ItemView mView;
private Context context;
private MainContract.MainModel coreModel;
public ItemPresenter(Context context, MainContract.ItemView itemView) {
this.mView = itemView;
this.context = context;
this.coreModel = new CoreModel(context);
}
@SuppressLint("StaticFieldLeak")
@Override
public void getImagesByItemID(int id) {
new AsyncTask<Void, Void, ResultWithErrorCode<ArrayList<ImageItemModel>>>() {
@Override
protected ResultWithErrorCode<ArrayList<ImageItemModel>> doInBackground(Void... voids) {
ArrayList<ImageItemModel> images = null;
try {
images = coreModel.fetchImagesByItemID(id);
} catch (NetworkErrorException networkErrorException) {
return new ResultWithErrorCode<>(images, networkErrorException.getErrorCode());
} catch (NullPointerException nullPointerException) {
return new ResultWithErrorCode<>(images, 3);
}
return new ResultWithErrorCode<>(images, 0);
}
@Override
protected void onPostExecute(ResultWithErrorCode<ArrayList<ImageItemModel>> result) {
super.onPostExecute(result);
switch (result.getErrorCode()) {
case 0: {
//mView.setViewPagerContent(result.getData());
ArrayList<Bitmap> bitmaps = new ArrayList<>();
ArrayList<String> uriStrings = new ArrayList<>();
for (ImageItemModel imageItem : result.getData()) {
byte[] imageStream = Base64.decode(imageItem.getImage(), Base64.DEFAULT);
bitmaps.add(BitmapFactory.decodeByteArray(imageStream, 0, imageStream.length));
}
for (int i = 0; i < bitmaps.size(); i++) {
uriStrings.add(processImages(bitmaps.get(i)).toString());
}
String[] uriStringsArray = new String[uriStrings.size()];
uriStrings.toArray(uriStringsArray);
mView.setViewPagerContent(uriStringsArray);
break;
}
case 1: {
mView.onFailureAnswer(1);
break;
}
case 2: {
mView.onFailureAnswer(2);
break;
}
case 3: {
mView.onFailureAnswer(3);
break;
}
}
}
}.execute();
}
private Uri processImages(Bitmap bitmap) {
File cacheDir = context.getCacheDir();
File cacheObject = new File(cacheDir, UUID.randomUUID().toString());
try {
FileOutputStream fileOutputStream = new FileOutputStream(cacheObject);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fileOutputStream);
fileOutputStream.flush();
fileOutputStream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return Uri.fromFile(cacheObject);
}
}

View File

@ -9,6 +9,7 @@ import ru.volgorobot.vrcatalog.additional.NetworkErrorException;
import ru.volgorobot.vrcatalog.model.CoreModel;
import ru.volgorobot.vrcatalog.model.DetailModel;
import ru.volgorobot.vrcatalog.model.FirstLevelModel;
import ru.volgorobot.vrcatalog.model.ImageItemModel;
import ru.volgorobot.vrcatalog.model.SecondLevelModel;
import ru.volgorobot.vrcatalog.model.ThirdLevelModel;
@ -42,10 +43,11 @@ public interface MainContract {
ArrayList<ThirdLevelModel> fetchThirdLevelByParentID(int parentID) throws NetworkErrorException, NullPointerException;
ArrayList<DetailModel> fetchDetailByID(int detailID) throws NetworkErrorException, NullPointerException;
void reinitializeApi() throws IllegalStateException;
boolean getApiState();
boolean isApiNotNull();
ArrayList<ThirdLevelModel> fetchDetailsByName(String name) throws NetworkErrorException, NullPointerException;
ArrayList<FirstLevelModel> fetchCategoryByID(int id) throws NetworkErrorException, NullPointerException;
ArrayList<SecondLevelModel> fetchSubCategoryByID(int id) throws NetworkErrorException, NullPointerException;
ArrayList<ImageItemModel> fetchImagesByItemID(int id) throws NetworkErrorException, NullPointerException;
}
interface SearchablePresenter {
@ -57,4 +59,13 @@ public interface MainContract {
void onFailureAnswer(int errorCode);
void swipeLayoutSetRefreshing(boolean state);
}
interface ItemPresenter {
void getImagesByItemID(int id);
}
interface ItemView {
void onFailureAnswer(int errorCode);
void setViewPagerContent(String[] uris);
}
}

View File

@ -170,6 +170,7 @@ public class ViewBinderPresenter implements MainContract.ViewBinderPresenter {
switch (result.getErrorCode()) {
case 0: {
Intent intent = new Intent(context, DetailActivity.class);
intent.putExtra("itemID", result.getData().getID().toString());
intent.putExtra("detailName", result.getData().getName());
intent.putExtra("detailQuantity", result.getData().getNumber().toString());
intent.putExtra("detailPrice", result.getData().getPrice());

View File

@ -0,0 +1,76 @@
package ru.volgorobot.vrcatalog.additional;
import android.content.Context;
import android.graphics.Bitmap;
import android.net.Uri;
import android.provider.MediaStore;
import android.support.annotation.NonNull;
import android.support.v4.view.PagerAdapter;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import com.squareup.picasso.Picasso;
import java.io.FileNotFoundException;
import java.io.IOException;
public class ImagePagerAdapter extends PagerAdapter {
/**
* This class is designed to control the ViewPager (images of item) in the activity of viewing details of items.
*/
private Context context;
private String[] imageUris;
public ImagePagerAdapter(Context context, String[] imageUris) {
this.context = context;
this.imageUris = imageUris;
}
@Override
public int getCount() {
return imageUris.length;
}
@Override
public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
return view == object;
}
/**
* This function initializes a new image from a URI.
* @return ImageView
*/
@NonNull
@Override
public Object instantiateItem(@NonNull ViewGroup container, int position) {
ImageView imageView = new ImageView(context);
ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(313, 313);
imageView.setLayoutParams(params);
Picasso.get()
.load(imageUris[position])
.resize(0, 313)
.centerCrop()
.into(imageView);
container.addView(imageView);
return imageView;
}
@Override
public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
container.removeView((View) object);
}
public Bitmap getBitmap(int position) {
Bitmap bitmap = null;
try {
bitmap = MediaStore.Images.Media.getBitmap(context.getContentResolver(), Uri.parse(imageUris[position]));
} catch (IOException e) {
e.printStackTrace();
}
return bitmap;
}
}

View File

@ -0,0 +1,52 @@
package ru.volgorobot.vrcatalog.additional;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
import java.util.LinkedHashMap;
import ru.volgorobot.vrcatalog.R;
public class PropertiesListAdapter extends BaseAdapter {
private LinkedHashMap<String, String> mData;
private String[] mKeys;
public PropertiesListAdapter(LinkedHashMap<String, String> data) {
mData = data;
mKeys = mData.keySet().toArray(new String[data.size()]);
}
@Override
public int getCount() {
return mData.size();
}
@Override
public Object getItem(int position) {
return mData.get(mKeys[position]);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final View result;
if (convertView == null) {
result = LayoutInflater.from(parent.getContext()).inflate(R.layout.properties_list_adapter, parent, false);
} else {
result = convertView;
}
((TextView) result.findViewById(R.id.propertyNameView)).setText(mKeys[position]);
((TextView) result.findViewById(R.id.propertyValueView)).setText(getItem(position).toString());
return result;
}
}

View File

@ -7,8 +7,8 @@ import me.texy.treeview.base.BaseNodeViewBinder;
import me.texy.treeview.base.BaseNodeViewFactory;
import ru.volgorobot.vrcatalog.MainContract;
import ru.volgorobot.vrcatalog.nodeViewBinders.ThirdLevelNodeViewBinder;
import ru.volgorobot.vrcatalog.searchNodeViewBinders.SecondLevelNodeViewBinder;
import ru.volgorobot.vrcatalog.searchNodeViewBinders.FirstLevelNodeViewBinder;
import ru.volgorobot.vrcatalog.searchNodeViewBinders.SecondLevelNodeViewBinder;
public class SearchableNodeViewFactory extends BaseNodeViewFactory {
private Context context;

View File

@ -4,32 +4,37 @@ import java.util.List;
import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Path;
import retrofit2.http.Query;
import ru.volgorobot.vrcatalog.model.DetailModel;
import ru.volgorobot.vrcatalog.model.FirstLevelModel;
import ru.volgorobot.vrcatalog.model.ImageItemModel;
import ru.volgorobot.vrcatalog.model.SecondLevelModel;
import ru.volgorobot.vrcatalog.model.ThirdLevelModel;
public interface VRApi {
@GET("/API/Api.php?action=getFirstLevel")
@GET("/api/level/1")
Call<List<FirstLevelModel>> getFirstLevel();
@GET("/API/Api.php?action=getSecondLevel")
Call<List<SecondLevelModel>> getSecondLevel(@Query("parentTypeID") int parentTypeID);
@GET("/api/level/2")
Call<List<SecondLevelModel>> getSecondLevel(@Query("categoryID") int categoryID);
@GET("/API/Api.php?action=getDetailsByParentID")
Call<List<ThirdLevelModel>> getDetails(@Query("parentID") int parentID);
@GET("/api/level/3")
Call<List<ThirdLevelModel>> getDetails(@Query("subcategoryID") int subcategoryID);
@GET("/API/Api.php?action=getDetailByID")
Call<List<DetailModel>> getDetailByID(@Query("detailID") int detailID);
@GET("/api/item/{id}")
Call<List<DetailModel>> getDetailByID(@Path("id") int itemID);
@GET("/API/Api.php?action=getCategoryByID")
Call<List<FirstLevelModel>> getCategoryByID(@Query("id") int id);
@GET("/api/level/1/{id}")
Call<List<FirstLevelModel>> getCategoryByID(@Path("id") int categoryID);
@GET("/API/Api.php?action=getSubCategoryByID")
Call<List<SecondLevelModel>> getSubCategoryByID(@Query("id") int id);
@GET("/api/level/2/{id}")
Call<List<SecondLevelModel>> getSubCategoryByID(@Path("id") int subcategoryID);
@GET("/API/Api.php?action=getDetailsByName")
@GET("/api/item")
Call<List<ThirdLevelModel>> getDetailsByName(@Query("name") String name);
@GET("/api/item/{id}/images")
Call<List<ImageItemModel>> getImagesByItemID(@Path("id") int itemID);
}

View File

@ -32,7 +32,7 @@ public class CoreModel implements MainContract.MainModel {
@Override
public ArrayList<FirstLevelModel> fetchFirstLevel() throws NetworkErrorException, NullPointerException {
if(vrApi == null) {
if(!isApiNotNull()) {
throw new NullPointerException();
}
final ArrayList<FirstLevelModel> firstLevelModels = new ArrayList<>();
@ -51,7 +51,7 @@ public class CoreModel implements MainContract.MainModel {
@Override
public ArrayList<SecondLevelModel> fetchSecondLevelByParentID(int parentID) throws NetworkErrorException, NullPointerException {
if(vrApi == null) {
if(!isApiNotNull()) {
throw new NullPointerException();
}
final ArrayList<SecondLevelModel> secondLevelModels = new ArrayList<>();
@ -70,7 +70,7 @@ public class CoreModel implements MainContract.MainModel {
@Override
public ArrayList<ThirdLevelModel> fetchThirdLevelByParentID(int parentID) throws NetworkErrorException, NullPointerException {
if(vrApi == null) {
if(!isApiNotNull()) {
throw new NullPointerException();
}
final ArrayList<ThirdLevelModel> thirdLevelModels = new ArrayList<>();
@ -89,7 +89,7 @@ public class CoreModel implements MainContract.MainModel {
@Override
public ArrayList<DetailModel> fetchDetailByID(int detailID) throws NetworkErrorException, NullPointerException {
if(vrApi == null) {
if(!isApiNotNull()) {
throw new NullPointerException();
}
ArrayList<DetailModel> detail = new ArrayList<>();
@ -118,17 +118,13 @@ public class CoreModel implements MainContract.MainModel {
}
@Override
public boolean getApiState() {
if(vrApi != null) {
return true;
} else {
return false;
}
public boolean isApiNotNull() {
return vrApi != null;
}
@Override
public ArrayList<ThirdLevelModel> fetchDetailsByName(String name) throws NetworkErrorException, NullPointerException {
if(vrApi == null) {
if(!isApiNotNull()) {
throw new NullPointerException();
}
final ArrayList<ThirdLevelModel> thirdLevelModels = new ArrayList<>();
@ -147,7 +143,7 @@ public class CoreModel implements MainContract.MainModel {
@Override
public ArrayList<FirstLevelModel> fetchCategoryByID(int id) throws NetworkErrorException, NullPointerException {
if(vrApi == null) {
if(!isApiNotNull()) {
throw new NullPointerException();
}
final ArrayList<FirstLevelModel> firstLevelModels = new ArrayList<>();
@ -166,7 +162,7 @@ public class CoreModel implements MainContract.MainModel {
@Override
public ArrayList<SecondLevelModel> fetchSubCategoryByID(int id) throws NetworkErrorException, NullPointerException {
if(vrApi == null) {
if(!isApiNotNull()) {
throw new NullPointerException();
}
final ArrayList<SecondLevelModel> secondLevelModels = new ArrayList<>();
@ -182,4 +178,23 @@ public class CoreModel implements MainContract.MainModel {
}
return secondLevelModels;
}
@Override
public ArrayList<ImageItemModel> fetchImagesByItemID(int id) throws NetworkErrorException, NullPointerException {
if(!isApiNotNull()) {
throw new NullPointerException();
}
final ArrayList<ImageItemModel> imageItemModels = new ArrayList<>();
try {
Response<List<ImageItemModel>> response = vrApi.getImagesByItemID(id).execute();
if(response.isSuccessful()) {
imageItemModels.addAll(response.body());
} else {
throw new NetworkErrorException(2);
}
} catch (IOException e) {
throw new NetworkErrorException(1);
}
return imageItemModels;
}
}

View File

@ -0,0 +1,40 @@
package ru.volgorobot.vrcatalog.model;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class ImageItemModel {
@SerializedName("DetailID")
@Expose
private Integer detailID;
@SerializedName("image")
@Expose
private String image;
@SerializedName("MD5")
@Expose
private String MD5;
public Integer getDetailID() {
return detailID;
}
public void setDetailID(Integer detailID) {
this.detailID = detailID;
}
public String getImage() {
return image;
}
public void setImage(String image) {
this.image = image;
}
public String getMD5() {
return MD5;
}
public void setMD5(String mD5) {
this.MD5 = mD5;
}
}

View File

@ -2,7 +2,6 @@ package ru.volgorobot.vrcatalog.view;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.Menu;
import android.view.MenuItem;
import ru.volgorobot.vrcatalog.R;

View File

@ -1,94 +1,100 @@
package ru.volgorobot.vrcatalog.view;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.os.Bundle;
import android.support.design.widget.TabLayout;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.text.method.LinkMovementMethod;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.MenuItem;
import android.widget.EditText;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import java.util.HashMap;
import java.util.LinkedHashMap;
import ru.volgorobot.vrcatalog.ItemPresenter;
import ru.volgorobot.vrcatalog.MainContract;
import ru.volgorobot.vrcatalog.R;
import ru.volgorobot.vrcatalog.additional.ImagePagerAdapter;
import ru.volgorobot.vrcatalog.additional.PropertiesListAdapter;
public class DetailActivity extends AppCompatActivity {
TextView nameView;
TextView quantityView;
TextView priceView;
TextView countryView;
TextView analogueView;
TextView datasheetView;
EditText notesView;
public class DetailActivity extends AppCompatActivity implements MainContract.ItemView {
private MainContract.ItemPresenter mPresenter;
private ViewPager viewPager;
private ListView propertiesList;
private ImagePagerAdapter imagePagerAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_detail);
Toolbar toolbar = findViewById(R.id.itemactivity_toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeButtonEnabled(true);
getSupportActionBar().setDisplayShowTitleEnabled(false);
initializeViews();
mPresenter = new ItemPresenter(DetailActivity.this, this);
Intent intent = getIntent();
HashMap<String, String> extrasMap = getIntentExtras(intent);
((TextView) findViewById(R.id.itemName)).setText(intent.getStringExtra("detailName"));
String tmp = intent.getStringExtra("detailPrice");
if(tmp.equals("0")) {
tmp = "Уточните у продавца";
} else {
tmp = tmp + " \u20BD";
}
((TextView) findViewById(R.id.itemPrice)).setText(tmp);
nameView.setText(extrasMap.get("detailName"));
quantityView.setText(extrasMap.get("detailQuantity"));
priceView.setText(extrasMap.get("detailPrice"));
countryView.setText(extrasMap.get("detailCountry"));
analogueView.setText(extrasMap.get("detailAnalogue"));
datasheetView.setText(extrasMap.get("detailDatasheet"));
notesView.setText(extrasMap.get("detailNotes"));
LinkedHashMap<String, String> extrasMap = getIntentExtras(intent);
propertiesList = findViewById(R.id.propertiesList);
PropertiesListAdapter propertiesListAdapter = new PropertiesListAdapter(extrasMap);
propertiesList.setAdapter(propertiesListAdapter);
mPresenter.getImagesByItemID(Integer.parseInt(intent.getStringExtra("itemID")));
}
void initializeViews() {
nameView = findViewById(R.id.name);
quantityView = findViewById(R.id.quantity);
priceView = findViewById(R.id.price);
notesView = findViewById(R.id.notes);
countryView = findViewById(R.id.country);
analogueView = findViewById(R.id.analogue);
datasheetView = findViewById(R.id.datasheet);
datasheetView.setMovementMethod(LinkMovementMethod.getInstance());
viewPager = findViewById(R.id.viewPager);
}
HashMap<String, String> getIntentExtras(Intent intent) {
HashMap<String, String> hashMap = new HashMap<>();
LinkedHashMap<String, String> getIntentExtras(Intent intent) {
LinkedHashMap<String, String> hashMap = new LinkedHashMap<>();
String tmp;
tmp = intent.getStringExtra("detailName");
hashMap.put("detailName", tmp);
tmp = intent.getStringExtra("detailQuantity");
if(tmp.equals("0")) {
tmp = "Под заказ";
}
hashMap.put("detailQuantity", tmp);
tmp = intent.getStringExtra("detailPrice");
if(tmp.equals("0")) {
tmp = "Уточните у продавца";
}
hashMap.put("detailPrice", tmp);
hashMap.put("Количество", tmp);
tmp = intent.getStringExtra("detailCountry");
if(tmp.equals("")) {
tmp = "Не указано";
}
hashMap.put("detailCountry", tmp);
hashMap.put("Страна изготовления", tmp);
tmp = intent.getStringExtra("detailAnalogue");
if(tmp.equals("")) {
tmp = "Нет аналогов";
}
hashMap.put("detailAnalogue", tmp);
hashMap.put("Аналоги", tmp);
tmp = intent.getStringExtra("detailDatasheet");
if(!tmp.matches("\\S")) {
if(!(tmp.trim().length() > 0)) {
tmp = "Не указано";
}
hashMap.put("detailDatasheet", tmp);
hashMap.put("Техническая спецификация", tmp);
tmp = intent.getStringExtra("detailNotes");
if(tmp != null && tmp.equals("")) {
@ -96,7 +102,7 @@ public class DetailActivity extends AppCompatActivity {
} else if (tmp == null){
tmp = "Нет описания";
}
hashMap.put("detailNotes", tmp);
hashMap.put("Описание", tmp);
return hashMap;
}
@ -110,4 +116,126 @@ public class DetailActivity extends AppCompatActivity {
}
return super.onOptionsItemSelected(item);
}
@Override
public void onFailureAnswer(int errorCode) {
switch (errorCode) {
case 1: {
Toast.makeText(DetailActivity.this, "Ошибка сети. Проверьте подключение к сети или данные подключения к API!", Toast.LENGTH_LONG).show();
Log.e("DetailActivity", "Network Error! Re-check your connection credentials or network settings!");
break;
}
case 2: {
Toast.makeText(DetailActivity.this, "Ответ от сервера неверен! Перепроверьте данные подключения!", Toast.LENGTH_LONG).show();
Log.e("DetailActivity", "Answer of server is wrong! Re-check your connection credentials!");
break;
}
case 3: {
Toast.makeText(DetailActivity.this, "Вы ввели неверный URL. Пример: http://example.ru", Toast.LENGTH_LONG).show();
Log.e("DetailActivity", "Invalid-formatted URL. Please, check URL (change his if it need) and try again.");
break;
}
}
}
@Override
public void setViewPagerContent(String[] uris) {
imagePagerAdapter = new ImagePagerAdapter(DetailActivity.this, uris);
TabLayout tabLayout = (TabLayout) findViewById(R.id.tabDots);
viewPager.setAdapter(imagePagerAdapter);
setViewPagerScrollListener();
tabLayout.setupWithViewPager(viewPager);
imagePagerAdapter.notifyDataSetChanged();
}
private int getImageAverageColor(Bitmap bitmap) {
if (null == bitmap) return Color.TRANSPARENT;
int redBucket = 0;
int greenBucket = 0;
int blueBucket = 0;
int alphaBucket = 0;
boolean hasAlpha = bitmap.hasAlpha();
int pixelCount = bitmap.getWidth() * bitmap.getHeight();
int[] pixels = new int[pixelCount];
bitmap.getPixels(pixels, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight());
for (int y = 0, h = bitmap.getHeight(); y < h; y++)
{
for (int x = 0, w = bitmap.getWidth(); x < w; x++)
{
int color = pixels[x + y * w]; // x + y * width
redBucket += (color >> 16) & 0xFF; // Color.red
greenBucket += (color >> 8) & 0xFF; // Color.greed
blueBucket += (color & 0xFF); // Color.blue
if (hasAlpha) alphaBucket += (color >>> 24); // Color.alpha
}
}
return Color.argb(
(hasAlpha) ? (alphaBucket / pixelCount) : 255,
redBucket / pixelCount,
greenBucket / pixelCount,
blueBucket / pixelCount);
}
private void setViewPagerScrollListener() {
ViewPager.OnPageChangeListener listener = new ViewPager.OnPageChangeListener() {
boolean firstImageProcessed = false;
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
if(position == 0 && !firstImageProcessed) {
viewPager.setBackgroundColor(getImageAverageColor(imagePagerAdapter.getBitmap(position)));
firstImageProcessed = true;
}
}
@Override
public void onPageSelected(int position) {
if(firstImageProcessed) {
viewPager.setBackgroundColor(getImageAverageColor(imagePagerAdapter.getBitmap(position)));
}
}
@Override
public void onPageScrollStateChanged(int state) {
//
}
};
viewPager.setOnPageChangeListener(listener);
}
public static boolean setListViewHeightBasedOnItems(ListView listView) {
ListAdapter listAdapter = listView.getAdapter();
if (listAdapter != null) {
int numberOfItems = listAdapter.getCount();
// Get total height of all items.
int totalItemsHeight = 0;
for (int itemPos = 0; itemPos < numberOfItems; itemPos++) {
View item = listAdapter.getView(itemPos, null, listView);
item.measure(0, 0);
totalItemsHeight += item.getMeasuredHeight();
}
// Get total height of all item dividers.
int totalDividersHeight = listView.getDividerHeight() *
(numberOfItems - 1);
// Set list height.
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalItemsHeight + totalDividersHeight;
listView.setLayoutParams(params);
listView.requestLayout();
return true;
} else {
return false;
}
}
}

View File

@ -19,7 +19,10 @@ import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import java.util.ArrayList;
@ -39,6 +42,9 @@ public class MainActivity extends AppCompatActivity
private TreeView treeView;
private TreeNode rootNode = TreeNode.root();
private SwipeRefreshLayout mSwipeRefreshLayout;
private ImageView mConnectionErrorImageView;
private ViewGroup mTreeViewContainer;
private TextView mErrorTextView;
@Override
protected void onCreate(Bundle savedInstanceState) {
@ -56,19 +62,25 @@ public class MainActivity extends AppCompatActivity
NavigationView navigationView = findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
mSwipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipeRefreshLayout);
mSwipeRefreshLayout = findViewById(R.id.swipeRefreshLayout);
mSwipeRefreshLayout.setOnRefreshListener(MainActivity.this);
mSwipeRefreshLayout.setColorSchemeResources(R.color.colorPrimary);
mErrorTextView = findViewById(R.id.errorTextView);
mConnectionErrorImageView = findViewById(R.id.connectionErrorImageView);
mPresenter = new MainPresenter(this, MainActivity.this);
treeView = new TreeView(rootNode, MainActivity.this, new NodeViewFactory(MainActivity.this, this, this.mPresenter.getCoreModel()));
treeView.setItemAnimator(new DefaultItemAnimator());
((ViewGroup) findViewById(R.id.treeViewContainer)).addView(treeView.getView());
mTreeViewContainer = findViewById(R.id.treeViewContainer);
mTreeViewContainer.addView(treeView.getView());
mSwipeRefreshLayout.setRefreshing(true);
mPresenter.getFirstLevel();
}
@Override
public void onBackPressed() {
DrawerLayout drawer = findViewById(R.id.drawer_layout);
@ -111,26 +123,44 @@ public class MainActivity extends AppCompatActivity
@Override
public void onRefresh() {
mConnectionErrorImageView.setVisibility(View.INVISIBLE);
mErrorTextView.setVisibility(View.INVISIBLE);
mTreeViewContainer.setVisibility(View.VISIBLE);
rootNode.setChildren(new ArrayList<TreeNode>());
treeView.refreshTreeView();
mPresenter.getFirstLevel();
}
public void onFailureAnswer(int errorCode) {
switch (errorCode) {
case 1: {
mErrorTextView.setText("Ошибка сети. Проверьте подключение к сети или данные подключения к API!");
Toast.makeText(MainActivity.this, "Ошибка сети. Проверьте подключение к сети или данные подключения к API!", Toast.LENGTH_LONG).show();
Log.e("VRCatalog", "Network Error! Re-check your connection credentials or network settings! Technical info: null");
Log.e("MainActivity", "Network Error! Re-check your connection credentials or network settings!");
mSwipeRefreshLayout.setRefreshing(false);
mTreeViewContainer.setVisibility(View.GONE);
mConnectionErrorImageView.setVisibility(View.VISIBLE);
mErrorTextView.setVisibility(View.VISIBLE);
break;
}
case 2: {
mErrorTextView.setText("Ответ от сервера неверен! Перепроверьте данные подключения!");
Toast.makeText(MainActivity.this, "Ответ от сервера неверен! Перепроверьте данные подключения!", Toast.LENGTH_LONG).show();
Log.e("VRCatalog", "Answer of server is wrong! Re-check your connection credentials! Technical info: null");
Log.e("MainActivity", "Answer of server is wrong! Re-check your connection credentials!");
mSwipeRefreshLayout.setRefreshing(false);
mTreeViewContainer.setVisibility(View.GONE);
mConnectionErrorImageView.setVisibility(View.VISIBLE);
mErrorTextView.setVisibility(View.VISIBLE);
break;
}
case 3: {
mErrorTextView.setText("Вы ввели неверный URL. Пример: http://example.ru");
Toast.makeText(this, "Вы ввели неверный URL. Пример: http://example.ru", Toast.LENGTH_LONG).show();
Log.e("MainActivity", "Invalid-formatted URL. Please, check URL (change his if it need) and try again.");
mSwipeRefreshLayout.setRefreshing(false);
mTreeViewContainer.setVisibility(View.GONE);
mConnectionErrorImageView.setVisibility(View.VISIBLE);
mErrorTextView.setVisibility(View.VISIBLE);
break;
}
}

View File

@ -2,14 +2,17 @@ package ru.volgorobot.vrcatalog.view;
import android.app.SearchManager;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.widget.NestedScrollView;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.DefaultItemAnimator;
import android.util.Log;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.ArrayList;
@ -27,6 +30,9 @@ public class SearchableActivity extends AppCompatActivity implements MainContrac
private String detailName;
private TreeView treeView;
private TreeNode rootNode = TreeNode.root();
private ImageView mConnectionErrorImageView;
private NestedScrollView mTreeViewContainer;
private TextView mErrorTextView;
@Override
protected void onCreate(Bundle savedInstanceState) {
@ -41,6 +47,10 @@ public class SearchableActivity extends AppCompatActivity implements MainContrac
mSwipeRefreshLayout.setOnRefreshListener(SearchableActivity.this);
mSwipeRefreshLayout.setColorSchemeResources(R.color.colorPrimary);
mConnectionErrorImageView = findViewById(R.id.searchableConnectionErrorImageView);
mTreeViewContainer = findViewById(R.id.searchableTreeViewContainer);
mErrorTextView = findViewById(R.id.searchableErrorTextView);
treeView = new TreeView(rootNode, SearchableActivity.this, new SearchableNodeViewFactory(SearchableActivity.this, this));
treeView.setItemAnimator(new DefaultItemAnimator());
((ViewGroup) findViewById(R.id.searchableTreeViewContainer)).addView(treeView.getView());
@ -62,20 +72,32 @@ public class SearchableActivity extends AppCompatActivity implements MainContrac
public void onFailureAnswer(int errorCode) {
switch (errorCode) {
case 1: {
Toast.makeText(SearchableActivity.this, "Ошибка сети. Проверьте подключение к сети или данные подключения к API!", Toast.LENGTH_LONG).show();
mErrorTextView.setText("Ошибка сети. Проверьте подключение к сети или данные подключения к API!");
//Toast.makeText(SearchableActivity.this, "Ошибка сети. Проверьте подключение к сети или данные подключения к API!", Toast.LENGTH_LONG).show();
Log.e("VRCatalog", "Network Error! Re-check your connection credentials or network settings! Technical info: null");
mSwipeRefreshLayout.setRefreshing(false);
mTreeViewContainer.setVisibility(View.GONE);
mConnectionErrorImageView.setVisibility(View.VISIBLE);
mErrorTextView.setVisibility(View.VISIBLE);
break;
}
case 2: {
Toast.makeText(SearchableActivity.this, "Ответ от сервера неверен! Перепроверьте данные подключения!", Toast.LENGTH_LONG).show();
mErrorTextView.setText("Ответ от сервера неверен! Перепроверьте данные подключения!");
//Toast.makeText(SearchableActivity.this, "Ответ от сервера неверен! Перепроверьте данные подключения!", Toast.LENGTH_LONG).show();
Log.e("VRCatalog", "Answer of server is wrong! Re-check your connection credentials! Technical info: null");
mSwipeRefreshLayout.setRefreshing(false);
mTreeViewContainer.setVisibility(View.GONE);
mConnectionErrorImageView.setVisibility(View.VISIBLE);
mErrorTextView.setVisibility(View.VISIBLE);
break;
}
case 3: {
Toast.makeText(SearchableActivity.this, "Вы ввели неверный URL. Пример: http://example.ru", Toast.LENGTH_LONG).show();
mErrorTextView.setText("Вы ввели неверный URL. Пример: http://example.ru");
//Toast.makeText(SearchableActivity.this, "Вы ввели неверный URL. Пример: http://example.ru", Toast.LENGTH_LONG).show();
mSwipeRefreshLayout.setRefreshing(false);
mTreeViewContainer.setVisibility(View.GONE);
mConnectionErrorImageView.setVisibility(View.VISIBLE);
mErrorTextView.setVisibility(View.VISIBLE);
break;
}
}
@ -83,6 +105,11 @@ public class SearchableActivity extends AppCompatActivity implements MainContrac
@Override
public void onRefresh() {
mConnectionErrorImageView.setVisibility(View.INVISIBLE);
mErrorTextView.setVisibility(View.INVISIBLE);
mTreeViewContainer.setVisibility(View.VISIBLE);
rootNode.setChildren(new ArrayList<TreeNode>());
treeView.refreshTreeView();
searchablePresenter.fetchDetailsTreeByName(detailName);
}

View File

@ -1,7 +1,6 @@
package ru.volgorobot.vrcatalog.view;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import ru.volgorobot.vrcatalog.R;

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#A9A9A9"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M19.35,10.04C18.67,6.59 15.64,4 12,4c-1.48,0 -2.85,0.43 -4.01,1.17l1.46,1.46C10.21,6.23 11.08,6 12,6c3.04,0 5.5,2.46 5.5,5.5v0.5H19c1.66,0 3,1.34 3,3 0,1.13 -0.64,2.11 -1.56,2.62l1.45,1.45C23.16,18.16 24,16.68 24,15c0,-2.64 -2.05,-4.78 -4.65,-4.96zM3,5.27l2.75,2.74C2.56,8.15 0,10.77 0,14c0,3.31 2.69,6 6,6h11.73l2,2L21,20.73 4.27,4 3,5.27zM7.73,10l8,8H6c-2.21,0 -4,-1.79 -4,-4s1.79,-4 4,-4h1.73z"/>
</vector>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:innerRadius="0dp"
android:shape="ring"
android:thickness="2dp"
android:useLevel="false">
<solid android:color="@android:color/darker_gray"/>
</shape>

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<shape
android:innerRadius="0dp"
android:shape="ring"
android:thickness="4dp"
android:useLevel="false"
xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/colorAccent"/>
</shape>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/tab_indicator_selected"
android:state_selected="true"/>
<item android:drawable="@drawable/tab_indicator_default"/>
</selector>

View File

@ -1,155 +1,78 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<android.support.design.widget.CoordinatorLayout 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="match_parent"
tools:layout_editor_absoluteY="81dp">
android:layout_height="wrap_content">
<TextView
android:id="@+id/name_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:text="Название: "
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
app:layout_constraintBaseline_toBaselineOf="@+id/name"
app:layout_constraintStart_toStartOf="parent" />
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<android.support.design.widget.CollapsingToolbarLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_scrollFlags="scroll|enterAlways">
<TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="TextView"
app:layout_constraintStart_toEndOf="@+id/name_text"
app:layout_constraintTop_toTopOf="parent" />
<android.support.v4.view.ViewPager
android:id="@+id/viewPager"
android:layout_width="wrap_content"
android:layout_height="311dp"
app:layout_collapseMode="parallax" />
<android.support.design.widget.TabLayout
android:id="@+id/tabDots"
android:layout_width="match_parent"
android:layout_height="62dp"
android:layout_gravity="bottom"
app:tabBackground="@drawable/tab_selector"
app:tabGravity="center"
app:tabIndicatorHeight="0dp" />
<android.support.v7.widget.Toolbar
android:id="@+id/itemactivity_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
android:theme="@style/ItemActionBar"/>
<TextView
android:id="@+id/notes_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="172dp"
android:text="Описание: "
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
app:layout_constraintStart_toStartOf="@+id/notes"
app:layout_constraintTop_toTopOf="parent" />
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<TextView
android:id="@+id/quantity_text"
android:layout_width="wrap_content"
android:layout_height="19dp"
android:text="Количество на складе: "
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
app:layout_constraintBaseline_toBaselineOf="@+id/quantity"
app:layout_constraintStart_toStartOf="@+id/name_text" />
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="619dp"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
android:fillViewport="true">
<TextView
android:id="@+id/quantity"
android:layout_width="wrap_content"
android:layout_height="19dp"
android:layout_marginTop="20dp"
android:layout_marginBottom="20dp"
android:text="TextView"
app:layout_constraintBottom_toBottomOf="@+id/price"
app:layout_constraintStart_toEndOf="@+id/quantity_text"
app:layout_constraintTop_toTopOf="@+id/name" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<EditText
android:id="@+id/notes"
android:layout_width="0dp"
android:layout_height="99dp"
android:layout_marginStart="16dp"
android:layout_marginTop="18dp"
android:layout_marginEnd="16dp"
android:ems="10"
android:focusable="false"
android:focusableInTouchMode="false"
android:inputType="textMultiLine"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/notes_text">
<TextView
android:id="@+id/itemName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="9dp"
android:text="Item Name"
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
android:textSize="30sp" />
<requestFocus />
</EditText>
<TextView
android:id="@+id/itemPrice"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="9dp"
android:text="Item Price"
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
android:textSize="24sp" />
<TextView
android:id="@+id/price_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Цена: "
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
app:layout_constraintBaseline_toBaselineOf="@+id/price"
app:layout_constraintStart_toStartOf="@+id/quantity_text" />
<TextView
android:id="@+id/price"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="11dp"
android:text="TextView"
app:layout_constraintBottom_toTopOf="@+id/country_text"
app:layout_constraintStart_toEndOf="@+id/price_text" />
<TextView
android:id="@+id/country_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:text="Страна изготовления: "
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
app:layout_constraintBaseline_toBaselineOf="@+id/country"
app:layout_constraintStart_toStartOf="parent" />
<TextView
android:id="@+id/country"
android:layout_width="wrap_content"
android:layout_height="19dp"
android:layout_marginTop="86dp"
android:layout_marginBottom="86dp"
android:text="TextView"
app:layout_constraintBottom_toBottomOf="@+id/notes_text"
app:layout_constraintStart_toEndOf="@+id/country_text"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/analogue_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:text="Аналоги: "
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
app:layout_constraintBaseline_toBaselineOf="@+id/analogue"
app:layout_constraintStart_toStartOf="parent" />
<TextView
android:id="@+id/analogue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="9dp"
android:text="TextView"
app:layout_constraintStart_toEndOf="@+id/analogue_text"
app:layout_constraintTop_toBottomOf="@+id/country_text" />
<TextView
android:id="@+id/datasheet_text"
android:layout_width="wrap_content"
android:layout_height="19dp"
android:layout_marginStart="16dp"
android:text="Техническая спецификация: "
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
app:layout_constraintBaseline_toBaselineOf="@+id/datasheet"
app:layout_constraintStart_toStartOf="parent" />
<TextView
android:id="@+id/datasheet"
android:layout_width="wrap_content"
android:layout_height="18dp"
android:layout_marginTop="128dp"
android:layout_marginBottom="127dp"
android:autoLink="web"
android:text="TextView"
app:layout_constraintBottom_toBottomOf="@+id/notes"
app:layout_constraintStart_toEndOf="@+id/datasheet_text"
app:layout_constraintTop_toTopOf="@+id/name" />
</android.support.constraint.ConstraintLayout>
<ListView
android:id="@+id/propertiesList"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
android:nestedScrollingEnabled="false"/>
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout>

View File

@ -10,12 +10,45 @@
android:orientation="horizontal"
android:id="@+id/searchableSwipeRefreshLayout">
<android.support.v4.widget.NestedScrollView
android:id="@+id/searchableTreeViewContainer"
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbarAlwaysDrawVerticalTrack="true">
</android.support.v4.widget.NestedScrollView>
android:layout_height="match_parent">
<android.support.v4.widget.NestedScrollView
android:id="@+id/searchableTreeViewContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbarAlwaysDrawVerticalTrack="true">
</android.support.v4.widget.NestedScrollView>
<ImageView
android:id="@+id/searchableConnectionErrorImageView"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="70dp"
android:layout_marginBottom="52dp"
android:src="@drawable/ic_cloud_off_gray_24dp"
android:visibility="invisible"
app:layout_constraintBottom_toTopOf="@+id/searchableErrorTextView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/searchableErrorTextView"
android:layout_width="0dp"
android:layout_height="77dp"
android:layout_marginStart="9dp"
android:layout_marginEnd="9dp"
android:layout_marginBottom="68dp"
android:text=""
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
android:visibility="invisible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/searchableConnectionErrorImageView" />
</android.support.constraint.ConstraintLayout>
</android.support.v4.widget.SwipeRefreshLayout>

View File

@ -10,12 +10,53 @@
android:orientation="horizontal"
android:id="@+id/swipeRefreshLayout">
<android.support.v4.widget.NestedScrollView
android:id="@+id/treeViewContainer"
<android.support.constraint.ConstraintLayout
android:id="@+id/mainActivityConstraint"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbarAlwaysDrawVerticalTrack="true">
</android.support.v4.widget.NestedScrollView>
android:layout_height="match_parent">
<android.support.v4.widget.NestedScrollView
android:id="@+id/treeViewContainer"
android:layout_width="0dp"
android:layout_height="0dp"
android:scrollbarAlwaysDrawVerticalTrack="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="1.0">
</android.support.v4.widget.NestedScrollView>
<ImageView
android:id="@+id/connectionErrorImageView"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="70dp"
android:layout_marginBottom="52dp"
android:src="@drawable/ic_cloud_off_gray_24dp"
android:visibility="invisible"
app:layout_constraintBottom_toTopOf="@+id/errorTextView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/errorTextView"
android:layout_width="0dp"
android:layout_height="77dp"
android:layout_marginStart="9dp"
android:layout_marginEnd="9dp"
android:layout_marginBottom="68dp"
android:text=""
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
android:visibility="invisible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/connectionErrorImageView" />
</android.support.constraint.ConstraintLayout>
</android.support.v4.widget.SwipeRefreshLayout>

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/propertyNameView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Property Name"
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
android:textSize="18sp"
android:layout_marginLeft="9dp"/>
<TextView
android:id="@+id/propertyValueView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Property Value"
android:layout_marginLeft="9dp"
android:autoLink="web"/>
</LinearLayout>

View File

@ -5,4 +5,17 @@
<item name="windowNoTitle">true</item>
<item name="android:statusBarColor">@android:color/transparent</item>
</style>
<style name="ItemActivityTheme" parent="AppTheme">
<item name="android:windowTranslucentStatus">true</item>
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
</style>
<style name="MyActionBar" parent="Widget.AppCompat.ActionBar.Solid">
<item name="android:background">@android:color/transparent</item>
<item name="background">@android:color/transparent</item>
</style>
<style name="ItemActionBar" parent="ItemActivityTheme">
<item name="android:textColorPrimary">@android:color/white</item>
<item name="android:textColorSecondary">@android:color/white</item>
</style>
</resources>

View File

@ -17,4 +17,8 @@
<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />
<style name="ItemActivityTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="android:windowTranslucentStatus">true</item>
</style>
</resources>

View File

@ -8,7 +8,7 @@ buildscript {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.3.0'
classpath 'com.android.tools.build:gradle:3.3.1'
// NOTE: Do not place your application dependencies here; they belong