Added essential http request and methods for places image upload to server
This commit is contained in:
parent
ef9092467f
commit
d66f357753
|
|
@ -1,5 +1,7 @@
|
||||||
package com.example.acloc.activity;
|
package com.example.acloc.activity;
|
||||||
|
|
||||||
|
import static com.example.acloc.utility.Constants.BASE_URL;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
@ -16,6 +18,7 @@ import androidx.appcompat.app.AppCompatActivity;
|
||||||
import androidx.appcompat.widget.AppCompatButton;
|
import androidx.appcompat.widget.AppCompatButton;
|
||||||
import androidx.appcompat.widget.Toolbar;
|
import androidx.appcompat.widget.Toolbar;
|
||||||
|
|
||||||
|
import com.example.acloc.utility.UploadManager;
|
||||||
import com.ieslamar.acloc.R;
|
import com.ieslamar.acloc.R;
|
||||||
import com.example.acloc.api.LocationApiClient;
|
import com.example.acloc.api.LocationApiClient;
|
||||||
import com.example.acloc.model.Place;
|
import com.example.acloc.model.Place;
|
||||||
|
|
@ -26,6 +29,10 @@ import com.example.acloc.utility.Helper;
|
||||||
import com.example.acloc.utility.SharedPref;
|
import com.example.acloc.utility.SharedPref;
|
||||||
import com.google.android.material.textfield.TextInputEditText;
|
import com.google.android.material.textfield.TextInputEditText;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
|
import com.squareup.picasso.Picasso;
|
||||||
|
|
||||||
|
import org.json.JSONException;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
import retrofit2.Call;
|
import retrofit2.Call;
|
||||||
import retrofit2.Callback;
|
import retrofit2.Callback;
|
||||||
|
|
@ -46,6 +53,10 @@ public class AddNewPlaceActivity extends AppCompatActivity implements View.OnCli
|
||||||
private String place_uuid;
|
private String place_uuid;
|
||||||
private static final int PICK_IMAGE_REQUEST = 200;
|
private static final int PICK_IMAGE_REQUEST = 200;
|
||||||
|
|
||||||
|
private Uri selectedImageUri;
|
||||||
|
private String imageUrl;
|
||||||
|
private String JSonString;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
@ -140,14 +151,44 @@ public class AddNewPlaceActivity extends AppCompatActivity implements View.OnCli
|
||||||
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);
|
||||||
if (requestCode == PICK_IMAGE_REQUEST && resultCode == RESULT_OK && data != null && data.getData() != null) {
|
if (requestCode == PICK_IMAGE_REQUEST && resultCode == RESULT_OK && data != null && data.getData() != null) {
|
||||||
// Get the image URI
|
selectedImageUri = data.getData();
|
||||||
Uri selectedImageUri = data.getData();
|
|
||||||
|
|
||||||
// Set the image in the ImageView
|
// Load image using Picasso
|
||||||
ivPlacePhoto.setImageURI(selectedImageUri);
|
Picasso.get().load(selectedImageUri).into(ivPlacePhoto);
|
||||||
|
|
||||||
|
// Upload the image
|
||||||
|
uploadImageToServer(selectedImageUri);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void uploadImageToServer(Uri imageUri) {
|
||||||
|
UploadManager.uploadImage(this, imageUri, new UploadManager.UploadCallback() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(String response) {
|
||||||
|
try {
|
||||||
|
JSONObject json = new JSONObject(response);
|
||||||
|
if (json.getBoolean("success")) {
|
||||||
|
String filename = json.getJSONObject("file").getString("filename");
|
||||||
|
imageUrl = BASE_URL + "public/" + filename;
|
||||||
|
JSonString = "[\"" + imageUrl + "\"]";
|
||||||
|
Helper.makeSnackBar(rlAddPlace, "Image uploaded successfully");
|
||||||
|
Log.d(TAG, "JsonString: " + JSonString);
|
||||||
|
} else {
|
||||||
|
Helper.makeSnackBar(rlAddPlace, "Upload failed");
|
||||||
|
}
|
||||||
|
} catch (JSONException e) {
|
||||||
|
Helper.makeSnackBar(rlAddPlace, "Response parsing error");
|
||||||
|
Log.e(TAG, "Failed to parse JSON", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void onError(String message) {
|
||||||
|
Helper.makeSnackBar(rlAddPlace, "Upload failed: " + message);
|
||||||
|
Log.e(TAG, "Upload error:" + message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private void onClickBtnSubmit() {
|
private void onClickBtnSubmit() {
|
||||||
View[] views = {etPlaceName, etLatitude, etLongitude, etAddress, etPlaceDescription};
|
View[] views = {etPlaceName, etLatitude, etLongitude, etAddress, etPlaceDescription};
|
||||||
if (Helper.isEmptyFieldValidation(views)) {
|
if (Helper.isEmptyFieldValidation(views)) {
|
||||||
|
|
@ -186,6 +227,7 @@ public class AddNewPlaceActivity extends AppCompatActivity implements View.OnCli
|
||||||
placeBody.addProperty("latitude", latitude);
|
placeBody.addProperty("latitude", latitude);
|
||||||
placeBody.addProperty("longitude", longitude);
|
placeBody.addProperty("longitude", longitude);
|
||||||
placeBody.addProperty("createdBy", createdBy);
|
placeBody.addProperty("createdBy", createdBy);
|
||||||
|
placeBody.addProperty("images", JSonString);
|
||||||
|
|
||||||
String token = "Bearer " + SharedPref.getAccessToken(context);
|
String token = "Bearer " + SharedPref.getAccessToken(context);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,14 @@
|
||||||
package com.example.acloc.api;
|
package com.example.acloc.api;
|
||||||
|
|
||||||
import static com.example.acloc.utility.Constants.BASE_URL;
|
|
||||||
|
|
||||||
import com.example.acloc.service.AuthService;
|
import com.example.acloc.service.AuthService;
|
||||||
import com.example.acloc.service.FavoriteService;
|
import com.example.acloc.service.FavoriteService;
|
||||||
import com.example.acloc.service.PlaceService;
|
import com.example.acloc.service.PlaceService;
|
||||||
import com.example.acloc.service.ReportService;
|
import com.example.acloc.service.ReportService;
|
||||||
import com.example.acloc.service.RoleService;
|
import com.example.acloc.service.RoleService;
|
||||||
|
import com.example.acloc.service.UploadService;
|
||||||
import com.example.acloc.service.UserService;
|
import com.example.acloc.service.UserService;
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
import okhttp3.OkHttpClient;
|
|
||||||
import okhttp3.logging.HttpLoggingInterceptor;
|
|
||||||
import retrofit2.Retrofit;
|
import retrofit2.Retrofit;
|
||||||
import retrofit2.converter.gson.GsonConverterFactory;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Centralized API client that manages Retrofit instance and provides access to all service interfaces
|
* Centralized API client that manages Retrofit instance and provides access to all service interfaces
|
||||||
|
|
@ -30,6 +24,7 @@ public class LocationApiClient {
|
||||||
private ReportService reportService;
|
private ReportService reportService;
|
||||||
private RoleService roleService;
|
private RoleService roleService;
|
||||||
private UserService userService;
|
private UserService userService;
|
||||||
|
private UploadService uploadService;
|
||||||
|
|
||||||
// Private constructor for singleton pattern
|
// Private constructor for singleton pattern
|
||||||
private LocationApiClient() {
|
private LocationApiClient() {
|
||||||
|
|
@ -112,4 +107,11 @@ public class LocationApiClient {
|
||||||
}
|
}
|
||||||
return userService;
|
return userService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public UploadService getUploadService(){
|
||||||
|
if(uploadService == null){
|
||||||
|
uploadService = retrofit.create(UploadService.class);
|
||||||
|
}
|
||||||
|
return uploadService;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
package com.example.acloc.service;
|
||||||
|
|
||||||
|
import okhttp3.MultipartBody;
|
||||||
|
import okhttp3.ResponseBody;
|
||||||
|
import retrofit2.Call;
|
||||||
|
import retrofit2.http.Multipart;
|
||||||
|
import retrofit2.http.POST;
|
||||||
|
import retrofit2.http.Part;
|
||||||
|
|
||||||
|
public interface UploadService {
|
||||||
|
@Multipart
|
||||||
|
@POST("upload")
|
||||||
|
Call<ResponseBody> uploadImage(@Part MultipartBody.Part file);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
package com.example.acloc.utility;
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
package com.example.acloc.utility;
|
||||||
|
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
|
||||||
|
import com.squareup.picasso.Picasso;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility class to handle image loading operations
|
||||||
|
* Separates image loading responsibility from activities
|
||||||
|
*/
|
||||||
|
public class ImageLoaderUtil {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads an image from a Uri into an ImageView
|
||||||
|
*
|
||||||
|
* @param imageUri Source Uri of the image
|
||||||
|
* @param targetView Target ImageView where the image will be displayed
|
||||||
|
*/
|
||||||
|
public static void loadImage(Uri imageUri, ImageView targetView) {
|
||||||
|
if (imageUri != null && targetView != null) {
|
||||||
|
Picasso.get().load(imageUri).into(targetView);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads an image from a Uri into an ImageView with placeholder and error handling
|
||||||
|
*
|
||||||
|
* @param imageUri Source Uri of the image
|
||||||
|
* @param targetView Target ImageView where the image will be displayed
|
||||||
|
* @param placeholderResId Resource ID for the placeholder image
|
||||||
|
* @param errorResId Resource ID for the error image
|
||||||
|
*/
|
||||||
|
public static void loadImageWithPlaceholder(
|
||||||
|
Uri imageUri,
|
||||||
|
ImageView targetView,
|
||||||
|
int placeholderResId,
|
||||||
|
int errorResId) {
|
||||||
|
if (imageUri != null && targetView != null) {
|
||||||
|
Picasso.get()
|
||||||
|
.load(imageUri)
|
||||||
|
.placeholder(placeholderResId)
|
||||||
|
.error(errorResId)
|
||||||
|
.into(targetView);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,106 @@
|
||||||
|
package com.example.acloc.utility;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.provider.OpenableColumns;
|
||||||
|
import android.webkit.MimeTypeMap;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
|
||||||
|
import okhttp3.MediaType;
|
||||||
|
import okhttp3.MultipartBody;
|
||||||
|
import okhttp3.RequestBody;
|
||||||
|
|
||||||
|
public class ImagePicker {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a file from a Uri.
|
||||||
|
*
|
||||||
|
* @param context The application context
|
||||||
|
* @param uri The Uri to get the file from
|
||||||
|
* @return The file
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public static File getFileFromUri(Context context, Uri uri) throws IOException {
|
||||||
|
String fileName = getFileName(context, uri);
|
||||||
|
File file = new File(context.getCacheDir(), fileName);
|
||||||
|
|
||||||
|
// Copy the file to the cache directory
|
||||||
|
try (InputStream inputStream = context.getContentResolver().openInputStream(uri);
|
||||||
|
OutputStream outputStream = new FileOutputStream(file)) {
|
||||||
|
|
||||||
|
if (inputStream == null) {
|
||||||
|
throw new IOException("Failed to open input stream.");
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] buffer = new byte[4 * 1024]; // 4k buffer
|
||||||
|
int read;
|
||||||
|
while ((read = inputStream.read(buffer)) != -1) {
|
||||||
|
outputStream.write(buffer, 0, read);
|
||||||
|
}
|
||||||
|
|
||||||
|
outputStream.flush();
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the file name from a Uri
|
||||||
|
*
|
||||||
|
* @param context The application context
|
||||||
|
* @param uri The Uri to get the file name from
|
||||||
|
* @return The file name
|
||||||
|
*/
|
||||||
|
private static String getFileName(Context context, Uri uri) {
|
||||||
|
String result = null;
|
||||||
|
if (uri.getScheme().equals("content")) {
|
||||||
|
try (Cursor cursor = context.getContentResolver().query(uri, null, null, null, null)) {
|
||||||
|
if (cursor != null && cursor.moveToFirst()) {
|
||||||
|
int nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
|
||||||
|
if (nameIndex != -1) {
|
||||||
|
result = cursor.getString(nameIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result == null) {
|
||||||
|
result = uri.getPath();
|
||||||
|
int cut = result.lastIndexOf('/');
|
||||||
|
if (cut != -1) {
|
||||||
|
result = result.substring(cut + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepare a file part for a multipart request
|
||||||
|
*
|
||||||
|
* @param partName The name of the part
|
||||||
|
* @param file The file to upload
|
||||||
|
* @return The MultipartBody.Part
|
||||||
|
*/
|
||||||
|
public static MultipartBody.Part prepareFilePart(String partName, File file) {
|
||||||
|
// Get the MIME type
|
||||||
|
String extension = MimeTypeMap.getFileExtensionFromUrl(file.getPath());
|
||||||
|
String mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
|
||||||
|
|
||||||
|
if (mimeType == null) {
|
||||||
|
// Default to image/jpeg if MIME type cannot be determined
|
||||||
|
mimeType = "image/jpeg";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create RequestBody instance from file
|
||||||
|
RequestBody requestFile = RequestBody.create(MediaType.parse(mimeType), file);
|
||||||
|
|
||||||
|
// MultipartBody.Part is used to send the actual file
|
||||||
|
return MultipartBody.Part.createFormData(partName, file.getName(), requestFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,73 @@
|
||||||
|
package com.example.acloc.utility;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.net.Uri;
|
||||||
|
|
||||||
|
import com.example.acloc.api.LocationApiClient;
|
||||||
|
import com.example.acloc.service.UploadService;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import okhttp3.MultipartBody;
|
||||||
|
import okhttp3.ResponseBody;
|
||||||
|
import retrofit2.Call;
|
||||||
|
import retrofit2.Callback;
|
||||||
|
import retrofit2.Response;
|
||||||
|
|
||||||
|
public class UploadManager {
|
||||||
|
public interface UploadCallback {
|
||||||
|
void onSuccess(String message);
|
||||||
|
void onError(String message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Uploads an image to the server
|
||||||
|
*
|
||||||
|
* @param context Application context
|
||||||
|
* @param imageUri URI of the image to upload
|
||||||
|
* @param callback Callback to handle the upload result
|
||||||
|
*/
|
||||||
|
public static void uploadImage(Context context, Uri imageUri, UploadCallback callback) {
|
||||||
|
if (context == null || imageUri == null || callback == null) {
|
||||||
|
if (callback != null) {
|
||||||
|
callback.onError("Invalid parameters");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
File file = ImagePicker.getFileFromUri(context, imageUri);
|
||||||
|
MultipartBody.Part filePart = ImagePicker.prepareFilePart("file", file);
|
||||||
|
|
||||||
|
performUpload(filePart, callback);
|
||||||
|
} catch (IOException e) {
|
||||||
|
callback.onError("Error preparing file: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void performUpload(MultipartBody.Part filePart, UploadCallback callback) {
|
||||||
|
UploadService uploadService = LocationApiClient.getInstance().getUploadService();
|
||||||
|
|
||||||
|
|
||||||
|
uploadService.uploadImage(filePart).enqueue(new Callback<ResponseBody>() {
|
||||||
|
@Override
|
||||||
|
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
|
||||||
|
if (response.isSuccessful()) {
|
||||||
|
try {
|
||||||
|
callback.onSuccess(response.body().string());
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
callback.onError("Server error: " + response.code());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Call<ResponseBody> call, Throwable t) {
|
||||||
|
callback.onError("Connection error: " + t.getMessage());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue