Ujednolić poziomy accessu metod, popraw/dodaj komentarze, popraw mały błąd z index out of bounds

This commit is contained in:
Kacper Dudzic 2020-06-20 00:58:53 +02:00
parent 0b65e9fe38
commit 318eaa6268
20 changed files with 150 additions and 118 deletions

View File

@ -40,5 +40,4 @@
</intent-filter> </intent-filter>
</activity> </activity>
</application> </application>
</manifest> </manifest>

View File

@ -1,7 +1,6 @@
package com.example.lookifyv2; package com.example.lookifyv2;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle; import android.os.Bundle;
public class About extends AppCompatActivity { public class About extends AppCompatActivity {
@ -11,10 +10,12 @@ public class About extends AppCompatActivity {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_about); setContentView(R.layout.activity_about);
//Do strzałki powrotu w górnej części ekranu.
assert getSupportActionBar() != null; assert getSupportActionBar() != null;
getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setDisplayHomeAsUpEnabled(true);
} }
//Kliknięcie strzałki powrotu kończy activity.
@Override @Override
public boolean onSupportNavigateUp(){ public boolean onSupportNavigateUp(){
finish(); finish();

View File

@ -2,13 +2,13 @@ package com.example.lookifyv2;
import java.io.IOException; import java.io.IOException;
public class CheckInternet { class CheckInternet {
//rozwiązanie zaczerpnięte z https://stackoverflow.com/a/27312494/12566206 //Rozwiązanie zaczerpnięte z https://stackoverflow.com/a/27312494/12566206.
public boolean isOnline() { boolean isOnline() {
Runtime runtime = Runtime.getRuntime(); Runtime runtime = Runtime.getRuntime();
try { try {
Process ipProcess = runtime.exec("/system/bin/ping -c 1 8.8.8.8"); Process ipProcess = runtime.exec("/system/bin/ping -c 1 8.8.8.8"); //pinguje DNS Google
int exitValue = ipProcess.waitFor(); int exitValue = ipProcess.waitFor();
return (exitValue == 0); return (exitValue == 0);
} }

View File

@ -35,21 +35,22 @@ import static org.opencv.imgproc.Imgproc.THRESH_BINARY;
public class Decode extends AppCompatActivity { public class Decode extends AppCompatActivity {
//inicjacja logów OpenCV //Inicjalizacja logów OpenCV.
private static final String TAG = "OCVSample::Activity"; static final String TAG = "OCVSample::Activity";
String filePath; String filePath;
Mat matPic; Mat matPic;
//OpenCV domyślnie uruchamia się po onCreate co powoduje problemy - zapobiegamy więc temu, zapewniając, by metoda wykorzystująca OpenCV //OpenCV domyślnie uruchamia się po onCreate co powoduje problemy - zapobiegamy więc temu, zapewniając, by metoda wykorzystująca OpenCV
//uruchamiała się dopiero po jego pomyślnym załadowaniu //uruchamiała się dopiero po jego pomyślnym załadowaniu.
//https://docs.opencv.org/2.4/platforms/android/service/doc/BaseLoaderCallback.html
private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) { private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {
@Override @Override
public void onManagerConnected(int status) { public void onManagerConnected(int status) {
switch (status) { switch (status) {
case LoaderCallbackInterface.SUCCESS: { case LoaderCallbackInterface.SUCCESS: {
Log.i(TAG, "OpenCV loaded successfully"); Log.i(TAG, "OpenCV loaded successfully");
decodePic(); decodePic(); //w praktyce tu się uruchamia cała reszta klasy
} }
break; break;
default: { default: {
@ -66,13 +67,15 @@ public class Decode extends AppCompatActivity {
setContentView(R.layout.activity_decode); setContentView(R.layout.activity_decode);
} }
public void decodePic() { private void decodePic() {
//Pobieranie adresu pliku przekazanego przez poprzednie activity.
//Obsługa sytuacji, w której nie ma dostępu do internetu
CheckInternet check = new CheckInternet();
if(!check.isOnline()){
Bundle extras = getIntent().getExtras(); Bundle extras = getIntent().getExtras();
filePath = extras.getString("takenPic"); filePath = extras.getString("takenPic");
//Obsługa sytuacji, w której nie ma dostępu do internetu - zrobione zdjęcie zostaje usunięte i następuje przejście do klasy
//odpowiedzialnej za błędy tej części aplikacji.
CheckInternet check = new CheckInternet();
if(!check.isOnline()){
File filefordeletion = new File(filePath); File filefordeletion = new File(filePath);
filefordeletion.delete(); filefordeletion.delete();
@ -82,9 +85,7 @@ public class Decode extends AppCompatActivity {
finish(); finish();
} }
//Pobieranie adresu pliku przekazanego przez poprzednie activity, tworzenie mata ze zdjęcia i usuwanie zdjęcia //Tworzenie mata ze zdjęcia i usuwanie zdjęcia.
Bundle extras = getIntent().getExtras();
filePath = extras.getString("takenPic");
matPic = Imgcodecs.imread(filePath); matPic = Imgcodecs.imread(filePath);
File filefordeletion = new File(filePath); File filefordeletion = new File(filePath);
filefordeletion.delete(); filefordeletion.delete();
@ -92,24 +93,30 @@ public class Decode extends AppCompatActivity {
Mat matPicGB = new Mat(); Mat matPicGB = new Mat();
Mat matPicGBT = new Mat(); Mat matPicGBT = new Mat();
//Zdjęcie zamieniane jest na czarno-biały odpowiednik //Zdjęcie zamieniane jest na czarno-biały odpowiednik.
//Na podstawie: Amgad Muhammad - OpenCV Android Programming By Example (43% e-booka).
Imgproc.cvtColor(matPic, matPicG, Imgproc.COLOR_RGB2GRAY); Imgproc.cvtColor(matPic, matPicG, Imgproc.COLOR_RGB2GRAY);
//Usuwanie "noise'u" przy jednoczesnym zachowywaniu ostrych krawędzi za pomocą bilateralnego filtru //Usuwanie "noise'u" przy jednoczesnym zachowywaniu ostrych krawędzi za pomocą bilateralnego filtru.
//Na podstawie: Daniel Lelis Baggio - OpenCV 3.0 Computer Vision with Java (s. 52).
Imgproc.bilateralFilter(matPicG, matPicGB, 5, 75, 75); Imgproc.bilateralFilter(matPicG, matPicGB, 5, 75, 75);
//Zwiększanie kontrastu za pomocą thresholdu //Zwiększanie kontrastu za pomocą thresholdu.
//Na podstawie: Salil Kapur, Nisarg Thakkar - Mastering OpenCV Android Application Programming (s. 19).
Imgproc.threshold(matPicGB, matPicGBT, 100, 255, THRESH_BINARY); Imgproc.threshold(matPicGB, matPicGBT, 100, 255, THRESH_BINARY);
//przygotowywanie mapy bitowej, którą przeskanuje ZXing w poszukiwaniu kodu //Przygotowywanie mapy bitowej, którą przeskanuje ZXing w poszukiwaniu kodu.
Bitmap bMap = Bitmap.createBitmap(matPicGBT.width(), matPicGBT.height(), Bitmap.Config.ARGB_8888); //zwykła mapa wbudowana w jave/android studio Bitmap bMap = Bitmap.createBitmap(matPicGBT.width(), matPicGBT.height(), Bitmap.Config.ARGB_8888); //Zwykła mapa wbudowana w
//Javę/Android Studio.
Utils.matToBitmap(matPicGBT, bMap); Utils.matToBitmap(matPicGBT, bMap);
int[] intArray = new int[bMap.getWidth() * bMap.getHeight()]; int[] intArray = new int[bMap.getWidth() * bMap.getHeight()];
bMap.getPixels(intArray, 0, bMap.getWidth(), 0, 0, bMap.getWidth(), bMap.getHeight()); bMap.getPixels(intArray, 0, bMap.getWidth(), 0, 0, bMap.getWidth(), bMap.getHeight()); //intArray otrzymuje dane o kolorach
LuminanceSource source = new RGBLuminanceSource(bMap.getWidth(), bMap.getHeight(), intArray); //zamienia różne formaty map na jedną spójną postać; pozwala wykonać nastepny krok //pikseli.
LuminanceSource source = new RGBLuminanceSource(bMap.getWidth(), bMap.getHeight(), intArray); //Zamienia różne formaty map na jedną
//spójną postać; pozwala wykonać nastepny krok.
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source)); BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
//Zwiększanie efektywności wykrywania kodów //Zwiększanie efektywności wykrywania kodów.
Hashtable<DecodeHintType, Object> hints = new Hashtable<>(); Hashtable<DecodeHintType, Object> hints = new Hashtable<>();
List<Object> formats = new ArrayList<>(); List<Object> formats = new ArrayList<>();
@ -132,8 +139,10 @@ public class Decode extends AppCompatActivity {
hints.put(DecodeHintType.POSSIBLE_FORMATS, formats); hints.put(DecodeHintType.POSSIBLE_FORMATS, formats);
hints.put(DecodeHintType.TRY_HARDER, true); hints.put(DecodeHintType.TRY_HARDER, true);
int reminder = 0; int reminder = 0; //Aplikacja zawsze jest trochę w przód z wykonywaniem kodu nawet po wywołaniu finish(), więc ta zmienna gwarantuje
//Szukanie kodu na wczytanym zdjęciu i podejmowanie odpowiednich działań w zależności od tego, czy został znaleziony, czy nie //brak wyświetlania kodu, jeśli nie został on znaleziony.
//Szukanie kodu na wczytanym zdjęciu i podejmowanie odpowiednich działań w zależności od tego, czy został znaleziony, czy nie.
MultiFormatReader reader = new MultiFormatReader(); MultiFormatReader reader = new MultiFormatReader();
String contents = null; String contents = null;
try { try {
@ -157,7 +166,8 @@ public class Decode extends AppCompatActivity {
} }
} }
//Druga część potrzebna do ładowania OpenCV w odpowiednim momencie, czyli gdy aplikacja była zminimalizowana, a teraz zostaje z powrotem zmaksymalizowana //Druga część potrzebna do ładowania OpenCV w odpowiednim momencie, czyli gdy aplikacja była zminimalizowana, a teraz zostaje z powrotem
//zmaksymalizowana.
@Override @Override
protected void onResume() { protected void onResume() {
super.onResume(); super.onResume();

View File

@ -18,10 +18,11 @@ public class DecodeFail extends AppCompatActivity {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_decode_fail); setContentView(R.layout.activity_decode_fail);
//Do strzałki powrotu w górnej części ekranu.
assert getSupportActionBar() != null; assert getSupportActionBar() != null;
getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setDisplayHomeAsUpEnabled(true);
//Pobieranie informacji o rodzaju błędu od Decode i wyświetlanie odpowiedniego komunikatu w zależności od tego rodzaju //Pobieranie informacji o rodzaju błędu od Decode i wyświetlanie odpowiedniego komunikatu w zależności od tego rodzaju.
Bundle extras = getIntent().getExtras(); Bundle extras = getIntent().getExtras();
status = extras.getString("status"); status = extras.getString("status");
showMessage(status); showMessage(status);
@ -36,13 +37,13 @@ public class DecodeFail extends AppCompatActivity {
}); });
} }
public void openScan(){ private void openScan(){
Intent intent_Scan = new Intent(this, TakePhoto.class); Intent intent_Scan = new Intent(this, TakePhoto.class);
startActivity(intent_Scan); startActivity(intent_Scan);
finish(); finish();
} }
public void showMessage(String status){ private void showMessage(String status){
if(status.equals("notfound")){ if(status.equals("notfound")){
TextView message = findViewById(R.id.text_notfound); TextView message = findViewById(R.id.text_notfound);
message.setVisibility(View.VISIBLE); message.setVisibility(View.VISIBLE);
@ -57,6 +58,7 @@ public class DecodeFail extends AppCompatActivity {
} }
} }
//Kliknięcie strzałki powrotu kończy activity.
@Override @Override
public boolean onSupportNavigateUp(){ public boolean onSupportNavigateUp(){
finish(); finish();

View File

@ -30,17 +30,18 @@ import okhttp3.Response;
public class Favourites extends AppCompatActivity { public class Favourites extends AppCompatActivity {
private List<Product> products; List<Product> products;
private List<Product> favourites; List<Product> favourites;
private RecyclerView recyclerView; RecyclerView recyclerView;
private GridLayoutManager gridLayout; GridLayoutManager gridLayout;
private FavouritesAdapter adapter; FavouritesAdapter adapter;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_favourites); setContentView(R.layout.activity_favourites);
//Do strzałki powrotu w górnej części ekranu.
assert getSupportActionBar() != null; assert getSupportActionBar() != null;
getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setDisplayHomeAsUpEnabled(true);
@ -80,7 +81,7 @@ public class Favourites extends AppCompatActivity {
protected Void doInBackground(Void... Void) { protected Void doInBackground(Void... Void) {
OkHttpClient client = new OkHttpClient(); OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url("http://192.168.0.87/products.php?id=0").build(); Request request = new Request.Builder().url("http://192.168.0.88/products.php?id=0").build();
try { try {
Response response = client.newCall(request).execute(); Response response = client.newCall(request).execute();
@ -118,8 +119,8 @@ public class Favourites extends AppCompatActivity {
asyncTask.execute(); asyncTask.execute();
} }
//z preferencji odczytywane kody obserwowanych produktów, jeśli nie ma żadnego wyświetlana jest odpowiednia wiadomość //Z preferencji odczytywane kody obserwowanych produktów, jeśli nie ma żadnego wyświetlana jest odpowiednia wiadomość.
//następnie pozycje kodów na liscie products ustalane i za ich pomocą odpowiednie elementy tej listy kopiowane do nowej listy z obserwowanymi //Następnie pozycje kodów na liscie products ustalane i za ich pomocą odpowiednie elementy tej listy kopiowane do nowej listy z obserwowanymi.
private void getFavourites() { private void getFavourites() {
SharedPreferences pref = MyApplication.getInstance().getSharedPreferences("Favourites", 0); SharedPreferences pref = MyApplication.getInstance().getSharedPreferences("Favourites", 0);
Map<String, ?> codes = pref.getAll(); Map<String, ?> codes = pref.getAll();
@ -144,6 +145,8 @@ public class Favourites extends AppCompatActivity {
} }
} }
} }
//Kliknięcie strzałki powrotu kończy activity.
@Override @Override
public boolean onSupportNavigateUp(){ public boolean onSupportNavigateUp(){
finish(); finish();

View File

@ -20,6 +20,7 @@ import com.bumptech.glide.Glide;
import java.util.List; import java.util.List;
//klasa napisana z pomocą tutorialu z http://androidbash.com/connecting-android-app-to-a-database-using-php-and-mysql/
public class FavouritesAdapter extends RecyclerView.Adapter<FavouritesAdapter.ViewHolder>{ public class FavouritesAdapter extends RecyclerView.Adapter<FavouritesAdapter.ViewHolder>{
private Context context; private Context context;
@ -54,10 +55,10 @@ public class FavouritesAdapter extends RecyclerView.Adapter<FavouritesAdapter.Vi
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{ public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
private ImageView imageView; ImageView imageView;
private TextView productName; TextView productName;
private TextView productPrice; TextView productPrice;
private TextView productRetailer; TextView productRetailer;
private ViewHolder(View itemView) { private ViewHolder(View itemView) {
super(itemView); super(itemView);
@ -83,14 +84,14 @@ public class FavouritesAdapter extends RecyclerView.Adapter<FavouritesAdapter.Vi
popup.show(); popup.show();
} }
class MenuClickListener implements PopupMenu.OnMenuItemClickListener { public class MenuClickListener implements PopupMenu.OnMenuItemClickListener {
Integer pos; Integer pos;
private MenuClickListener(int pos) { private MenuClickListener(int pos) {
this.pos=pos; this.pos=pos;
} }
//Pierwszy case to usuwanie produktu z obserwowanych. By odświeżyć widok po usunięciu zamykane //Pierwszy case to usuwanie produktu z obserwowanych. By odświeżyć widok po usunięciu zamykane ona i powiązane z nią activity,
// ona i powiązane z nią activity, a ona sama uruchamiana ponownie //a ona sama uruchamiana ponownie.
@Override @Override
public boolean onMenuItemClick(MenuItem menuItem) { public boolean onMenuItemClick(MenuItem menuItem) {
switch (menuItem.getItemId()) { switch (menuItem.getItemId()) {
@ -101,8 +102,8 @@ public class FavouritesAdapter extends RecyclerView.Adapter<FavouritesAdapter.Vi
editor.apply(); editor.apply();
Intent intent_Favourites = new Intent(context, Favourites.class); Intent intent_Favourites = new Intent(context, Favourites.class);
intent_Favourites.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); //niszczy i powiązane activity, dzięki czemu przy kolejnym intent_Favourites.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); //Niszczy i powiązane activity, dzięki czemu przy kolejnym
//uruchomieniu favourites nie widać już usuniętych kafelków //uruchomieniu favourites nie widać już usuniętych kafelków.
context.startActivity(intent_Favourites); context.startActivity(intent_Favourites);
Toast.makeText(context, "Produkt \"" + products.get(pos).getproductName() + "\" został usunięty z Obserwowanych.", Toast.makeText(context, "Produkt \"" + products.get(pos).getproductName() + "\" został usunięty z Obserwowanych.",

View File

@ -1,7 +1,6 @@
package com.example.lookifyv2; package com.example.lookifyv2;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle; import android.os.Bundle;
import android.text.method.ScrollingMovementMethod; import android.text.method.ScrollingMovementMethod;
import android.widget.TextView; import android.widget.TextView;
@ -16,10 +15,12 @@ public class Help extends AppCompatActivity {
TextView text = findViewById(R.id.help); TextView text = findViewById(R.id.help);
text.setMovementMethod(new ScrollingMovementMethod()); text.setMovementMethod(new ScrollingMovementMethod());
//Do strzałki powrotu w górnej części ekranu.
assert getSupportActionBar() != null; assert getSupportActionBar() != null;
getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setDisplayHomeAsUpEnabled(true);
} }
//Kliknięcie strzałki powrotu kończy activity.
@Override @Override
public boolean onSupportNavigateUp(){ public boolean onSupportNavigateUp(){
finish(); finish();

View File

@ -56,14 +56,14 @@ public class MainActivity extends AppCompatActivity {
} }
}); });
//Dezaktywacja przycisku skanowania, jeśli nie ma dostępu do kamery; żądanie dostępu do kamery i zapisu //Dezaktywacja przycisku skanowania, jeśli nie ma dostępu do kamery; żądanie dostępu do kamery i zapisu.
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
button_scan.setEnabled(false); button_scan.setEnabled(false);
ActivityCompat.requestPermissions(this, new String[] { Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE }, 0); ActivityCompat.requestPermissions(this, new String[] { Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE }, 0);
} }
} }
//Aktywacja przycisku skanowania, jeśli uprawnienia zostały przyznane //Aktywacja przycisku skanowania, jeśli uprawnienia zostały przyznane.
@Override @Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
if (requestCode == 0) { if (requestCode == 0) {
@ -74,22 +74,22 @@ public class MainActivity extends AppCompatActivity {
} }
} }
public void openHelp(){ private void openHelp(){
Intent intent_Help = new Intent(this, Help.class); Intent intent_Help = new Intent(this, Help.class);
startActivity(intent_Help); startActivity(intent_Help);
} }
public void openAbout(){ private void openAbout(){
Intent intent_About = new Intent(this, About.class); Intent intent_About = new Intent(this, About.class);
startActivity(intent_About); startActivity(intent_About);
} }
public void openScan(){ private void openScan(){
Intent intent_Scan = new Intent(this, TakePhoto.class); Intent intent_Scan = new Intent(this, TakePhoto.class);
startActivity(intent_Scan); startActivity(intent_Scan);
} }
public void openFavourites(){ private void openFavourites(){
Intent intent_Favourites = new Intent(this, Favourites.class); Intent intent_Favourites = new Intent(this, Favourites.class);
startActivity(intent_Favourites); startActivity(intent_Favourites);
} }

View File

@ -2,10 +2,11 @@ package com.example.lookifyv2;
import android.app.Application; import android.app.Application;
//Umożliwia uzyskanie globalnego kontekstu aplikacji klasom, które nie activity. Obiekt Application tworzony jest //Umożliwia uzyskanie globalnego kontekstu aplikacji klasom, które nie Activity. Obiekt Application tworzony jest
//przed powstaniem jakiegokolwiek obiektu activity i trwa przez cały cykl życia aplikacji. Rozwiązanie z https://stackoverflow.com/a/12405879/12566206 //przed powstaniem jakiegokolwiek obiektu Activity i trwa przez cały cykl życia aplikacji.
//https://stackoverflow.com/a/12405879/12566206.
public class MyApplication extends Application { public class MyApplication extends Application {
private static MyApplication instance; static MyApplication instance;
@Override @Override
public void onCreate() { public void onCreate() {
@ -13,7 +14,7 @@ public class MyApplication extends Application {
instance = this; instance = this;
} }
public static MyApplication getInstance() { static MyApplication getInstance() {
return instance; return instance;
} }
} }

View File

@ -16,6 +16,7 @@ public class Popup extends AppCompatActivity {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_popup); setContentView(R.layout.activity_popup);
//Do strzałki powrotu w górnej części ekranu.
assert getSupportActionBar() != null; assert getSupportActionBar() != null;
getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setDisplayHomeAsUpEnabled(true);
@ -30,7 +31,7 @@ public class Popup extends AppCompatActivity {
Bundle bundle = this.getIntent().getExtras(); Bundle bundle = this.getIntent().getExtras();
//do załadowania obrazka używana jest zewnętrzna biblioteka Glide //Do załadowania obrazka używana jest zewnętrzna biblioteka Glide.
Glide.with(this).load((String) bundle.getSerializable("productimage")).into(productImage); Glide.with(this).load((String) bundle.getSerializable("productimage")).into(productImage);
productCode.setText(Html.fromHtml("<b>" + "Kod produktu:" + "</b> " + bundle.getSerializable("productcode"))); productCode.setText(Html.fromHtml("<b>" + "Kod produktu:" + "</b> " + bundle.getSerializable("productcode")));
@ -42,6 +43,7 @@ public class Popup extends AppCompatActivity {
productCollection.setText(Html.fromHtml("<b>" + "Kolekcja:" + "</b> " + bundle.getSerializable("productcollection"))); productCollection.setText(Html.fromHtml("<b>" + "Kolekcja:" + "</b> " + bundle.getSerializable("productcollection")));
} }
//Kliknięcie strzałki powrotu kończy Activity.
@Override @Override
public boolean onSupportNavigateUp(){ public boolean onSupportNavigateUp(){
finish(); finish();

View File

@ -1,7 +1,7 @@
package com.example.lookifyv2; package com.example.lookifyv2;
//klasa stworzona na podstawie podobnej z http://androidbash.com/connecting-android-app-to-a-database-using-php-and-mysql/ //Klasa stworzona na podstawie podobnej z http://androidbash.com/connecting-android-app-to-a-database-using-php-and-mysql/.
//jest po prostu obiektem produktu ze wszystkimi jego danymi i metodami te dane zwracającymi //Jest po prostu obiektem produktu ze wszystkimi jego danymi i metodami te dane zwracającymi.
public class Product{ public class Product{
private int id; private int id;
@ -31,7 +31,7 @@ public class Product{
this.productSex = productSex; this.productSex = productSex;
} }
public int getId() { int getId() {
return id; return id;
} }
String getImageLink() { return imageLink; } String getImageLink() { return imageLink; }

View File

@ -23,6 +23,7 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
//Klasa napisana z pomocą tutorialu z http://androidbash.com/connecting-android-app-to-a-database-using-php-and-mysql/.
public class ProductsAdapter extends RecyclerView.Adapter<ProductsAdapter.ViewHolder>{ public class ProductsAdapter extends RecyclerView.Adapter<ProductsAdapter.ViewHolder>{
private Context context; private Context context;
@ -33,7 +34,7 @@ public class ProductsAdapter extends RecyclerView.Adapter<ProductsAdapter.ViewHo
this.products = products; this.products = products;
} }
//viewholder przechowuje dane viewów, by nie musieć za każdym razem ich pojedynczo wypełniać //Viewholder przechowuje dane viewów, by nie musieć za każdym razem ich pojedynczo wypełniać.
@Override @Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.card,parent,false); View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.card,parent,false);
@ -44,7 +45,9 @@ public class ProductsAdapter extends RecyclerView.Adapter<ProductsAdapter.ViewHo
@Override @Override
public void onBindViewHolder(final ViewHolder holder, int position) { public void onBindViewHolder(final ViewHolder holder, int position) {
//Do załadowania obrazka używana jest zewnętrzna biblioteka Glide.
Glide.with(context).load(products.get(position).getImageLink()).into(holder.imageView); Glide.with(context).load(products.get(position).getImageLink()).into(holder.imageView);
holder.productName.setText(products.get(position).getproductName()); holder.productName.setText(products.get(position).getproductName());
holder.productPrice.setText(products.get(position).getproductPrice()); holder.productPrice.setText(products.get(position).getproductPrice());
holder.productRetailer.setText(products.get(position).getproductRetailer()); holder.productRetailer.setText(products.get(position).getproductRetailer());
@ -86,13 +89,13 @@ public class ProductsAdapter extends RecyclerView.Adapter<ProductsAdapter.ViewHo
popup.show(); popup.show();
} }
class MenuClickListener implements PopupMenu.OnMenuItemClickListener { public class MenuClickListener implements PopupMenu.OnMenuItemClickListener {
Integer pos; Integer pos;
MenuClickListener(int pos) { MenuClickListener(int pos) {
this.pos=pos; this.pos=pos;
} }
//Zasadniczo dzieje się tutaj to samo, co w przypadku przycisków w Results //Zasadniczo dzieje się tutaj to samo, co w przypadku przycisków w Results.
@Override @Override
public boolean onMenuItemClick(MenuItem menuItem) { public boolean onMenuItemClick(MenuItem menuItem) {
switch (menuItem.getItemId()) { switch (menuItem.getItemId()) {

View File

@ -36,12 +36,12 @@ import okhttp3.OkHttpClient;
import okhttp3.Request; import okhttp3.Request;
import okhttp3.Response; import okhttp3.Response;
//klasa napisana z pomocą tutorialu z http://androidbash.com/connecting-android-app-to-a-database-using-php-and-mysql/ //Klasa napisana z pomocą tutorialu z http://androidbash.com/connecting-android-app-to-a-database-using-php-and-mysql/.
public class Results extends AppCompatActivity { public class Results extends AppCompatActivity {
private List<Product> products; List<Product> products;
private List<Product> productstop6; List<Product> productstop6;
private ProductsAdapter adapter; ProductsAdapter adapter;
String decodedCode; String decodedCode;
Button button_favourite; Button button_favourite;
Button button_details; Button button_details;
@ -51,29 +51,29 @@ public class Results extends AppCompatActivity {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_results); setContentView(R.layout.activity_results);
//Do strzałki powrotu w górnej części ekranu.
assert getSupportActionBar() != null; assert getSupportActionBar() != null;
getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setDisplayHomeAsUpEnabled(true);
RecyclerView recyclerView = findViewById(R.id.recyclerview); RecyclerView recyclerView = findViewById(R.id.recyclerview);
products = new ArrayList<>(); products = new ArrayList<>();
productstop6 = new ArrayList<>(); productstop6 = new ArrayList<>();
getProductsFromDB(); //ładuje wszystkie produktu z bazy do listy products, a następnie najbardziej podobne 6 do productstop6 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 GridLayoutManager gridLayout = new GridLayoutManager(this, 2); //Recyclerview do implementacji potrzebuje managera,
//spancount to w praktyce wielkość kafelków.
recyclerView.setLayoutManager(gridLayout); recyclerView.setLayoutManager(gridLayout);
adapter = new ProductsAdapter(this, productstop6); //adapter ładuje dane z jakiegoś datasetu aplikacji do kafelków adapter = new ProductsAdapter(this, productstop6); //Adapter ładuje dane z jakiegoś datasetu aplikacji do kafelków.
recyclerView.setAdapter(adapter); recyclerView.setAdapter(adapter);
} }
private void getProductsFromDB() { private void getProductsFromDB() {
@SuppressLint("StaticFieldLeak") AsyncTask<Void, Void, Void> asyncTask = new AsyncTask<Void, Void, Void>() { @SuppressLint("StaticFieldLeak") AsyncTask<Void, Void, Void> asyncTask = new AsyncTask<Void, Void, Void>() {
@Override @Override
protected Void doInBackground(Void... Void) { protected Void doInBackground(Void... Void) {
OkHttpClient client = new OkHttpClient(); //Zewnętrzna biblioteka wykorzystana do nawiązania połączenia.
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();
Request request = new Request.Builder().url("http://192.168.0.87/products.php?id=0").build();
try { try {
Response response = client.newCall(request).execute(); Response response = client.newCall(request).execute();
@ -101,15 +101,15 @@ public class Results extends AppCompatActivity {
return null; return null;
} }
//dopiero po utworzeniu listy wszystkich produktów po stronie aplikacji wykonywane dalsze operacje, stąd onPostExecute //Dopiero po utworzeniu listy wszystkich produktów po stronie aplikacji wykonywane dalsze operacje, stąd onPostExecute.
@Override @Override
protected void onPostExecute(Void aVoid) { 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 adapter.notifyDataSetChanged(); //W praktyce informuje adapter, by odświeżył View którym zarząda, bo zmieniły się dane.
Bundle extras = getIntent().getExtras(); Bundle extras = getIntent().getExtras();
decodedCode = extras.getString("decodedcode"); 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 //Ustalana jest lokacja zeskanowanego kodu w bazie; jeśli go tam nie ma, to następuje przeniesienie do ekranu błędu.
int foundPosition = -1; int foundPosition = -1;
for(int i = 0; i < products.size(); i++){ for(int i = 0; i < products.size(); i++){
if(decodedCode.equals(products.get(i).getproductCode())){ if(decodedCode.equals(products.get(i).getproductCode())){
@ -129,7 +129,9 @@ public class Results extends AppCompatActivity {
TextView foundProductName = findViewById(R.id.foundproductname); TextView foundProductName = findViewById(R.id.foundproductname);
TextView getFoundProductRetailer = findViewById(R.id.foundproductretailer); 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); Glide.with(Results.this).load(products.get(foundPosition).getImageLink()).into(imageView);
foundProductPrice.setText(products.get(foundPosition).getproductPrice()); foundProductPrice.setText(products.get(foundPosition).getproductPrice());
foundProductName.setText(products.get(foundPosition).getproductName()); foundProductName.setText(products.get(foundPosition).getproductName());
getFoundProductRetailer.setText(products.get(foundPosition).getproductRetailer()); getFoundProductRetailer.setText(products.get(foundPosition).getproductRetailer());
@ -139,7 +141,8 @@ public class Results extends AppCompatActivity {
button_details = findViewById(R.id.details_button); button_details = findViewById(R.id.details_button);
button_details.getBackground().setColorFilter(0xFF67BAFF, PorterDuff.Mode.MULTIPLY); button_details.getBackground().setColorFilter(0xFF67BAFF, PorterDuff.Mode.MULTIPLY);
final int finalFoundPosition = foundPosition; 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() { button_favourite.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
@ -159,7 +162,7 @@ public class Results extends AppCompatActivity {
asyncTask.execute(); asyncTask.execute();
} }
public void openDetails(int position){ private void openDetails(int position){
Intent intent_Details = new Intent(this, Popup.class); Intent intent_Details = new Intent(this, Popup.class);
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
@ -178,9 +181,10 @@ public class Results extends AppCompatActivity {
startActivity(intent_Details); startActivity(intent_Details);
} }
//do zapisywania obserwowanych produktów wykorzystany został niekonwencjonalnie depozyt preferencji użytkownika //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 //Sprawdzana jest obecność kodu w depozycie i podejmowana odpowiednia akcja: albo dodanie go, albo wyświetlenie informacji,
public void addFavourite(Context context, int position){ //że już jest dodany.
private void addFavourite(Context context, int position){
SharedPreferences pref = MyApplication.getInstance().getSharedPreferences("Favourites", 0); SharedPreferences pref = MyApplication.getInstance().getSharedPreferences("Favourites", 0);
SharedPreferences.Editor editor = pref.edit(); SharedPreferences.Editor editor = pref.edit();
Map<String, ?> codes = pref.getAll(); Map<String, ?> codes = pref.getAll();
@ -202,7 +206,7 @@ public class Results extends AppCompatActivity {
} }
} }
//Prostu algorytm jest wykorzystywany, by stworzyć ranking produktów podobne do tego zeskanowanego. Można znacznie rozbudować. //Prostu algorytm jest wykorzystywany, by stworzyć ranking produktów podobnych do tego zeskanowanego. Można znacznie rozbudować!
private void getRecommendedProducts(int foundpos){ private void getRecommendedProducts(int foundpos){
HashMap<Integer, Integer> ranking = new HashMap<>(); HashMap<Integer, Integer> ranking = new HashMap<>();
for(int i = 0; i < products.size(); i++) { for(int i = 0; i < products.size(); i++) {
@ -234,21 +238,23 @@ public class Results extends AppCompatActivity {
else{ else{
Ordering<Map.Entry<Integer, Integer>> byMapValues = new Ordering<Map.Entry<Integer, Integer>>() { Ordering<Map.Entry<Integer, Integer>> byMapValues = new Ordering<Map.Entry<Integer, Integer>>() {
@Override @Override
public int compare(Map.Entry<Integer, Integer> left, Map.Entry<Integer, Integer> right) { //ustalany jest sposób sortowania public int compare(Map.Entry<Integer, Integer> left, Map.Entry<Integer, Integer> right) { //Ustalany jest sposób sortowania.
return left.getValue().compareTo(right.getValue()); return left.getValue().compareTo(right.getValue());
} }
}; };
List<Map.Entry<Integer, Integer>> rankinglist = Lists.newArrayList(ranking.entrySet()); //tworzona jest lista z zawartością mapy, 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) //by móc użyć metody sort (ze zdefiniowanym sposobem sortowania).
Collections.sort(rankinglist, byMapValues.reverse()); Collections.sort(rankinglist, byMapValues.reverse());
for(int i = 0; i < 6; i++) { int i = 0;
while(i < 6 && i < ranking.size()) {
productstop6.add(products.get(rankinglist.get(i).getKey())); productstop6.add(products.get(rankinglist.get(i).getKey()));
i++;
}
} }
} }
} //Kliknięcie strzałki powrotu kończy activity.
@Override @Override
public boolean onSupportNavigateUp(){ public boolean onSupportNavigateUp(){
finish(); finish();

View File

@ -5,15 +5,13 @@ import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.os.Environment; import android.os.Environment;
import android.provider.MediaStore; import android.provider.MediaStore;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import java.io.File; import java.io.File;
//klasa napisana z pomocą tutorialu dostępnego na https://androidkennel.org/android-camera-access-tutorial/ //Klasa napisana z pomocą tutorialu dostępnego na https://androidkennel.org/android-camera-access-tutorial/.
public class TakePhoto extends AppCompatActivity { public class TakePhoto extends AppCompatActivity {
public File photoFile; File photoFile;
String path; String path;
@Override @Override
@ -23,21 +21,26 @@ public class TakePhoto extends AppCompatActivity {
openCamera(); openCamera();
} }
//Uruchomienie androidowego modułu kamery //Uruchomienie androidowego modułu kamery.
public void openCamera() { private void openCamera() {
Intent intent_Camera = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); Intent intent_Camera = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
photoFile = getOutputMediaFile(); photoFile = getOutputMediaFile();
Uri photoFileUri = Uri.fromFile(photoFile); Uri photoFileUri = Uri.fromFile(photoFile); //Zgodny z pewnym standardem łańcuch znaków.
intent_Camera.putExtra(MediaStore.EXTRA_OUTPUT, photoFileUri); intent_Camera.putExtra(MediaStore.EXTRA_OUTPUT, photoFileUri); //Kamera "wypełnia" przekazany jej pusty plik.
startActivityForResult(intent_Camera, 100); //w przeciwieństwie do startActivity zwraca wynik w postaci Intentu odbieranego poniżej startActivityForResult(intent_Camera, 100); //W przeciwieństwie do startActivity zwraca wynik w postaci Intentu odbieranego
//poniżej.
} }
//Jeśli moduł kamery zostanie zamknięty zanim zrobione zostanie zdjęcie to activity skanowania się kończy, w innym razie przechodzi dalej //Jeśli moduł kamery zostanie zamknięty zanim zrobione zostanie zdjęcie to activity skanowania się kończy i "puste" zdjęcie zostaje usunięte,
//w innym razie przechodzi dalej.
@Override @Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) { protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data); super.onActivityResult(requestCode, resultCode, data);
path = photoFile.getAbsolutePath();
if (requestCode == 100) { if (requestCode == 100) {
if (resultCode == RESULT_CANCELED) { if (resultCode == RESULT_CANCELED) {
File filefordeletion = new File(path);
filefordeletion.delete();
finish(); finish();
} else { } else {
goDecode(); goDecode();
@ -45,13 +48,14 @@ public class TakePhoto extends AppCompatActivity {
} }
} }
//Tworzenie katalogu dla danych aplikacji jesli nie istnieje; umieszczanie w nim tymczasowego pliku zdjecia w formacie .jpg //Tworzenie katalogu dla danych aplikacji jesli nie istnieje; umieszczanie w nim tymczasowego pliku zdjecia w formacie .jpg.
private static File getOutputMediaFile() { private static File getOutputMediaFile() {
File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory( File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES), "Lookify"); Environment.DIRECTORY_PICTURES), "Lookify"); //Pozyskiwanie ścieżki do publicznego katalogu z obrazami z podkatalogiem
//dla naszej aplikacji.
if (!mediaStorageDir.exists()) { if (!mediaStorageDir.exists()) { //Jeśli katalog z powyższej ścieżki nie istnieje...
if (!mediaStorageDir.mkdirs()) { if (!mediaStorageDir.mkdirs()) { //...stwórz go; jeśli to niemożliwe, zwróć null.
return null; return null;
} }
} }
@ -60,9 +64,8 @@ public class TakePhoto extends AppCompatActivity {
"TEMP" + ".jpg"); "TEMP" + ".jpg");
} }
//Przejście do activity odpowiedzialnego za odczytywanie kodu wraz z przekazaniem jej ścieżki zdjęcia //Przejście do activity odpowiedzialnego za odczytywanie kodu wraz z przekazaniem jej ścieżki zdjęcia.
public void goDecode(){ private void goDecode(){
path = photoFile.getAbsolutePath();
Intent intent_Decode = new Intent(this, Decode.class); Intent intent_Decode = new Intent(this, Decode.class);
intent_Decode.putExtra("takenPic", path); intent_Decode.putExtra("takenPic", path);
startActivity(intent_Decode); startActivity(intent_Decode);

View File

@ -44,13 +44,12 @@
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/favouriterecyclerview" android:id="@+id/favouriterecyclerview"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="match_parent"
card_view:cardUseCompatPadding="true"
card_view:cardElevation="4dp"
card_view:cardCornerRadius="4dp"
android:scrollbars="vertical"
android:layout_marginTop="6dp"
android:layout_marginLeft="5dp" android:layout_marginLeft="5dp"
android:layout_marginRight="5dp" /> android:layout_marginTop="6dp"
android:layout_marginRight="5dp"
android:scrollbars="vertical"
card_view:cardCornerRadius="4dp"
card_view:cardElevation="4dp"
card_view:cardUseCompatPadding="true" />
</RelativeLayout> </RelativeLayout>

View File

@ -1 +1 @@
#Tue Feb 25 23:39:16 CET 2020 #Sat Jun 20 00:20:56 CEST 2020