266 lines
12 KiB
Java
266 lines
12 KiB
Java
package com.example.lookifyv2;
|
|
|
|
import android.annotation.SuppressLint;
|
|
import android.content.Context;
|
|
import android.content.Intent;
|
|
import android.content.SharedPreferences;
|
|
import android.graphics.PorterDuff;
|
|
import android.os.AsyncTask;
|
|
import android.os.Bundle;
|
|
import android.view.View;
|
|
import android.widget.Button;
|
|
import android.widget.ImageView;
|
|
import android.widget.TextView;
|
|
import android.widget.Toast;
|
|
|
|
import androidx.appcompat.app.AppCompatActivity;
|
|
import androidx.recyclerview.widget.GridLayoutManager;
|
|
import androidx.recyclerview.widget.RecyclerView;
|
|
|
|
import com.bumptech.glide.Glide;
|
|
import com.google.common.collect.Lists;
|
|
import com.google.common.collect.Ordering;
|
|
|
|
import org.json.JSONArray;
|
|
import org.json.JSONException;
|
|
import org.json.JSONObject;
|
|
|
|
import java.io.IOException;
|
|
import java.util.ArrayList;
|
|
import java.util.Collections;
|
|
import java.util.HashMap;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
|
|
import okhttp3.OkHttpClient;
|
|
import okhttp3.Request;
|
|
import okhttp3.Response;
|
|
|
|
//Klasa napisana z pomocą tutorialu z http://androidbash.com/connecting-android-app-to-a-database-using-php-and-mysql/.
|
|
public class Results extends AppCompatActivity {
|
|
|
|
List<Product> products;
|
|
List<Product> productstop6;
|
|
ProductsAdapter adapter;
|
|
String decodedCode;
|
|
Button button_favourite;
|
|
Button button_details;
|
|
|
|
@Override
|
|
protected void onCreate(Bundle savedInstanceState) {
|
|
super.onCreate(savedInstanceState);
|
|
setContentView(R.layout.activity_results);
|
|
|
|
//Do strzałki powrotu w górnej części ekranu.
|
|
assert getSupportActionBar() != null;
|
|
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
|
|
|
RecyclerView recyclerView = findViewById(R.id.recyclerview);
|
|
products = new ArrayList<>();
|
|
productstop6 = new ArrayList<>();
|
|
getProductsFromDB(); //Ładuje wszystkie produkty z bazy do listy products, a następnie najbardziej podobne 6 do productstop6.
|
|
|
|
GridLayoutManager gridLayout = new GridLayoutManager(this, 2); //Recyclerview do implementacji potrzebuje managera,
|
|
//spancount to w praktyce wielkość kafelków.
|
|
recyclerView.setLayoutManager(gridLayout);
|
|
|
|
adapter = new ProductsAdapter(this, productstop6); //Adapter ładuje dane z jakiegoś datasetu aplikacji do kafelków.
|
|
recyclerView.setAdapter(adapter);
|
|
}
|
|
|
|
private void getProductsFromDB() {
|
|
@SuppressLint("StaticFieldLeak") AsyncTask<Void, Void, Void> asyncTask = new AsyncTask<Void, Void, Void>() {
|
|
@Override
|
|
protected Void doInBackground(Void... Void) {
|
|
OkHttpClient client = new OkHttpClient(); //Zewnętrzna biblioteka wykorzystana do nawiązania połączenia.
|
|
Request request = new Request.Builder().url("http://192.168.0.88/products.php?id=0").build();
|
|
try {
|
|
Response response = client.newCall(request).execute();
|
|
|
|
JSONArray array = new JSONArray(response.body().string());
|
|
|
|
for (int i = 0; i < array.length(); i++) {
|
|
|
|
JSONObject object = array.getJSONObject(i);
|
|
|
|
Product product = new Product(object.getInt("id"), object.getString("product_code"),
|
|
object.getString("product_name"), object.getString("product_image"),
|
|
object.getString("product_price"), object.getString("product_retailer"),
|
|
object.getString("product_colour"), object.getString("product_style"),
|
|
object.getString("product_collection"),
|
|
object.getString("product_type"), object.getString("product_sex"));
|
|
|
|
Results.this.products.add(product);
|
|
}
|
|
|
|
} catch (IOException e) {
|
|
e.printStackTrace();
|
|
} catch (JSONException e) {
|
|
e.printStackTrace();
|
|
}
|
|
return null;
|
|
}
|
|
|
|
//Dopiero po utworzeniu listy wszystkich produktów po stronie aplikacji wykonywane są dalsze operacje, stąd onPostExecute.
|
|
@Override
|
|
protected void onPostExecute(Void aVoid) {
|
|
adapter.notifyDataSetChanged(); //W praktyce informuje adapter, by odświeżył View którym zarząda, bo zmieniły się dane.
|
|
|
|
Bundle extras = getIntent().getExtras();
|
|
decodedCode = extras.getString("decodedcode");
|
|
|
|
//Ustalana jest lokacja zeskanowanego kodu w bazie; jeśli go tam nie ma, to następuje przeniesienie do ekranu błędu.
|
|
int foundPosition = -1;
|
|
for(int i = 0; i < products.size(); i++){
|
|
if(decodedCode.equals(products.get(i).getproductCode())){
|
|
foundPosition = i;
|
|
break;
|
|
}
|
|
}
|
|
if(foundPosition == -1){
|
|
Intent intent_DecodeFail = new Intent(Results.this, DecodeFail.class);
|
|
intent_DecodeFail.putExtra("status", "notindatabase");
|
|
startActivity(intent_DecodeFail);
|
|
finish();
|
|
}
|
|
|
|
ImageView imageView = findViewById(R.id.foundproductimage);
|
|
TextView foundProductPrice = findViewById(R.id.foundproductprice);
|
|
TextView foundProductName = findViewById(R.id.foundproductname);
|
|
TextView getFoundProductRetailer = findViewById(R.id.foundproductretailer);
|
|
|
|
//Do załadowania obrazka używana jest zewnętrzna biblioteka Glide.
|
|
Glide.with(Results.this).load(products.get(foundPosition).getImageLink()).into(imageView);
|
|
|
|
foundProductPrice.setText(products.get(foundPosition).getproductPrice());
|
|
foundProductName.setText(products.get(foundPosition).getproductName());
|
|
getFoundProductRetailer.setText(products.get(foundPosition).getproductRetailer());
|
|
|
|
button_favourite = findViewById(R.id.favourite_button);
|
|
button_favourite.getBackground().setColorFilter(0xFF67BAFF, PorterDuff.Mode.MULTIPLY);
|
|
button_details = findViewById(R.id.details_button);
|
|
button_details.getBackground().setColorFilter(0xFF67BAFF, PorterDuff.Mode.MULTIPLY);
|
|
|
|
final int finalFoundPosition = foundPosition; //Constant, jej wartości nie da się zmienić, tutaj wykorzystana bo były błędy
|
|
//ze zwykłym intem.
|
|
button_favourite.setOnClickListener(new View.OnClickListener() {
|
|
@Override
|
|
public void onClick(View v) {
|
|
addFavourite(Results.this, finalFoundPosition);
|
|
}
|
|
});
|
|
button_details.setOnClickListener(new View.OnClickListener() {
|
|
@Override
|
|
public void onClick(View v) {
|
|
openDetails(finalFoundPosition);
|
|
}
|
|
});
|
|
|
|
getRecommendedProducts(finalFoundPosition); //zapełniane jest productstop6
|
|
}
|
|
};
|
|
asyncTask.execute();
|
|
}
|
|
|
|
private void openDetails(int position){
|
|
Intent intent_Details = new Intent(this, Popup.class);
|
|
|
|
Bundle bundle = new Bundle();
|
|
|
|
bundle.putSerializable("productimage", products.get(position).getImageLink());
|
|
bundle.putSerializable("productcode", products.get(position).getproductCode());
|
|
bundle.putSerializable("productname", products.get(position).getproductName());
|
|
bundle.putSerializable("productprice", products.get(position).getproductPrice());
|
|
bundle.putSerializable("productretailer", products.get(position).getproductRetailer());
|
|
bundle.putSerializable("productcolour", products.get(position).getproductColour());
|
|
bundle.putSerializable("productstyle", products.get(position).getproductStyle());
|
|
bundle.putSerializable("productcollection", products.get(position).getproductCollection());
|
|
|
|
intent_Details.putExtras(bundle);
|
|
|
|
startActivity(intent_Details);
|
|
}
|
|
|
|
//Do zapisywania obserwowanych produktów wykorzystany został niekonwencjonalnie depozyt preferencji użytkownika.
|
|
//Sprawdzana jest obecność kodu w depozycie i podejmowana odpowiednia akcja: albo dodanie go, albo wyświetlenie informacji,
|
|
//że już jest dodany.
|
|
private void addFavourite(Context context, int position){
|
|
SharedPreferences pref = MyApplication.getInstance().getSharedPreferences("Favourites", 0);
|
|
SharedPreferences.Editor editor = pref.edit();
|
|
Map<String, ?> codes = pref.getAll();
|
|
ArrayList<String> codeslist = Lists.newArrayList(codes.keySet());
|
|
int checker = 0;
|
|
for(int i = 0; i < codeslist.size(); i++){
|
|
if(products.get(position).getproductCode().equals(codeslist.get(i))){
|
|
checker = -1;
|
|
Toast.makeText(context, "Ten produkt jest już obserwowany!",
|
|
Toast.LENGTH_SHORT).show();
|
|
break;
|
|
}
|
|
}
|
|
if(checker == 0){
|
|
editor.putBoolean(products.get(position).getproductCode(), true);
|
|
editor.apply();
|
|
Toast.makeText(context, "Produkt \"" + products.get(position).getproductName() + "\" został dodany do Obserwowanych.",
|
|
Toast.LENGTH_SHORT).show();
|
|
}
|
|
}
|
|
|
|
//Prostu algorytm jest wykorzystywany, by stworzyć ranking produktów podobnych do tego zeskanowanego. Można znacznie rozbudować!
|
|
private void getRecommendedProducts(int foundpos){
|
|
HashMap<Integer, Integer> ranking = new HashMap<>();
|
|
for(int i = 0; i < products.size(); i++) {
|
|
if (products.get(foundpos).getId() != products.get(i).getId()
|
|
&& products.get(foundpos).getproductType().equals(products.get(i).getproductType())
|
|
&& products.get(foundpos).getproductSex().equals(products.get(i).getproductSex())) {
|
|
int counter = 0;
|
|
if (products.get(foundpos).getproductColour().equals(products.get(i).getproductColour())) {
|
|
counter++;
|
|
}
|
|
if (products.get(foundpos).getproductStyle().equals(products.get(i).getproductStyle())) {
|
|
counter++;
|
|
}
|
|
if (products.get(foundpos).getproductCollection().equals(products.get(i).getproductCollection())
|
|
|| products.get(foundpos).getproductCollection().equals("całoroczna")
|
|
|| products.get(i).getproductCollection().equals("całoroczna")) {
|
|
counter++;
|
|
}
|
|
ranking.put(i, counter);
|
|
}
|
|
}
|
|
|
|
//Odpowiednia informacja wyświetlana jest, jeśli nie znaleziono podobnych produktów.
|
|
//Do sortowania rankingu wykorzystywana jest zewnętrzna biblioteka Guava.
|
|
if(ranking.size() == 0){
|
|
TextView noproductsmessage = findViewById(R.id.noproductsmessage);
|
|
noproductsmessage.setVisibility(View.VISIBLE);
|
|
}
|
|
else{
|
|
Ordering<Map.Entry<Integer, Integer>> byMapValues = new Ordering<Map.Entry<Integer, Integer>>() {
|
|
@Override
|
|
public int compare(Map.Entry<Integer, Integer> left, Map.Entry<Integer, Integer> right) { //Ustalany jest sposób sortowania.
|
|
return left.getValue().compareTo(right.getValue());
|
|
}
|
|
};
|
|
List<Map.Entry<Integer, Integer>> rankinglist = Lists.newArrayList(ranking.entrySet()); //Tworzona jest lista z zawartością mapy,
|
|
//by móc użyć metody sort (ze zdefiniowanym sposobem sortowania).
|
|
Collections.sort(rankinglist, byMapValues.reverse());
|
|
|
|
int i = 0;
|
|
while(i < 6 && i < ranking.size()) {
|
|
productstop6.add(products.get(rankinglist.get(i).getKey()));
|
|
i++;
|
|
}
|
|
}
|
|
}
|
|
|
|
//Kliknięcie strzałki powrotu kończy activity.
|
|
@Override
|
|
public boolean onSupportNavigateUp(){
|
|
finish();
|
|
return true;
|
|
}
|
|
}
|
|
|
|
|