Checkpoint Screen Design

master
saad.siddiq 2026-01-27 18:06:15 +05:00
parent eb02e85eb9
commit b50037625f
17 changed files with 419 additions and 305 deletions

View File

@ -20,7 +20,7 @@
tools:ignore="ScopedStorage" /> tools:ignore="ScopedStorage" />
<application <application
android:allowBackup="true" android:allowBackup="false"
android:dataExtractionRules="@xml/data_extraction_rules" android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules" android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
@ -55,7 +55,7 @@
<provider <provider
android:name="androidx.core.content.FileProvider" android:name="androidx.core.content.FileProvider"
android:authorities="com.utopiaindustries.qc_android" android:authorities="${applicationId}.provider"
android:exported="false" android:exported="false"
android:grantUriPermissions="true"> android:grantUriPermissions="true">
<meta-data <meta-data

View File

@ -65,15 +65,12 @@ public class DashboardActivity extends AppCompatActivity {
btnFetchProduct.setOnClickListener(v -> { btnFetchProduct.setOnClickListener(v -> {
if (Helper.isNetworkConnected(this)) { if (Helper.isNetworkConnected(this)) {
serviceViewModel.getCheckpointsData(this);
} }
}); });
btnLogout.setOnClickListener(v -> {}); btnLogout.setOnClickListener(v -> {});
btnAppUpdate.setOnClickListener(v -> {}); btnAppUpdate.setOnClickListener(v -> {});
btnReportUpload.setOnClickListener(v -> {}); btnReportUpload.setOnClickListener(v -> {});
} }
public void initializeLayout() { public void initializeLayout() {

View File

@ -1,26 +1,43 @@
package com.utopiaindustries.qc_android.activities; package com.utopiaindustries.qc_android.activities;
import android.os.Bundle; import android.os.Bundle;
import android.view.Window;
import android.view.WindowManager;
import androidx.activity.EdgeToEdge; import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;
import androidx.core.graphics.Insets; import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat; import androidx.core.view.ViewCompat;
import androidx.core.view.WindowCompat;
import androidx.core.view.WindowInsetsCompat; import androidx.core.view.WindowInsetsCompat;
import androidx.core.view.WindowInsetsControllerCompat;
import androidx.lifecycle.ViewModelProvider;
import androidx.navigation.NavController; import androidx.navigation.NavController;
import androidx.navigation.Navigation; import androidx.navigation.Navigation;
import com.utopiaindustries.qc_android.R; import com.utopiaindustries.qc_android.R;
import com.utopiaindustries.qc_android.db.CheckpointRepository;
import com.utopiaindustries.qc_android.models.InspectionCheckPoint;
import com.utopiaindustries.qc_android.viewmodels.DataEntryViewModel;
import java.util.ArrayList;
import java.util.List;
public class QCTerryActivity extends AppCompatActivity { public class QCTerryActivity extends AppCompatActivity {
private NavController navController; private NavController navController;
private List<InspectionCheckPoint> checkPointList = new ArrayList<>();
private DataEntryViewModel viewModel;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
EdgeToEdge.enable(this); EdgeToEdge.enable(this);
setContentView(R.layout.activity_qcterry); setContentView(R.layout.activity_qcterry);
setStatusBarColor();
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> { ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()); Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom); v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
@ -32,6 +49,9 @@ public class QCTerryActivity extends AppCompatActivity {
private void initializeLayout() { private void initializeLayout() {
viewModel = new ViewModelProvider(this).get(DataEntryViewModel.class);
loadCheckPoints();
// Setup Navigation // Setup Navigation
navController = Navigation.findNavController(this, R.id.nav_host_fragment); navController = Navigation.findNavController(this, R.id.nav_host_fragment);
} }
@ -40,4 +60,57 @@ public class QCTerryActivity extends AppCompatActivity {
public boolean onSupportNavigateUp() { public boolean onSupportNavigateUp() {
return navController.navigateUp() || super.onSupportNavigateUp(); return navController.navigateUp() || super.onSupportNavigateUp();
} }
private void loadCheckPoints() {
checkPointList.clear();
CheckpointRepository checkpointRepository = new CheckpointRepository(this);
checkPointList = checkpointRepository.findAll();
/*InspectionCheckPoint item1 = new InspectionCheckPoint(1, "Safety Helmet Check", "Safety");
checkPointList.add(item1);
InspectionCheckPoint item2 = new InspectionCheckPoint(2, "Fire Extinguisher Check", "Safety");
checkPointList.add(item2);
InspectionCheckPoint item3 = new InspectionCheckPoint(3, "Material Quality Inspection", "Quality");
checkPointList.add(item3);
InspectionCheckPoint item4 = new InspectionCheckPoint(4, "Weld Quality Check", "Quality");
checkPointList.add(item4);
InspectionCheckPoint item5 = new InspectionCheckPoint(5, "Electrical Panel Inspection", "Electrical");
checkPointList.add(item5);
InspectionCheckPoint item6 = new InspectionCheckPoint(6, "Wiring Safety Check", "Electrical");
checkPointList.add(item6);
InspectionCheckPoint item8 = new InspectionCheckPoint(8, "Machine Guarding Check", "Mechanical");
checkPointList.add(item8);
InspectionCheckPoint item9 = new InspectionCheckPoint(9, "Structural Integrity", "Civil");
checkPointList.add(item9);
for (int i = 11; i <= 15; i++) {
String[] categories = {"Safety", "Quality", "Electrical", "General"};
String category = categories[(i - 11) % categories.length];
InspectionCheckPoint item = new InspectionCheckPoint(i, "Check Point " + i, category);
checkPointList.add(item);
}*/
viewModel.setCheckPointList(checkPointList);
}
private void setStatusBarColor() {
Window window = getWindow();
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
window.setStatusBarColor(ContextCompat.getColor(this, R.color.theme_color));
WindowInsetsControllerCompat controller =
WindowCompat.getInsetsController(window, window.getDecorView());
controller.setAppearanceLightStatusBars(false);
}
} }

View File

@ -73,8 +73,7 @@ public class CheckPointAdapter extends RecyclerView.Adapter<CheckPointAdapter.Ch
setupListeners(holder, position); setupListeners(holder, position);
} }
private void setupImagesRecyclerView(CheckPointViewHolder holder, int parentPosition, private void setupImagesRecyclerView(CheckPointViewHolder holder, int parentPosition, InspectionCheckPoint item) {
InspectionCheckPoint item) {
// Create and setup images adapter // Create and setup images adapter
/*ImageAdapter imagesAdapter = new ImageAdapter(item.getImages(), /*ImageAdapter imagesAdapter = new ImageAdapter(item.getImages(),
new ImageAdapter.OnImageClickListener() { new ImageAdapter.OnImageClickListener() {

View File

@ -12,10 +12,10 @@ import retrofit2.converter.gson.GsonConverterFactory;
public class RetrofitClient { public class RetrofitClient {
//Live url //Live url
//private final static String BASE_URL = "https://portal.utopiaindustries.pk/uind/"; private final static String BASE_URL = "https://portal.utopiaindustries.pk/uind/";
//Test Url //Test Url
private final static String BASE_URL = "http://192.168.90.22:8081/uind/"; //private final static String BASE_URL = "http://192.168.90.22:8081/uind/";
private static Retrofit retrofit; private static Retrofit retrofit;
@ -25,19 +25,11 @@ public class RetrofitClient {
//.registerTypeAdapter(Boolean.class, new BooleanTypeAdapter()) //.registerTypeAdapter(Boolean.class, new BooleanTypeAdapter())
.create(); .create();
if (retrofit == null) { if (retrofit == null) {
try { try {
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.connectTimeout(60, TimeUnit.SECONDS)
.readTimeout(60, TimeUnit.SECONDS)
.writeTimeout(60, TimeUnit.SECONDS)
.build();
retrofit = new Retrofit.Builder() retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL) .baseUrl(BASE_URL)
.client(okHttpClient) .client(SSLCheckHttpClient.getOkHttpClient())
.addConverterFactory(GsonConverterFactory.create(gson)) .addConverterFactory(GsonConverterFactory.create(gson))
.build(); .build();
} catch (Exception e) { } catch (Exception e) {

View File

@ -184,30 +184,30 @@ public class DatabaseHelper extends SQLiteOpenHelper {
db.execSQL( CREATE_PRODUCT_TABLE ); //db.execSQL( CREATE_PRODUCT_TABLE );
db.execSQL( CREATE_INSPECTION_DIMENSION_TABLE ); //db.execSQL( CREATE_INSPECTION_DIMENSION_TABLE );
db.execSQL( CREATE_CHECKPOINT_TABLE ); db.execSQL( CREATE_CHECKPOINT_TABLE );
db.execSQL( CREATE_DEFECT_TABLE ); ///db.execSQL( CREATE_DEFECT_TABLE );
db.execSQL( CREATE_UNIT_TABLE ); //db.execSQL( CREATE_UNIT_TABLE );
db.execSQL( CREATE_REPORT_TABLE ); //db.execSQL( CREATE_REPORT_TABLE );
db.execSQL( CREATE_DRAFT_REPORT_TABLE); //db.execSQL( CREATE_DRAFT_REPORT_TABLE);
db.execSQL( CREATE_SKU_CHECKPOINT_TABLE ); //db.execSQL( CREATE_SKU_CHECKPOINT_TABLE );
db.execSQL( CREATE_INSPECTION_LABEL_TABLE ); //db.execSQL( CREATE_INSPECTION_LABEL_TABLE );
db.execSQL( CREATE_QUALITY_LABEL_TABLE ); //db.execSQL( CREATE_QUALITY_LABEL_TABLE );
} }
@Override @Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL( "DROP TABLE IF EXISTS " + PRODUCT_TABLE_NAME); //db.execSQL( "DROP TABLE IF EXISTS " + PRODUCT_TABLE_NAME);
db.execSQL( "DROP TABLE IF EXISTS " + INSPECTION_DIMENSION_TABLE_NAME ); //db.execSQL( "DROP TABLE IF EXISTS " + INSPECTION_DIMENSION_TABLE_NAME );
db.execSQL( "DROP TABLE IF EXISTS " + CHECKPOINT_TABLE_NAME ); db.execSQL( "DROP TABLE IF EXISTS " + CHECKPOINT_TABLE_NAME );
db.execSQL( "DROP TABLE IF EXISTS " + DEFECT_TABLE_NAME ); //db.execSQL( "DROP TABLE IF EXISTS " + DEFECT_TABLE_NAME );
db.execSQL( "DROP TABLE IF EXISTS " + UNIT_TABLE_NAME ); //db.execSQL( "DROP TABLE IF EXISTS " + UNIT_TABLE_NAME );
db.execSQL( "DROP TABLE IF EXISTS " + REPORT_TABLE_NAME ); //db.execSQL( "DROP TABLE IF EXISTS " + REPORT_TABLE_NAME );
db.execSQL( "DROP TABLE IF EXISTS " + DRAFT_REPORT_TABLE_NAME ); // db.execSQL( "DROP TABLE IF EXISTS " + DRAFT_REPORT_TABLE_NAME );
db.execSQL( "DROP TABLE IF EXISTS " + CHECKPOINT_SKU_TABLE_NAME ); //db.execSQL( "DROP TABLE IF EXISTS " + CHECKPOINT_SKU_TABLE_NAME );
db.execSQL( "DROP TABLE IF EXISTS " + INSPECTION_LABEL_TABLE_NAME ); //db.execSQL( "DROP TABLE IF EXISTS " + INSPECTION_LABEL_TABLE_NAME );
db.execSQL( "DROP TABLE IF EXISTS " + QUALITY_LABEL_TABLE_NAME ); //db.execSQL( "DROP TABLE IF EXISTS " + QUALITY_LABEL_TABLE_NAME );
onCreate(db); onCreate(db);
} }
} }

View File

@ -10,6 +10,7 @@ import android.net.Uri;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.provider.MediaStore; import android.provider.MediaStore;
import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
@ -35,6 +36,7 @@ import androidx.recyclerview.widget.RecyclerView;
import com.utopiaindustries.qc_android.R; import com.utopiaindustries.qc_android.R;
import com.utopiaindustries.qc_android.adapters.CheckPointAdapter; import com.utopiaindustries.qc_android.adapters.CheckPointAdapter;
import com.utopiaindustries.qc_android.helper.Helper;
import com.utopiaindustries.qc_android.models.InspectionCheckPoint; import com.utopiaindustries.qc_android.models.InspectionCheckPoint;
import com.utopiaindustries.qc_android.viewmodels.DataEntryViewModel; import com.utopiaindustries.qc_android.viewmodels.DataEntryViewModel;
@ -66,12 +68,12 @@ public class FragmentQcTerryTwo extends Fragment implements CheckPointAdapter.On
private static final int PENDING_CAMERA = 1; private static final int PENDING_CAMERA = 1;
private static final int PENDING_GALLERY = 2; private static final int PENDING_GALLERY = 2;
private int pendingAction = 0; private int pendingAction = 0;
private int currentPosition = -1;
@Nullable @Nullable
@Override @Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
@Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_qc_terry_two, container, false); View view = inflater.inflate(R.layout.fragment_qc_terry_two, container, false);
initializeLayouts(view); initializeLayouts(view);
@ -83,161 +85,6 @@ public class FragmentQcTerryTwo extends Fragment implements CheckPointAdapter.On
recyclerView = view.findViewById(R.id.check_point_recycler_view); recyclerView = view.findViewById(R.id.check_point_recycler_view);
btnNext = view.findViewById(R.id.btnNext); btnNext = view.findViewById(R.id.btnNext);
// Setup RecyclerView
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
adapter = new CheckPointAdapter(getActivity(), checkPointList, this);
recyclerView.setAdapter(adapter);
//loadCheckPoints();
}
private void loadCheckPoints() {
checkPointList.clear();
// Item 1: Using 7-field constructor
List<byte[]> item1Images = createImages("Helmet", 2);
InspectionCheckPoint item1 = new InspectionCheckPoint(
1, // id
"Safety Helmet Check", // title
"Safety", // category
true, // isOkChecked
false, // isNoChecked
"All workers wearing helmets properly", // remarks
item1Images // images
);
checkPointList.add(item1);
// Item 2: NO checked with single image
List<byte[]> item2Images = new ArrayList<>();
item2Images.add(createSampleImageBytes("Fire_Extinguisher"));
InspectionCheckPoint item2 = new InspectionCheckPoint(
2,
"Fire Extinguisher Check",
"Safety",
false,
true,
"Fire extinguisher expired, needs replacement",
item2Images
);
checkPointList.add(item2);
// Item 3: Quality check with multiple images
List<byte[]> item3Images = createImages("Material", 3);
InspectionCheckPoint item3 = new InspectionCheckPoint(
3,
"Material Quality Inspection",
"Quality",
true,
false,
"Material meets all specifications",
item3Images
);
checkPointList.add(item3);
// Item 4: NO status with many images
List<byte[]> item4Images = createImages("Weld_Defect", 5);
InspectionCheckPoint item4 = new InspectionCheckPoint(
4,
"Weld Quality Check",
"Quality",
false,
true,
"Poor weld quality, needs rework",
item4Images
);
checkPointList.add(item4);
// Item 5: Pending (no status selected), no images
InspectionCheckPoint item5 = new InspectionCheckPoint(
5,
"Electrical Panel Inspection",
"Electrical",
false,
false,
"Awaiting electrician's review",
new ArrayList<>() // Empty images list
);
checkPointList.add(item5);
// Item 6: OK checked with one image
List<byte[]> item6Images = new ArrayList<>();
item6Images.add(createSampleImageBytes("Wiring"));
InspectionCheckPoint item6 = new InspectionCheckPoint(
6,
"Wiring Safety Check",
"Electrical",
true,
false,
"All wiring properly insulated and secured",
item6Images
);
checkPointList.add(item6);
// Item 8: NO checked, no remarks
List<byte[]> item8Images = createImages("Missing_Guard", 2);
InspectionCheckPoint item8 = new InspectionCheckPoint(
8,
"Machine Guarding Check",
"Mechanical",
false,
true,
null, // No remarks
item8Images
);
checkPointList.add(item8);
// Item 9: OK with default empty images
InspectionCheckPoint item9 = new InspectionCheckPoint(
9,
"Structural Integrity",
"Civil",
true,
false,
"Structure stable, no cracks observed",
null // Will be converted to empty list in constructor
);
checkPointList.add(item9);
// Add more items using loops
for (int i = 11; i <= 15; i++) {
String[] categories = {"Safety", "Quality", "Electrical", "General"};
String category = categories[(i - 11) % categories.length];
List<byte[]> images = new ArrayList<>();
int imageCount = (i % 3); // 0, 1, or 2 images
for (int j = 0; j < imageCount; j++) {
images.add(createSampleImageBytes("CP" + i + "_Img" + j));
}
boolean isOkChecked = (i % 2 == 0);
boolean isNoChecked = (i % 3 == 0);
InspectionCheckPoint item = new InspectionCheckPoint(
i,
"Check Point " + i,
category,
isOkChecked,
isNoChecked,
"Remarks for check point " + i,
images
);
checkPointList.add(item);
}
adapter.notifyDataSetChanged();
}
private List<byte[]> createImages(String prefix, int count) {
List<byte[]> images = new ArrayList<>();
for (int i = 1; i <= count; i++) {
images.add(createSampleImageBytes(prefix + "_" + i));
}
return images;
}
private byte[] createSampleImageBytes(String imageName) {
String imageData = "SAMPLE_IMAGE[" + imageName + "]_" + System.currentTimeMillis();
return imageData.getBytes();
} }
@Override @Override
@ -246,6 +93,15 @@ public class FragmentQcTerryTwo extends Fragment implements CheckPointAdapter.On
viewModel = new ViewModelProvider(requireActivity()).get(DataEntryViewModel.class); viewModel = new ViewModelProvider(requireActivity()).get(DataEntryViewModel.class);
checkPointList.addAll(viewModel.getCheckPointList().getValue());
// Setup RecyclerView
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
adapter = new CheckPointAdapter(getActivity(), checkPointList, this);
recyclerView.setAdapter(adapter);
// Initialize Activity Result Launchers
initializeLaunchers();
// Load existing data // Load existing data
/*if (viewModel.getAddress().getValue() != null) { /*if (viewModel.getAddress().getValue() != null) {
edtAddress.setText(viewModel.getAddress().getValue()); edtAddress.setText(viewModel.getAddress().getValue());
@ -254,6 +110,8 @@ public class FragmentQcTerryTwo extends Fragment implements CheckPointAdapter.On
edtCity.setText(viewModel.getCity().getValue()); edtCity.setText(viewModel.getCity().getValue());
}*/ }*/
btnNext.setOnClickListener(new View.OnClickListener() { btnNext.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
@ -272,6 +130,7 @@ public class FragmentQcTerryTwo extends Fragment implements CheckPointAdapter.On
public void onImagePickerClicked(int position) { public void onImagePickerClicked(int position) {
// Handle image picker click // Handle image picker click
//openImagePicker(position); //openImagePicker(position);
alertForPictures(getActivity(), position);
} }
@Override @Override
@ -294,8 +153,12 @@ public class FragmentQcTerryTwo extends Fragment implements CheckPointAdapter.On
@Override @Override
public void onRemarksChanged(int position, String remarks) { public void onRemarksChanged(int position, String remarks) {
// Update remarks in the model // Update remarks in the model
Log.e("Pos: ",""+position);
Log.e("Remarks: ",""+remarks);
InspectionCheckPoint item = checkPointList.get(position); InspectionCheckPoint item = checkPointList.get(position);
item.setRemarks(remarks); item.setRemarks(remarks);
viewModel.setCheckPointList(checkPointList);
Log.e("ViewModel: ",""+viewModel.getCheckPointList().getValue());
} }
@Override @Override
@ -304,6 +167,7 @@ public class FragmentQcTerryTwo extends Fragment implements CheckPointAdapter.On
InspectionCheckPoint item = checkPointList.get(position); InspectionCheckPoint item = checkPointList.get(position);
item.setOkChecked(isOkChecked); item.setOkChecked(isOkChecked);
item.setNoChecked(isNoChecked); item.setNoChecked(isNoChecked);
viewModel.setCheckPointList(checkPointList);
} }
private void openImagePicker(int position) { private void openImagePicker(int position) {
@ -313,7 +177,7 @@ public class FragmentQcTerryTwo extends Fragment implements CheckPointAdapter.On
// adapter.addImageToCheckPoint(position, imageUri); // adapter.addImageToCheckPoint(position, imageUri);
} }
public void alertForPictures(Context con) { public void alertForPictures(Context con, int position) {
ViewGroup viewGroup = requireActivity().findViewById(android.R.id.content); ViewGroup viewGroup = requireActivity().findViewById(android.R.id.content);
TextView dialogCameraBtn, dialogGalleryBtn; TextView dialogCameraBtn, dialogGalleryBtn;
@ -334,7 +198,7 @@ public class FragmentQcTerryTwo extends Fragment implements CheckPointAdapter.On
public void onClick(View view) { public void onClick(View view) {
alertDialog.dismiss(); alertDialog.dismiss();
checkPermissionAndOpenCamera(); checkPermissionAndOpenCamera(position);
} }
}); });
@ -343,7 +207,7 @@ public class FragmentQcTerryTwo extends Fragment implements CheckPointAdapter.On
public void onClick(View view) { public void onClick(View view) {
alertDialog.dismiss(); alertDialog.dismiss();
checkPermissionAndOpenGallery(); checkPermissionAndOpenGallery(position);
} }
}); });
@ -385,6 +249,25 @@ public class FragmentQcTerryTwo extends Fragment implements CheckPointAdapter.On
if (result.getResultCode() == getActivity().RESULT_OK && photoUri != null) { if (result.getResultCode() == getActivity().RESULT_OK && photoUri != null) {
//imageView.setImageURI(photoUri); //imageView.setImageURI(photoUri);
viewModel.setSelectedImageUri(photoUri); viewModel.setSelectedImageUri(photoUri);
Helper.uriToByteArrayAsync(
getContext(),
photoUri,
100,
compressedImage -> {
requireActivity().runOnUiThread(() -> {
checkPointList.get(currentPosition).addImage(compressedImage);
adapter.notifyItemChanged(currentPosition);
viewModel.setCheckPointList(checkPointList);
currentPosition = -1;
});
},
error -> {
requireActivity().runOnUiThread(() -> {
Toast.makeText(getContext(), "Error compressing image: " + error.getMessage(), Toast.LENGTH_SHORT).show();
});
}
);
} }
}); });
@ -395,6 +278,25 @@ public class FragmentQcTerryTwo extends Fragment implements CheckPointAdapter.On
if (uri != null) { if (uri != null) {
//imageView.setImageURI(uri); //imageView.setImageURI(uri);
viewModel.setSelectedImageUri(uri); viewModel.setSelectedImageUri(uri);
Helper.uriToByteArrayAsync(
getContext(),
uri,
100,
compressedImage -> {
requireActivity().runOnUiThread(() -> {
checkPointList.get(currentPosition).addImage(compressedImage);
adapter.notifyItemChanged(currentPosition);
viewModel.setCheckPointList(checkPointList);
currentPosition = -1;
});
},
error -> {
requireActivity().runOnUiThread(() -> {
Toast.makeText(getContext(), "Error compressing image: " + error.getMessage(), Toast.LENGTH_SHORT).show();
});
}
);
} }
}); });
} }
@ -402,8 +304,9 @@ public class FragmentQcTerryTwo extends Fragment implements CheckPointAdapter.On
/** /**
* Check permissions and open camera * Check permissions and open camera
*/ */
private void checkPermissionAndOpenCamera() { private void checkPermissionAndOpenCamera(int position) {
String[] requiredPermissions = getRequiredCameraPermissions(); String[] requiredPermissions = getRequiredCameraPermissions();
currentPosition = position;
if (hasPermissions(requiredPermissions)) { if (hasPermissions(requiredPermissions)) {
openCamera(); openCamera();
@ -416,8 +319,9 @@ public class FragmentQcTerryTwo extends Fragment implements CheckPointAdapter.On
/** /**
* Check permissions and open gallery * Check permissions and open gallery
*/ */
private void checkPermissionAndOpenGallery() { private void checkPermissionAndOpenGallery(int position) {
String[] requiredPermissions = getRequiredGalleryPermissions(); String[] requiredPermissions = getRequiredGalleryPermissions();
currentPosition = position;
if (hasPermissions(requiredPermissions)) { if (hasPermissions(requiredPermissions)) {
openGallery(); openGallery();
@ -499,9 +403,9 @@ public class FragmentQcTerryTwo extends Fragment implements CheckPointAdapter.On
File storageDir = requireContext().getExternalFilesDir(null); File storageDir = requireContext().getExternalFilesDir(null);
File image = File.createTempFile( File image = File.createTempFile(
imageFileName, /* prefix */ imageFileName,
".jpg", /* suffix */ ".jpg",
storageDir /* directory */ storageDir
); );
return image; return image;

View File

@ -25,6 +25,7 @@ import com.google.gson.reflect.TypeToken;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.File; import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Type; import java.lang.reflect.Type;
@ -456,4 +457,51 @@ public class Helper {
} }
}); });
}*/ }*/
public static void uriToByteArrayAsync(
Context context,
Uri uri,
int targetSizeInKB,
Consumer<byte[]> onSuccess,
Consumer<Exception> 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();
}
} }

View File

@ -22,14 +22,14 @@ public class InspectionCheckPoint implements Serializable {
public InspectionCheckPoint() { public InspectionCheckPoint() {
} }
public InspectionCheckPoint(long id, String title, String category, boolean isOkChecked, boolean isNoChecked, String remarks, List<byte[]> images) { public InspectionCheckPoint(long id, String title, String category) {
this.id = id; this.id = id;
this.title = title; this.title = title;
this.category = category; this.category = category;
this.isOkChecked = isOkChecked; this.isOkChecked = isOkChecked;
this.isNoChecked = isNoChecked; this.isNoChecked = isNoChecked;
this.remarks = remarks; this.remarks = remarks;
this.images = images; this.images = (images != null) ? images : new ArrayList<>();
} }
public long getId() { public long getId() {
@ -113,6 +113,10 @@ public class InspectionCheckPoint implements Serializable {
"id=" + id + "id=" + id +
", title='" + title + '\'' + ", title='" + title + '\'' +
", category='" + category + '\'' + ", category='" + category + '\'' +
", isOkChecked=" + isOkChecked +
", isNoChecked=" + isNoChecked +
", remarks='" + remarks + '\'' +
", images=" + images +
'}'; '}';
} }
} }

View File

@ -6,6 +6,11 @@ import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel; import androidx.lifecycle.ViewModel;
import com.utopiaindustries.qc_android.models.InspectionCheckPoint;
import java.util.ArrayList;
import java.util.List;
public class DataEntryViewModel extends ViewModel { public class DataEntryViewModel extends ViewModel {
// Personal Info // Personal Info
@ -23,6 +28,9 @@ public class DataEntryViewModel extends ViewModel {
private MutableLiveData<Uri> selectedImageUri = new MutableLiveData<>(); private MutableLiveData<Uri> selectedImageUri = new MutableLiveData<>();
private MutableLiveData<List<InspectionCheckPoint>> checkPointList =
new MutableLiveData<>(new ArrayList<>());
// Getters and Setters // Getters and Setters
public LiveData<String> getFirstName() { public LiveData<String> getFirstName() {
return firstName; return firstName;
@ -87,4 +95,12 @@ public class DataEntryViewModel extends ViewModel {
public void setSelectedImageUri(Uri uri) { public void setSelectedImageUri(Uri uri) {
selectedImageUri.setValue(uri); selectedImageUri.setValue(uri);
} }
public LiveData<List<InspectionCheckPoint>> getCheckPointList() {
return checkPointList;
}
public void setCheckPointList(List<InspectionCheckPoint> list) {
checkPointList.setValue(list);
}
} }

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle">
<corners android:radius="8dp" />
<padding
android:bottom="1dp"
android:left="1dp"
android:right="1dp"
android:top="1dp" />
<solid android:color="#0D000000" /> </shape>
</item>
<item android:bottom="2dp" android:right="2dp" android:top="1dp" android:left="1dp">
<shape android:shape="rectangle">
<corners android:radius="8dp" />
<solid android:color="@android:color/white" />
<stroke android:width="1dp" android:color="#E0E0E0"/> </shape>
</item>
</layer-list>

View File

@ -33,7 +33,7 @@
android:layout_marginBottom="20dp" android:layout_marginBottom="20dp"
android:padding="5dp" android:padding="5dp"
android:text="Login Now to Continue" android:text="Login Now to Continue"
android:textSize="@dimen/_16sdp" /> android:textSize="@dimen/_14sdp" />
<com.google.android.material.textfield.TextInputLayout <com.google.android.material.textfield.TextInputLayout
@ -91,7 +91,7 @@
android:padding="5dp" android:padding="5dp"
android:text="Login" android:text="Login"
android:textColor="@color/white" android:textColor="@color/white"
android:textSize="@dimen/_15sdp" /> android:textSize="@dimen/_12sdp" />
</LinearLayout> </LinearLayout>
<TextView <TextView

View File

@ -8,38 +8,42 @@
android:clickable="true" android:clickable="true"
android:elevation="10dp" android:elevation="10dp"
android:focusable="true" android:focusable="true"
android:padding="4dp" android:padding="5dp"
app:cardBackgroundColor="@color/white"> app:cardBackgroundColor="@color/white">
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical" android:orientation="vertical">
android:padding="8dp">
<TextView
android:id="@+id/check_point_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:background="@color/grey_200"
android:layout_gravity="center|right"
android:layout_marginBottom="5dp"
android:textStyle="bold" />
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_margin="5dp"
android:orientation="horizontal"> android:orientation="horizontal">
<TextView
android:id="@+id/check_point_title"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:layout_weight="4" />
<CheckBox <CheckBox
android:id="@+id/check_point_ok" android:id="@+id/check_point_ok"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="50dp" android:layout_height="50dp"
android:layout_weight="1" android:layout_weight="0.5"
android:text="OK" /> android:text="OK" />
<CheckBox <CheckBox
android:id="@+id/check_point_no" android:id="@+id/check_point_no"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="50dp" android:layout_height="50dp"
android:layout_weight="1" android:layout_weight="10.5"
android:text="NO" /> android:text="NO" />
</LinearLayout> </LinearLayout>
@ -47,10 +51,11 @@
<EditText <EditText
android:id="@+id/check_point_remarks" android:id="@+id/check_point_remarks"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="50dp" android:layout_height="wrap_content"
android:layout_marginTop="3dp" android:layout_margin="5dp"
android:layout_weight="4" android:background="@drawable/et_border"
android:hint="Remarks" /> android:hint="Remarks"
android:padding="10dp" />
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@ -27,7 +27,7 @@
android:text="Select Image from" android:text="Select Image from"
android:textAllCaps="false" android:textAllCaps="false"
android:textColor="@color/black" android:textColor="@color/black"
android:textSize="@dimen/_15sdp" android:textSize="@dimen/_11sdp"
android:textStyle="normal" /> android:textStyle="normal" />
<View <View
@ -54,7 +54,7 @@
android:text="Camera" android:text="Camera"
android:textAllCaps="false" android:textAllCaps="false"
android:textColor="@color/white" android:textColor="@color/white"
android:textSize="@dimen/_14sdp" android:textSize="@dimen/_10sdp"
android:textStyle="normal" /> android:textStyle="normal" />
<TextView <TextView
@ -77,7 +77,7 @@
android:textAllCaps="false" android:textAllCaps="false"
android:background="@drawable/custom_button" android:background="@drawable/custom_button"
android:textColor="@color/white" android:textColor="@color/white"
android:textSize="@dimen/_14sdp" android:textSize="@dimen/_10sdp"
android:textStyle="normal" /> android:textStyle="normal" />
</LinearLayout> </LinearLayout>

View File

@ -1,109 +1,142 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent">
android:orientation="vertical"
android:padding="16dp">
<TextView <androidx.appcompat.widget.Toolbar
android:layout_width="wrap_content" android:id="@+id/toolbar"
android:layout_height="wrap_content"
android:layout_marginBottom="24dp"
android:text="Personal Information"
android:textSize="20sp"
android:textStyle="bold" />
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginBottom="16dp" android:background="@color/theme_color"
android:hint="First Name" android:minHeight="?attr/actionBarSize"
app:errorEnabled="true"> android:theme="?attr/actionBarTheme" >
<EditText <TextView
android:id="@+id/edtFirstName" android:id="@+id/textView"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:inputType="textPersonName" /> android:text="QC - Terry"
</com.google.android.material.textfield.TextInputLayout> android:layout_gravity="center"
android:gravity="center"
android:padding="5dp"
android:textColor="@color/white"
android:textSize="@dimen/_11sdp" />
</androidx.appcompat.widget.Toolbar>
<com.google.android.material.textfield.TextInputLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="match_parent"
android:layout_marginBottom="16dp" android:layout_below="@+id/toolbar"
android:hint="Last Name" android:layout_above="@+id/btnNext"
app:errorEnabled="true"> android:layout_margin="5dp"
android:padding="10dp"
android:orientation="vertical">
<EditText <TextView
android:id="@+id/edtLastName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPersonName" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="32dp"
android:hint="Email"
app:errorEnabled="true">
<EditText
android:id="@+id/edtEmail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textEmailAddress" />
</com.google.android.material.textfield.TextInputLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<LinearLayout
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_alignParentStart="true" android:layout_marginBottom="24dp"
android:layout_centerInParent="true" android:text="Personal Information"
android:padding="5dp" android:textSize="20sp"
android:orientation="vertical" android:textStyle="bold" />
android:layout_marginBottom="16dp">
<Button <com.google.android.material.textfield.TextInputLayout
android:id="@+id/btnCamera" android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:hint="First Name"
app:errorEnabled="true">
<EditText
android:id="@+id/edtFirstName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPersonName" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:hint="Last Name"
app:errorEnabled="true">
<EditText
android:id="@+id/edtLastName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPersonName" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="32dp"
android:hint="Email"
app:errorEnabled="true">
<EditText
android:id="@+id/edtEmail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textEmailAddress" />
</com.google.android.material.textfield.TextInputLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<LinearLayout
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1" android:layout_alignParentStart="true"
android:text="Camera" /> android:layout_centerInParent="true"
android:layout_marginBottom="16dp"
android:orientation="vertical"
android:padding="5dp">
<Button <Button
android:id="@+id/btnGallery" android:id="@+id/btnCamera"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1" android:layout_weight="1"
android:text="Gallery " /> android:background="@drawable/rounded_btn_login"
android:text="Camera" />
</LinearLayout> <Button
android:id="@+id/btnGallery"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_weight="1"
android:background="@drawable/rounded_btn_login"
android:text="Gallery " />
<ImageView </LinearLayout>
android:id="@+id/imageView"
android:layout_width="200dp"
android:layout_height="200dp"
android:padding="5dp"
android:layout_alignParentEnd="true"
android:background="#f0f0f0"
android:scaleType="centerCrop"
android:layout_marginBottom="24dp"/>
</RelativeLayout>
<ImageView
android:id="@+id/imageView"
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_alignParentEnd="true"
android:layout_marginBottom="24dp"
android:background="#f0f0f0"
android:padding="5dp"
android:scaleType="centerCrop" />
</RelativeLayout>
</LinearLayout>
<Button <Button
android:id="@+id/btnNext" android:id="@+id/btnNext"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="16dp" android:layout_alignParentBottom="true"
android:textSize="@dimen/_11sdp"
android:padding="10dp"
android:background="@drawable/rounded_btn_login"
android:text="Next →" /> android:text="Next →" />
</LinearLayout> </RelativeLayout>

View File

@ -5,11 +5,33 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical"> android:orientation="vertical">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/theme_color"
android:minHeight="?attr/actionBarSize"
android:theme="?attr/actionBarTheme" >
<TextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="QC - Terry"
android:layout_gravity="center"
android:gravity="center"
android:padding="5dp"
android:textColor="@color/white"
android:textSize="@dimen/_11sdp" />
</androidx.appcompat.widget.Toolbar>
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/check_point_recycler_view" android:id="@+id/check_point_recycler_view"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_below="@+id/toolbar"
android:layout_above="@+id/btnNext" android:layout_above="@+id/btnNext"
android:layout_margin="5dp"
android:padding="8dp" /> android:padding="8dp" />
<Button <Button
@ -20,6 +42,7 @@
android:layout_alignParentBottom="true" android:layout_alignParentBottom="true"
android:background="@drawable/rounded_btn_login" android:background="@drawable/rounded_btn_login"
android:padding="10dp" android:padding="10dp"
android:textSize="@dimen/_11sdp"
android:text="Next →" /> android:text="Next →" />
</RelativeLayout> </RelativeLayout>

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android"> <paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="my_images" path="Android/data/com.utopiaindustries.qc_android/files/Pictures" /> <external-path name="external_files" path="." />
</paths> </paths>