diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 4fd93b0..38a9d46 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -10,7 +10,7 @@ - + + android:windowSoftInputMode="stateAlwaysHidden"> + @@ -40,33 +41,35 @@ android:name=".ui.activities.MainActivity" android:exported="true" android:screenOrientation="portrait" - android:windowSoftInputMode="stateHidden|adjustPan"> - + android:windowSoftInputMode="stateHidden|adjustPan"> - + android:theme="@style/AppTheme" + android:windowSoftInputMode="adjustPan|adjustResize"> + - + + + - + @@ -79,7 +82,6 @@ android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> - \ No newline at end of file diff --git a/app/src/main/java/com/utopiaindustries/qualitychecker/apiservice/RetrofitClient.java b/app/src/main/java/com/utopiaindustries/qualitychecker/apiservice/RetrofitClient.java index 70a96f8..28e238d 100644 --- a/app/src/main/java/com/utopiaindustries/qualitychecker/apiservice/RetrofitClient.java +++ b/app/src/main/java/com/utopiaindustries/qualitychecker/apiservice/RetrofitClient.java @@ -19,8 +19,8 @@ import retrofit2.Retrofit; import retrofit2.converter.gson.GsonConverterFactory; public class RetrofitClient { - private final static String BASE_URL = "https://portal.utopiaindustries.pk/uind/"; - //private final static String BASE_URL = "http://192.168.91.44:8081/uind/";//"http://192.168.91.44:8081/uind/";//"http://192.168.90.27:8080/uind/";//"http://192.168.91.16:8080/uind/"; + //private final static String BASE_URL = "https://portal.utopiaindustries.pk/uind/"; + private final static String BASE_URL = "http://192.168.91.44:8081/uind/";//"http://192.168.91.44:8081/uind/";//"http://192.168.90.27:8080/uind/";//"http://192.168.91.16:8080/uind/"; private static Retrofit retrofit; diff --git a/app/src/main/java/com/utopiaindustries/qualitychecker/models/InspectionItemDimension.java b/app/src/main/java/com/utopiaindustries/qualitychecker/models/InspectionItemDimension.java index 2e8fd9f..43c8952 100644 --- a/app/src/main/java/com/utopiaindustries/qualitychecker/models/InspectionItemDimension.java +++ b/app/src/main/java/com/utopiaindustries/qualitychecker/models/InspectionItemDimension.java @@ -2,6 +2,8 @@ package com.utopiaindustries.qualitychecker.models; import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; public class InspectionItemDimension implements Serializable { diff --git a/app/src/main/java/com/utopiaindustries/qualitychecker/models/InspectionReportItem.java b/app/src/main/java/com/utopiaindustries/qualitychecker/models/InspectionReportItem.java index 459e3c8..b3a9d01 100644 --- a/app/src/main/java/com/utopiaindustries/qualitychecker/models/InspectionReportItem.java +++ b/app/src/main/java/com/utopiaindustries/qualitychecker/models/InspectionReportItem.java @@ -3,6 +3,7 @@ package com.utopiaindustries.qualitychecker.models; import androidx.annotation.NonNull; import java.io.Serializable; +import java.util.ArrayList; import java.util.List; public class InspectionReportItem implements Serializable { @@ -59,6 +60,7 @@ public class InspectionReportItem implements Serializable { // wrapper private List checkPoints; private List dimensions; + private List dimensionImages = new ArrayList<>(); private String fnsku; @@ -424,6 +426,14 @@ public void setLevelMinorDefects(int levelMinorDefects) { this.section = section; } + public List getDimensionImages() { + return dimensionImages; + } + + public void addDimensionImageList(byte[] image) { + this.dimensionImages.add(image); + } + @Override public String toString() { return "InspectionReportItem{" + @@ -472,6 +482,7 @@ public void setLevelMinorDefects(int levelMinorDefects) { ", section='" + section + '\'' + ", dimensions=" + dimensions + ", fnsku='" + fnsku + '\'' + + ", dimensionImages=" + dimensionImages + '}'; } } diff --git a/app/src/main/java/com/utopiaindustries/qualitychecker/ui/activities/MainActivity.java b/app/src/main/java/com/utopiaindustries/qualitychecker/ui/activities/MainActivity.java index 6f863ed..15b48b2 100644 --- a/app/src/main/java/com/utopiaindustries/qualitychecker/ui/activities/MainActivity.java +++ b/app/src/main/java/com/utopiaindustries/qualitychecker/ui/activities/MainActivity.java @@ -31,6 +31,7 @@ import com.utopiaindustries.qualitychecker.ui.fragments.FirstStepFragment; import com.utopiaindustries.qualitychecker.ui.fragments.SecondStepFragment; import com.google.zxing.integration.android.IntentIntegrator; import com.google.zxing.integration.android.IntentResult; +import com.utopiaindustries.qualitychecker.ui.fragments.ThirdStepFragment; import com.utopiaindustries.qualitychecker.utils.FileUtils; import java.io.ByteArrayInputStream; @@ -45,6 +46,9 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe private String fromClass; private String draftReportId; + private static final int CAMERA_REQUEST = 10111; + private static final int GALLERY_REQUEST = 20111; + @SuppressLint("SourceLockedOrientationActivity") @Override protected void onCreate(Bundle savedInstanceState) { @@ -118,6 +122,14 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe } } } + else if (requestCode == CAMERA_REQUEST) { + ThirdStepFragment thirdStepFragment = ( ThirdStepFragment) getCurrentVisibleFragment(); + thirdStepFragment.onImagePickerResult( requestCode, resultCode, data ); + } + else if (requestCode == GALLERY_REQUEST) { + ThirdStepFragment thirdStepFragment = ( ThirdStepFragment) getCurrentVisibleFragment(); + thirdStepFragment.onImagePickerResult( requestCode, resultCode, data ); + } else if (requestCode != -1 && resultCode == -1 && data == null) { Log.e("camera ","------- camera ***"); SecondStepFragment secondStepFragment = ( SecondStepFragment) getCurrentVisibleFragment(); diff --git a/app/src/main/java/com/utopiaindustries/qualitychecker/ui/fragments/SecondStepFragment.java b/app/src/main/java/com/utopiaindustries/qualitychecker/ui/fragments/SecondStepFragment.java index c27e549..f696b7f 100644 --- a/app/src/main/java/com/utopiaindustries/qualitychecker/ui/fragments/SecondStepFragment.java +++ b/app/src/main/java/com/utopiaindustries/qualitychecker/ui/fragments/SecondStepFragment.java @@ -36,6 +36,7 @@ import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import com.bumptech.glide.Glide; +import com.google.android.material.floatingactionbutton.FloatingActionButton; import com.utopiaindustries.qualitychecker.R; import com.utopiaindustries.qualitychecker.async.ImageProcessor; import com.utopiaindustries.qualitychecker.models.callback.SaveDraftReportCallback; @@ -60,7 +61,7 @@ public class SecondStepFragment extends Fragment implements View.OnClickListener { private NavController navController; - private Button leftFab, rightFab, draftFab; + private Button leftFab, rightFab, draftFab, moveToBottom; private RecyclerView recyclerView; private CheckPointAdapter adapter; private TextView profileName; @@ -83,6 +84,7 @@ public class SecondStepFragment extends Fragment draftFab = view.findViewById(R.id.button_draft_second); leftFab = view.findViewById(R.id.button_left_frag_2); rightFab = view.findViewById(R.id.button_right_frag_2); + moveToBottom = view.findViewById(R.id.button_move_to_bottom); recyclerView = view.findViewById(R.id.check_point_recycler_view); profileName = view.findViewById(R.id.second_profile_name); profileImage = view.findViewById(R.id.second_step_profile_image); @@ -128,6 +130,7 @@ public class SecondStepFragment extends Fragment leftFab.setOnClickListener(this); rightFab.setOnClickListener(this); draftFab.setOnClickListener(this); + moveToBottom.setOnClickListener(this); updateProfileViews(); return view; } @@ -186,6 +189,11 @@ public class SecondStepFragment extends Fragment if (v.getId() == R.id.button_right_frag_2) { checkIsRecyclerViewIsCompletelyScrolled(recyclerView); } + + if (v.getId() == R.id.button_move_to_bottom) { + Log.e("Fab-Button","click"); + scrollToBottom(); + } } public void onImagePickerResult(int requestCode, int resultCode, Intent data) { @@ -334,6 +342,12 @@ public class SecondStepFragment extends Fragment }).start(); } + private void scrollToBottom() { + if (adapter != null && adapter.getItemCount() > 0) { + //recyclerView.scrollToPosition(adapter.getItemCount() - 1); // Scroll to the last item + recyclerView.smoothScrollToPosition(adapter.getItemCount() - 1); // Smooth scroll, if desired. + } + } private void checkIsRecyclerViewIsCompletelyScrolled(RecyclerView recyclerView) { if (recyclerView.getLayoutManager() instanceof LinearLayoutManager) { diff --git a/app/src/main/java/com/utopiaindustries/qualitychecker/ui/fragments/ThirdStepFragment.java b/app/src/main/java/com/utopiaindustries/qualitychecker/ui/fragments/ThirdStepFragment.java index b7a2fd6..3bdc474 100644 --- a/app/src/main/java/com/utopiaindustries/qualitychecker/ui/fragments/ThirdStepFragment.java +++ b/app/src/main/java/com/utopiaindustries/qualitychecker/ui/fragments/ThirdStepFragment.java @@ -1,11 +1,20 @@ package com.utopiaindustries.qualitychecker.ui.fragments; +import static android.app.Activity.RESULT_OK; + +import android.Manifest; import android.annotation.SuppressLint; +import android.app.Activity; import android.content.Context; +import android.content.Intent; import android.content.SharedPreferences; +import android.content.pm.PackageManager; +import android.net.Uri; import android.os.Bundle; +import android.os.Environment; import android.os.Handler; import android.os.Looper; +import android.provider.MediaStore; import android.text.Editable; import android.text.TextWatcher; import android.util.Log; @@ -17,6 +26,7 @@ import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.EditText; +import android.widget.ImageButton; import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.Spinner; @@ -26,7 +36,9 @@ import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AlertDialog; +import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; +import androidx.core.content.FileProvider; import androidx.fragment.app.Fragment; import androidx.navigation.NavController; import androidx.navigation.Navigation; @@ -48,9 +60,14 @@ import com.utopiaindustries.qualitychecker.notification.NotificationHelper; import com.utopiaindustries.qualitychecker.service.InspectionReportService; import com.utopiaindustries.qualitychecker.store.Store; import com.utopiaindustries.qualitychecker.ui.adapter.DimensionAdapter; +import com.utopiaindustries.qualitychecker.ui.adapter.ImageAdapter; import com.utopiaindustries.qualitychecker.ui.adapter.ItemDimensionAdapter; import com.utopiaindustries.qualitychecker.ui.adapter.VocAdapter; +import com.utopiaindustries.qualitychecker.utils.FileUtils; +import com.utopiaindustries.qualitychecker.utils.ImageUriHolder; +import java.io.File; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Objects; @@ -62,6 +79,7 @@ import retrofit2.Response; public class ThirdStepFragment extends Fragment implements View.OnClickListener { private NavController navController; private Button backBtn,nextBtn,openDimensionDialog, btnDraft; + private ImageButton imagePicker, deleteImage ; private TextView profileName; private ImageView profileImage; private InspectionReportService inspectionReportService; @@ -70,6 +88,15 @@ public class ThirdStepFragment extends Fragment implements View.OnClickListener private Spinner resultSpinner, sectionSpinner; private ApiService apiService; private EditText generalRemarks, etQualityAuditor, etProdRepresentative, etQcRepresentative,etFloor; + private static final int MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE = 100; + private static final int MY_PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE = 101; + private static final int MY_PERMISSIONS_REQUEST_CAMERA = 102; + + private static final int CAMERA_REQUEST = 10111; + private static final int GALLERY_REQUEST = 20111; + + private ImageAdapter imageAdapter; + private RecyclerView imageRecyclerView; private TextView minorCountTv,majorCountTv,criticalCountTv, txtMajor, txtMinor; String[] sectionArray = {"Comforter & Mattress Pad", @@ -89,6 +116,7 @@ public class ThirdStepFragment extends Fragment implements View.OnClickListener apiService = ApiServiceFactory.getApiService(); initializeViews( view ); + checkPermissions(); populateViews(); setOnClickListeners(); updateProfileViews(); @@ -220,9 +248,110 @@ public class ThirdStepFragment extends Fragment implements View.OnClickListener } }); + + imagePicker.setOnClickListener( new View.OnClickListener() { + @Override + public void onClick(View v) { + + AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); + builder.setTitle("Choose an Option"); + + String[] options = {"Gallery", "Camera"}; + builder.setItems(options, (dialog, which) -> { + switch (which) { + case 0: + Log.e("Gallery","**********"); + Intent intent = new Intent( Intent.ACTION_GET_CONTENT ); + intent.addCategory( Intent.CATEGORY_OPENABLE ); + intent.setType( "image/*" ); + //startActivityForResult( intent, GALLERY_REQUEST ); + ( ( Activity ) getContext() ).startActivityForResult( intent, GALLERY_REQUEST ); + break; + case 1: + Log.e("Camera: ","***********"); + Intent camera_intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); + File imageFile = new File(getContext().getExternalFilesDir(Environment.DIRECTORY_PICTURES), "captured_image.jpg"); + Uri imageUri = FileProvider.getUriForFile(getContext(), getContext().getPackageName() + ".fileprovider", imageFile); + //Log.e("imageUri: ",""+imageUri); + ImageUriHolder.getInstance().setImageUri(imageUri); + camera_intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri); + //startActivityForResult(camera_intent, CAMERA_REQUEST); + ( ( Activity ) getContext() ).startActivityForResult( camera_intent, CAMERA_REQUEST ); + break; + } + }); + + builder.setNegativeButton("Cancel", (dialog, which) -> dialog.dismiss()); + + AlertDialog dialog = builder.create(); + dialog.show(); + + } + }); + + deleteImage.setOnClickListener( new View.OnClickListener() { + @Override + public void onClick(View v) { + + if (!store.getReport().getItems().get(0).getDimensionImages().isEmpty()) { + store.getReport().getItems().get(0).getDimensionImages().remove(store.getReport().getItems().get(0).getDimensionImages().size() - 1); + updateImageAdapter(store.getReport().getItems().get(0).getDimensionImages()); + } + else { + System.out.println("The list is empty"); + } + } + }); + return view; } + public void onImagePickerResult(int requestCode, int resultCode, Intent data) { + if (requestCode == CAMERA_REQUEST) { + Uri selectedImageUri = ImageUriHolder.getInstance().getImageUri(); + saveImage(selectedImageUri); + } + else if (requestCode == GALLERY_REQUEST) { + Uri selectedImageUri = data.getData(); + assert selectedImageUri != null; + saveImage(selectedImageUri); + } + } + + private void saveImage(Uri imageUri) { + FileUtils.convertUriToByteArrayAsync( + getContext(), + imageUri, + 100, // Target size in KB + compressedImage -> { + // Handle the compressed image here, e.g., display it + requireActivity().runOnUiThread(() -> { + store.getReport().getItems().get(0).addDimensionImageList(compressedImage); + updateImageAdapter(store.getReport().getItems().get(0).getDimensionImages()); + //adapter.notifyItemChanged(requestCode); + }); + }, + error -> { + // Handle any errors + requireActivity().runOnUiThread(() -> { + Toast.makeText(getContext(), "Error compressing image: " + error.getMessage(), Toast.LENGTH_SHORT).show(); + }); + } + ); + + + } + + private void updateImageAdapter(List imgFiles) { + imageRecyclerView.setLayoutManager(new LinearLayoutManager(getContext(), LinearLayoutManager.HORIZONTAL, false)); + imageAdapter = new ImageAdapter(imgFiles, getContext()); + imageRecyclerView.setAdapter(imageAdapter); + + int position = imgFiles.size(); + imageAdapter.notifyItemInserted(position); + + } + @Override public void onClick(View v) { navController = Navigation.findNavController( requireView() ); @@ -488,6 +617,11 @@ public class ThirdStepFragment extends Fragment implements View.OnClickListener txtMajor.setText(String.format("Major : %s/%d", (int)majorInspection, (int)(majorInspection + 1))); txtMinor.setText(String.format("Minor : %s/%d", (int)minorInspection, (int)(minorInspection + 1))); } + + if (!store.getReport().getItems().get(0).getDimensionImages().isEmpty()) { + updateImageAdapter(store.getReport().getItems().get(0).getDimensionImages()); + } + } private void calculateDimensions(){ @@ -546,6 +680,9 @@ public class ThirdStepFragment extends Fragment implements View.OnClickListener backBtn = view.findViewById( R.id.button_left_frag_3 ); nextBtn = view.findViewById( R.id.button_right_frag_3 ); btnDraft = view.findViewById(R.id.button_draft_third); + imagePicker = view.findViewById(R.id.image_picker); + deleteImage = view.findViewById(R.id.delete_image); + imageRecyclerView = view.findViewById(R.id.imageRecyclerView); openDimensionDialog = view.findViewById( R.id.button_open_dimension ); profileImage = view.findViewById( R.id.third_step_profile_image ); profileName = view.findViewById( R.id.third_profile_name ); @@ -580,4 +717,34 @@ public class ThirdStepFragment extends Fragment implements View.OnClickListener .load( store.getProfileImage( ) ) .into( profileImage ); } + + // PERMISSIONS + private void checkPermissions() { + // Check if permission is not granted + if (ContextCompat.checkSelfPermission(getContext(), Manifest.permission.READ_EXTERNAL_STORAGE) + != PackageManager.PERMISSION_GRANTED) { + + // Permission is not granted, request it + ActivityCompat.requestPermissions(getActivity(), + new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, + MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE); + } + + if (ContextCompat.checkSelfPermission(getContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE) + != PackageManager.PERMISSION_GRANTED) { + + ActivityCompat.requestPermissions(getActivity(), + new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, + MY_PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE); + } + + if (ContextCompat.checkSelfPermission(getContext(), Manifest.permission.CAMERA) + != PackageManager.PERMISSION_GRANTED) { + + ActivityCompat.requestPermissions(getActivity(), + new String[]{Manifest.permission.CAMERA}, + MY_PERMISSIONS_REQUEST_CAMERA); + } + } + } diff --git a/app/src/main/java/com/utopiaindustries/qualitychecker/utils/FileUtils.java b/app/src/main/java/com/utopiaindustries/qualitychecker/utils/FileUtils.java index 6bb320e..5ab36f2 100644 --- a/app/src/main/java/com/utopiaindustries/qualitychecker/utils/FileUtils.java +++ b/app/src/main/java/com/utopiaindustries/qualitychecker/utils/FileUtils.java @@ -3,6 +3,7 @@ package com.utopiaindustries.qualitychecker.utils; import android.app.Activity; import android.content.Context; import android.graphics.Bitmap; +import android.graphics.BitmapFactory; import android.net.Uri; import android.os.Handler; import android.os.Looper; @@ -25,7 +26,9 @@ import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStream; import java.util.Objects; +import java.util.function.Consumer; public class FileUtils { public static String writeFile( Context context , @@ -154,4 +157,51 @@ public class FileUtils { dialog.show(); } + + public static void convertUriToByteArrayAsync( + Context context, + Uri uri, + int targetSizeInKB, + Consumer onSuccess, + Consumer onError + ) { + new Thread(() -> { + try { + int targetSizeInBytes = targetSizeInKB * 1024; + + // Load the image as a Bitmap without scaling + Bitmap bitmap; + try (InputStream inputStream = context.getContentResolver().openInputStream(uri)) { + bitmap = BitmapFactory.decodeStream(inputStream); + } + + if (bitmap == null) { + throw new IOException("Failed to decode image from URI."); + } + + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + int minQuality = 10; + int maxQuality = 100; + int quality = maxQuality; + + // Binary search for the best quality that meets the target size + while (minQuality <= maxQuality) { + byteArrayOutputStream.reset(); + bitmap.compress(Bitmap.CompressFormat.JPEG, quality, byteArrayOutputStream); + + int byteSize = byteArrayOutputStream.size(); + if (byteSize > targetSizeInBytes) { + maxQuality = quality - 1; + } else { + minQuality = quality + 1; + } + quality = (minQuality + maxQuality) / 2; + } + + onSuccess.accept(byteArrayOutputStream.toByteArray()); + } catch (IOException e) { + onError.accept(e); + } + }).start(); + } } diff --git a/app/src/main/res/layout/fragment_second_step.xml b/app/src/main/res/layout/fragment_second_step.xml index ffb4dad..9341388 100644 --- a/app/src/main/res/layout/fragment_second_step.xml +++ b/app/src/main/res/layout/fragment_second_step.xml @@ -8,6 +8,7 @@ android:id="@+id/fragment_tag"> +