diff --git a/.idea/assetWizardSettings.xml b/.idea/assetWizardSettings.xml index 978ee3f..56880e2 100644 --- a/.idea/assetWizardSettings.xml +++ b/.idea/assetWizardSettings.xml @@ -18,7 +18,7 @@ @@ -28,8 +28,8 @@ diff --git a/.idea/caches/gradle_models.ser b/.idea/caches/gradle_models.ser new file mode 100644 index 0000000..efedd02 Binary files /dev/null and b/.idea/caches/gradle_models.ser differ diff --git a/.idea/render.experimental.xml b/.idea/render.experimental.xml new file mode 100644 index 0000000..8ec256a --- /dev/null +++ b/.idea/render.experimental.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml index 35eb1dd..8306744 100644 --- a/.idea/vcs.xml +++ b/.idea/vcs.xml @@ -2,5 +2,6 @@ + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 3b89585..aa59440 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -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' +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index f210ba2..e5aa12d 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -23,7 +23,9 @@ - + >>() { + @Override + protected ResultWithErrorCode> doInBackground(Void... voids) { + ArrayList 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> result) { + super.onPostExecute(result); + switch (result.getErrorCode()) { + case 0: { + //mView.setViewPagerContent(result.getData()); + ArrayList bitmaps = new ArrayList<>(); + ArrayList 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); + } +} diff --git a/app/src/main/java/ru/volgorobot/vrcatalog/MainContract.java b/app/src/main/java/ru/volgorobot/vrcatalog/MainContract.java index 4bf200d..62247c0 100644 --- a/app/src/main/java/ru/volgorobot/vrcatalog/MainContract.java +++ b/app/src/main/java/ru/volgorobot/vrcatalog/MainContract.java @@ -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 fetchThirdLevelByParentID(int parentID) throws NetworkErrorException, NullPointerException; ArrayList fetchDetailByID(int detailID) throws NetworkErrorException, NullPointerException; void reinitializeApi() throws IllegalStateException; - boolean getApiState(); + boolean isApiNotNull(); ArrayList fetchDetailsByName(String name) throws NetworkErrorException, NullPointerException; ArrayList fetchCategoryByID(int id) throws NetworkErrorException, NullPointerException; ArrayList fetchSubCategoryByID(int id) throws NetworkErrorException, NullPointerException; + ArrayList 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); + } } diff --git a/app/src/main/java/ru/volgorobot/vrcatalog/ViewBinderPresenter.java b/app/src/main/java/ru/volgorobot/vrcatalog/ViewBinderPresenter.java index 5f02f40..9d1d236 100644 --- a/app/src/main/java/ru/volgorobot/vrcatalog/ViewBinderPresenter.java +++ b/app/src/main/java/ru/volgorobot/vrcatalog/ViewBinderPresenter.java @@ -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()); diff --git a/app/src/main/java/ru/volgorobot/vrcatalog/additional/ImagePagerAdapter.java b/app/src/main/java/ru/volgorobot/vrcatalog/additional/ImagePagerAdapter.java new file mode 100644 index 0000000..69a63bb --- /dev/null +++ b/app/src/main/java/ru/volgorobot/vrcatalog/additional/ImagePagerAdapter.java @@ -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; + } +} diff --git a/app/src/main/java/ru/volgorobot/vrcatalog/additional/PropertiesListAdapter.java b/app/src/main/java/ru/volgorobot/vrcatalog/additional/PropertiesListAdapter.java new file mode 100644 index 0000000..15941d7 --- /dev/null +++ b/app/src/main/java/ru/volgorobot/vrcatalog/additional/PropertiesListAdapter.java @@ -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 mData; + private String[] mKeys; + + public PropertiesListAdapter(LinkedHashMap 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; + } +} diff --git a/app/src/main/java/ru/volgorobot/vrcatalog/additional/SearchableNodeViewFactory.java b/app/src/main/java/ru/volgorobot/vrcatalog/additional/SearchableNodeViewFactory.java index 15274d1..baca273 100644 --- a/app/src/main/java/ru/volgorobot/vrcatalog/additional/SearchableNodeViewFactory.java +++ b/app/src/main/java/ru/volgorobot/vrcatalog/additional/SearchableNodeViewFactory.java @@ -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; diff --git a/app/src/main/java/ru/volgorobot/vrcatalog/api/VRApi.java b/app/src/main/java/ru/volgorobot/vrcatalog/api/VRApi.java index 40b8ce3..cc29f58 100644 --- a/app/src/main/java/ru/volgorobot/vrcatalog/api/VRApi.java +++ b/app/src/main/java/ru/volgorobot/vrcatalog/api/VRApi.java @@ -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> getFirstLevel(); - @GET("/API/Api.php?action=getSecondLevel") - Call> getSecondLevel(@Query("parentTypeID") int parentTypeID); + @GET("/api/level/2") + Call> getSecondLevel(@Query("categoryID") int categoryID); - @GET("/API/Api.php?action=getDetailsByParentID") - Call> getDetails(@Query("parentID") int parentID); + @GET("/api/level/3") + Call> getDetails(@Query("subcategoryID") int subcategoryID); - @GET("/API/Api.php?action=getDetailByID") - Call> getDetailByID(@Query("detailID") int detailID); + @GET("/api/item/{id}") + Call> getDetailByID(@Path("id") int itemID); - @GET("/API/Api.php?action=getCategoryByID") - Call> getCategoryByID(@Query("id") int id); + @GET("/api/level/1/{id}") + Call> getCategoryByID(@Path("id") int categoryID); - @GET("/API/Api.php?action=getSubCategoryByID") - Call> getSubCategoryByID(@Query("id") int id); + @GET("/api/level/2/{id}") + Call> getSubCategoryByID(@Path("id") int subcategoryID); - @GET("/API/Api.php?action=getDetailsByName") + @GET("/api/item") Call> getDetailsByName(@Query("name") String name); + + @GET("/api/item/{id}/images") + Call> getImagesByItemID(@Path("id") int itemID); } diff --git a/app/src/main/java/ru/volgorobot/vrcatalog/model/CoreModel.java b/app/src/main/java/ru/volgorobot/vrcatalog/model/CoreModel.java index 7a3ee03..22eba65 100644 --- a/app/src/main/java/ru/volgorobot/vrcatalog/model/CoreModel.java +++ b/app/src/main/java/ru/volgorobot/vrcatalog/model/CoreModel.java @@ -32,7 +32,7 @@ public class CoreModel implements MainContract.MainModel { @Override public ArrayList fetchFirstLevel() throws NetworkErrorException, NullPointerException { - if(vrApi == null) { + if(!isApiNotNull()) { throw new NullPointerException(); } final ArrayList firstLevelModels = new ArrayList<>(); @@ -51,7 +51,7 @@ public class CoreModel implements MainContract.MainModel { @Override public ArrayList fetchSecondLevelByParentID(int parentID) throws NetworkErrorException, NullPointerException { - if(vrApi == null) { + if(!isApiNotNull()) { throw new NullPointerException(); } final ArrayList secondLevelModels = new ArrayList<>(); @@ -70,7 +70,7 @@ public class CoreModel implements MainContract.MainModel { @Override public ArrayList fetchThirdLevelByParentID(int parentID) throws NetworkErrorException, NullPointerException { - if(vrApi == null) { + if(!isApiNotNull()) { throw new NullPointerException(); } final ArrayList thirdLevelModels = new ArrayList<>(); @@ -89,7 +89,7 @@ public class CoreModel implements MainContract.MainModel { @Override public ArrayList fetchDetailByID(int detailID) throws NetworkErrorException, NullPointerException { - if(vrApi == null) { + if(!isApiNotNull()) { throw new NullPointerException(); } ArrayList 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 fetchDetailsByName(String name) throws NetworkErrorException, NullPointerException { - if(vrApi == null) { + if(!isApiNotNull()) { throw new NullPointerException(); } final ArrayList thirdLevelModels = new ArrayList<>(); @@ -147,7 +143,7 @@ public class CoreModel implements MainContract.MainModel { @Override public ArrayList fetchCategoryByID(int id) throws NetworkErrorException, NullPointerException { - if(vrApi == null) { + if(!isApiNotNull()) { throw new NullPointerException(); } final ArrayList firstLevelModels = new ArrayList<>(); @@ -166,7 +162,7 @@ public class CoreModel implements MainContract.MainModel { @Override public ArrayList fetchSubCategoryByID(int id) throws NetworkErrorException, NullPointerException { - if(vrApi == null) { + if(!isApiNotNull()) { throw new NullPointerException(); } final ArrayList secondLevelModels = new ArrayList<>(); @@ -182,4 +178,23 @@ public class CoreModel implements MainContract.MainModel { } return secondLevelModels; } + + @Override + public ArrayList fetchImagesByItemID(int id) throws NetworkErrorException, NullPointerException { + if(!isApiNotNull()) { + throw new NullPointerException(); + } + final ArrayList imageItemModels = new ArrayList<>(); + try { + Response> 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; + } } diff --git a/app/src/main/java/ru/volgorobot/vrcatalog/model/ImageItemModel.java b/app/src/main/java/ru/volgorobot/vrcatalog/model/ImageItemModel.java new file mode 100644 index 0000000..cf14302 --- /dev/null +++ b/app/src/main/java/ru/volgorobot/vrcatalog/model/ImageItemModel.java @@ -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; + } +} diff --git a/app/src/main/java/ru/volgorobot/vrcatalog/view/AboutActivity.java b/app/src/main/java/ru/volgorobot/vrcatalog/view/AboutActivity.java index 77ef4fe..6dc752c 100644 --- a/app/src/main/java/ru/volgorobot/vrcatalog/view/AboutActivity.java +++ b/app/src/main/java/ru/volgorobot/vrcatalog/view/AboutActivity.java @@ -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; diff --git a/app/src/main/java/ru/volgorobot/vrcatalog/view/DetailActivity.java b/app/src/main/java/ru/volgorobot/vrcatalog/view/DetailActivity.java index 8af69ba..14ea6db 100644 --- a/app/src/main/java/ru/volgorobot/vrcatalog/view/DetailActivity.java +++ b/app/src/main/java/ru/volgorobot/vrcatalog/view/DetailActivity.java @@ -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 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 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 getIntentExtras(Intent intent) { - HashMap hashMap = new HashMap<>(); + LinkedHashMap getIntentExtras(Intent intent) { + LinkedHashMap 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; + } + + } } diff --git a/app/src/main/java/ru/volgorobot/vrcatalog/view/MainActivity.java b/app/src/main/java/ru/volgorobot/vrcatalog/view/MainActivity.java index a89b0f9..117e17d 100644 --- a/app/src/main/java/ru/volgorobot/vrcatalog/view/MainActivity.java +++ b/app/src/main/java/ru/volgorobot/vrcatalog/view/MainActivity.java @@ -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()); + 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; } } diff --git a/app/src/main/java/ru/volgorobot/vrcatalog/view/SearchableActivity.java b/app/src/main/java/ru/volgorobot/vrcatalog/view/SearchableActivity.java index 612fe25..19d1a40 100644 --- a/app/src/main/java/ru/volgorobot/vrcatalog/view/SearchableActivity.java +++ b/app/src/main/java/ru/volgorobot/vrcatalog/view/SearchableActivity.java @@ -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()); + treeView.refreshTreeView(); searchablePresenter.fetchDetailsTreeByName(detailName); } diff --git a/app/src/main/java/ru/volgorobot/vrcatalog/view/SettingsActivity.java b/app/src/main/java/ru/volgorobot/vrcatalog/view/SettingsActivity.java index 0e0714b..8f57d8a 100644 --- a/app/src/main/java/ru/volgorobot/vrcatalog/view/SettingsActivity.java +++ b/app/src/main/java/ru/volgorobot/vrcatalog/view/SettingsActivity.java @@ -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; diff --git a/app/src/main/res/drawable/ic_cloud_off_gray_24dp.xml b/app/src/main/res/drawable/ic_cloud_off_gray_24dp.xml new file mode 100644 index 0000000..821958f --- /dev/null +++ b/app/src/main/res/drawable/ic_cloud_off_gray_24dp.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/tab_indicator_default.xml b/app/src/main/res/drawable/tab_indicator_default.xml new file mode 100644 index 0000000..871dfba --- /dev/null +++ b/app/src/main/res/drawable/tab_indicator_default.xml @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/tab_indicator_selected.xml b/app/src/main/res/drawable/tab_indicator_selected.xml new file mode 100644 index 0000000..83daff8 --- /dev/null +++ b/app/src/main/res/drawable/tab_indicator_selected.xml @@ -0,0 +1,9 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/tab_selector.xml b/app/src/main/res/drawable/tab_selector.xml new file mode 100644 index 0000000..001747c --- /dev/null +++ b/app/src/main/res/drawable/tab_selector.xml @@ -0,0 +1,8 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_detail.xml b/app/src/main/res/layout/activity_detail.xml index 5727204..05af980 100644 --- a/app/src/main/res/layout/activity_detail.xml +++ b/app/src/main/res/layout/activity_detail.xml @@ -1,155 +1,78 @@ - + android:layout_height="wrap_content"> - + + - + + + - + + - + - + - + - - + - - - - - - - - - - - - - - - - \ No newline at end of file + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_searchable.xml b/app/src/main/res/layout/activity_searchable.xml index 3af0744..4bdcf45 100644 --- a/app/src/main/res/layout/activity_searchable.xml +++ b/app/src/main/res/layout/activity_searchable.xml @@ -10,12 +10,45 @@ android:orientation="horizontal" android:id="@+id/searchableSwipeRefreshLayout"> - - + android:layout_height="match_parent"> + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/content_main.xml b/app/src/main/res/layout/content_main.xml index 88dce18..e3e2877 100644 --- a/app/src/main/res/layout/content_main.xml +++ b/app/src/main/res/layout/content_main.xml @@ -10,12 +10,53 @@ android:orientation="horizontal" android:id="@+id/swipeRefreshLayout"> - - + android:layout_height="match_parent"> + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/properties_list_adapter.xml b/app/src/main/res/layout/properties_list_adapter.xml new file mode 100644 index 0000000..5a36547 --- /dev/null +++ b/app/src/main/res/layout/properties_list_adapter.xml @@ -0,0 +1,22 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values-v21/styles.xml b/app/src/main/res/values-v21/styles.xml index fd7a058..5aff55f 100644 --- a/app/src/main/res/values-v21/styles.xml +++ b/app/src/main/res/values-v21/styles.xml @@ -5,4 +5,17 @@ true @android:color/transparent + + + diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 545b9c6..f49f94b 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -17,4 +17,8 @@ + diff --git a/build.gradle b/build.gradle index 47d59f1..ab22a0a 100644 --- a/build.gradle +++ b/build.gradle @@ -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