diff --git a/ProbnaSlika.png b/ProbnaSlika.png
new file mode 100644
index 0000000..02be370
Binary files /dev/null and b/ProbnaSlika.png differ
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index da8f44d..e61290a 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -40,6 +40,8 @@ dependencies {
implementation("com.squareup.retrofit2:retrofit:2.9.0")
implementation("com.squareup.retrofit2:converter-gson:2.9.0")
+ implementation ("com.github.bumptech.glide:glide:4.16.0")
+ annotationProcessor ("com.github.bumptech.glide:compiler:4.16.0")
testImplementation(libs.junit)
androidTestImplementation(libs.ext.junit)
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index ce85111..663a763 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -16,7 +16,8 @@
+ tools:ignore="Instantiatable"
+ android:windowSoftInputMode="adjustResize|stateHidden"/>
diff --git a/app/src/main/java/com/example/gallery/LoginActivity.java b/app/src/main/java/com/example/gallery/LoginActivity.java
index 9f5cdd1..5c34323 100644
--- a/app/src/main/java/com/example/gallery/LoginActivity.java
+++ b/app/src/main/java/com/example/gallery/LoginActivity.java
@@ -4,6 +4,7 @@ import android.content.Intent;
import android.os.Bundle;
import android.widget.Button;
import android.widget.EditText;
+import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
@@ -12,7 +13,6 @@ import com.example.gallery.api.ApiClient;
import com.example.gallery.api.ApiService;
import com.example.gallery.models.LoginRequest;
import com.example.gallery.models.LoginResponse;
-import com.example.gallery.UserResponse;
import retrofit2.Call;
import retrofit2.Callback;
@@ -20,84 +20,60 @@ import retrofit2.Response;
public class LoginActivity extends AppCompatActivity {
- EditText usernameEdit, passwordEdit;
- Button loginBtn;
+ private EditText usernameEdit, passwordEdit;
+ private Button loginBtn;
+ private TextView registerTV;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
- // Updated ids from your XML
usernameEdit = findViewById(R.id.usernameTxt);
passwordEdit = findViewById(R.id.userpasswordTxt);
loginBtn = findViewById(R.id.btnLogin);
+ registerTV = findViewById(R.id.registerTV);
- loginBtn.setOnClickListener(v -> {
- String username = usernameEdit.getText().toString().trim();
- String password = passwordEdit.getText().toString().trim();
+ loginBtn.setOnClickListener(v -> login());
+ }
- if (username.isEmpty() || password.isEmpty()) {
- Toast.makeText(LoginActivity.this, "All fields are required", Toast.LENGTH_SHORT).show();
- return;
+ private void login() {
+ String username = usernameEdit.getText().toString().trim();
+ String password = passwordEdit.getText().toString().trim();
+
+ if (username.isEmpty() || password.isEmpty()) {
+ Toast.makeText(this, "All fields are required", Toast.LENGTH_SHORT).show();
+ return;
+ }
+
+ ApiService apiService = ApiClient.getClient().create(ApiService.class);
+ LoginRequest request = new LoginRequest(username, password);
+
+ apiService.login(request).enqueue(new Callback() {
+ @Override
+ public void onResponse(Call call, Response response) {
+ if (response.isSuccessful() && response.body() != null) {
+
+ // 🔑 STORE RAW TOKEN ONLY
+ getSharedPreferences("MyAppPrefs", MODE_PRIVATE)
+ .edit()
+ .putString("authToken", response.body().getToken())
+ .putBoolean("isLoggedIn", true)
+ .apply();
+
+ Toast.makeText(LoginActivity.this, "Login successful", Toast.LENGTH_SHORT).show();
+
+ startActivity(new Intent(LoginActivity.this, MainActivity.class));
+ finish();
+ } else {
+ Toast.makeText(LoginActivity.this, "Login failed", Toast.LENGTH_SHORT).show();
+ }
}
- ApiService apiService = ApiClient.getClient().create(ApiService.class);
- LoginRequest request = new LoginRequest(username, password);
-
- // 🔹 Login API call
- apiService.login(request).enqueue(new Callback() {
- @Override
- public void onResponse(Call call, Response response) {
- if (response.isSuccessful() && response.body() != null) {
- String token = "Token " + response.body().getToken();
-
- // 🔹 Save token & login state in SharedPreferences
- getSharedPreferences("MyAppPrefs", MODE_PRIVATE)
- .edit()
- .putString("authToken", token)
- .putBoolean("isLoggedIn", true)
- .apply();
-
- Toast.makeText(LoginActivity.this, "Login successful", Toast.LENGTH_SHORT).show();
-
- // 🔹 Verify token with /api/auth/me/
- apiService.getMe(token).enqueue(new Callback() {
- @Override
- public void onResponse(Call call, Response response) {
- if (response.isSuccessful() && response.body() != null) {
- Toast.makeText(LoginActivity.this,
- "Welcome " + response.body().getUsername(),
- Toast.LENGTH_SHORT).show();
-
- // Go to MainActivity
- startActivity(new Intent(LoginActivity.this, MainActivity.class));
- finish();
- } else {
- Toast.makeText(LoginActivity.this,
- "Failed to verify user",
- Toast.LENGTH_SHORT).show();
- }
- }
-
- @Override
- public void onFailure(Call call, Throwable t) {
- Toast.makeText(LoginActivity.this,
- "Verification error: " + t.getMessage(),
- Toast.LENGTH_SHORT).show();
- }
- });
-
- } else {
- Toast.makeText(LoginActivity.this, "Login failed", Toast.LENGTH_SHORT).show();
- }
- }
-
- @Override
- public void onFailure(Call call, Throwable t) {
- Toast.makeText(LoginActivity.this, "Server error: " + t.getMessage(), Toast.LENGTH_SHORT).show();
- }
- });
+ @Override
+ public void onFailure(Call call, Throwable t) {
+ Toast.makeText(LoginActivity.this, "Server error: " + t.getMessage(), Toast.LENGTH_SHORT).show();
+ }
});
}
}
diff --git a/app/src/main/java/com/example/gallery/MainActivity.java b/app/src/main/java/com/example/gallery/MainActivity.java
index 3611ac7..63610ae 100644
--- a/app/src/main/java/com/example/gallery/MainActivity.java
+++ b/app/src/main/java/com/example/gallery/MainActivity.java
@@ -4,62 +4,135 @@ import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
+import android.widget.Toast;
-import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.example.gallery.adapters.PostsAdapter;
+import com.example.gallery.api.ApiClient;
+import com.example.gallery.api.ApiService;
+import com.example.gallery.models.Publication;
+import com.example.gallery.models.PublicationListResponse;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import retrofit2.Call;
+import retrofit2.Callback;
+import retrofit2.Response;
public class MainActivity extends AppCompatActivity {
- Button loginBtn, registerBtn, logoutBtn;
+ private Button loginBtn, registerBtn, logoutBtn, newPostBtn;
+ private RecyclerView recyclerView;
+ private PostsAdapter postsAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- EdgeToEdge.enable(this);
setContentView(R.layout.activity_main);
+ // Initialize all views BEFORE using them
loginBtn = findViewById(R.id.Loginbtn);
registerBtn = findViewById(R.id.Registerbtn);
logoutBtn = findViewById(R.id.btnLogout);
+ newPostBtn = findViewById(R.id.newPostBtn);
+ recyclerView = findViewById(R.id.postsRecyclerView);
- // Button listeners
- loginBtn.setOnClickListener(v -> {
- Intent intent = new Intent(MainActivity.this, LoginActivity.class);
- startActivity(intent);
- });
+ // RecyclerView setup
+ recyclerView.setLayoutManager(new LinearLayoutManager(this));
+ postsAdapter = new PostsAdapter(new ArrayList<>());
+ recyclerView.setAdapter(postsAdapter);
- registerBtn.setOnClickListener(v -> {
- Intent intent = new Intent(MainActivity.this, RegisterActivity.class);
- startActivity(intent);
- });
+ setupButtons();
+ updateAuthUI();
+ loadPublications();
+ }
- // Check login state from SharedPreferences
+ private void setupButtons() {
+ if (loginBtn != null) {
+ loginBtn.setOnClickListener(v ->
+ startActivity(new Intent(MainActivity.this, LoginActivity.class))
+ );
+ }
+
+ if (registerBtn != null) {
+ registerBtn.setOnClickListener(v ->
+ startActivity(new Intent(MainActivity.this, RegisterActivity.class))
+ );
+ }
+
+ if (logoutBtn != null) {
+ logoutBtn.setOnClickListener(v -> {
+ getSharedPreferences("MyAppPrefs", MODE_PRIVATE).edit().clear().apply();
+ updateAuthUI();
+ Toast.makeText(MainActivity.this, "Logged out", Toast.LENGTH_SHORT).show();
+ });
+ }
+
+ if (newPostBtn != null) {
+ newPostBtn.setOnClickListener(v ->
+ startActivityForResult(
+ new Intent(MainActivity.this, NewPostActivity.class), 100)
+ );
+ }
+ }
+
+ private void updateAuthUI() {
boolean isLoggedIn = getSharedPreferences("MyAppPrefs", MODE_PRIVATE)
.getBoolean("isLoggedIn", false);
- if (isLoggedIn) {
- // User is logged in → hide login/register, show logout
- loginBtn.setVisibility(View.GONE);
- registerBtn.setVisibility(View.GONE);
- logoutBtn.setVisibility(View.VISIBLE);
- } else {
- // User not logged in → show login/register, hide logout
- loginBtn.setVisibility(View.VISIBLE);
- registerBtn.setVisibility(View.VISIBLE);
- logoutBtn.setVisibility(View.GONE);
- }
+ if (loginBtn != null) loginBtn.setVisibility(isLoggedIn ? View.GONE : View.VISIBLE);
+ if (registerBtn != null) registerBtn.setVisibility(isLoggedIn ? View.GONE : View.VISIBLE);
+ if (logoutBtn != null) logoutBtn.setVisibility(isLoggedIn ? View.VISIBLE : View.GONE);
+ if (newPostBtn != null) newPostBtn.setVisibility(isLoggedIn ? View.VISIBLE : View.GONE);
+ }
- // Logout button
- logoutBtn.setOnClickListener(v -> {
- // Clear token and login state
- getSharedPreferences("MyAppPrefs", MODE_PRIVATE)
- .edit()
- .remove("authToken") // remove saved token
- .putBoolean("isLoggedIn", false) // set logged out
- .apply();
+ private void loadPublications() {
+ ApiService apiService = ApiClient.getClient().create(ApiService.class);
- // Refresh activity to reflect state change
- recreate();
+ String token = getSharedPreferences("MyAppPrefs", MODE_PRIVATE)
+ .getString("authToken", null);
+ String authHeader = token != null ? "Token " + token : null;
+
+ Call call = apiService.getPublications(authHeader);
+ call.enqueue(new Callback() {
+ @Override
+ public void onResponse(Call call, Response response) {
+ if (response.isSuccessful() && response.body() != null) {
+ List posts = response.body().results;
+ Toast.makeText(MainActivity.this,
+ "Posts loaded: " + posts.size(),
+ Toast.LENGTH_SHORT).show();
+ postsAdapter.updateData(posts);
+ } else {
+ Toast.makeText(MainActivity.this,
+ "Failed to load publications: " + response.code(), Toast.LENGTH_SHORT).show();
+ }
+ }
+
+ @Override
+ public void onFailure(Call call, Throwable t) {
+ Toast.makeText(MainActivity.this,
+ "Failed to load publications: " + t.getMessage(), Toast.LENGTH_SHORT).show();
+ }
});
}
-}
\ No newline at end of file
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+ if (requestCode == 100 && resultCode == RESULT_OK) {
+ loadPublications(); // reload feed after new post
+ }
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ updateAuthUI();
+ loadPublications();
+ }
+}
diff --git a/app/src/main/java/com/example/gallery/NewPostActivity.java b/app/src/main/java/com/example/gallery/NewPostActivity.java
index d7f3cd5..a9fd17d 100644
--- a/app/src/main/java/com/example/gallery/NewPostActivity.java
+++ b/app/src/main/java/com/example/gallery/NewPostActivity.java
@@ -1,4 +1,175 @@
package com.example.gallery;
-public class NewPostActivity {
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.widget.*;
+import androidx.activity.result.ActivityResultLauncher;
+import androidx.activity.result.contract.ActivityResultContracts;
+import androidx.appcompat.app.AlertDialog;
+import androidx.appcompat.app.AppCompatActivity;
+
+import com.example.gallery.api.ApiClient;
+import com.example.gallery.api.ApiService;
+import com.example.gallery.models.FileUtils;
+import com.example.gallery.models.Publication;
+
+import java.io.File;
+
+import okhttp3.MediaType;
+import okhttp3.MultipartBody;
+import okhttp3.RequestBody;
+import retrofit2.Call;
+import retrofit2.Callback;
+import retrofit2.Response;
+
+public class NewPostActivity extends AppCompatActivity {
+
+ private EditText descriptionET;
+ private RadioGroup mediaTypeRG;
+ private Spinner categorySpinner;
+ private Button selectMediaBtn, submitBtn, cancelBtn;
+ private TextView selectedFileTV;
+ private ImageView previewIV;
+
+ private Uri selectedFileUri;
+ private String mediaType = "image";
+ private int selectedCategory = 1; // default
+
+ private final ActivityResultLauncher picker =
+ registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),
+ result -> {
+ if (result.getResultCode() == RESULT_OK && result.getData() != null) {
+ selectedFileUri = result.getData().getData();
+ selectedFileTV.setText(FileUtils.getFileName(this, selectedFileUri));
+
+ if (mediaType.equals("image")) {
+ previewIV.setImageURI(selectedFileUri);
+ previewIV.setVisibility(ImageView.VISIBLE);
+ } else {
+ previewIV.setVisibility(ImageView.GONE);
+ }
+ }
+ });
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_new_post);
+
+ descriptionET = findViewById(R.id.descriptionET);
+ mediaTypeRG = findViewById(R.id.mediaTypeRG);
+ selectMediaBtn = findViewById(R.id.selectMediaBtn);
+ submitBtn = findViewById(R.id.submitBtn);
+ cancelBtn = findViewById(R.id.cancelBtn);
+ selectedFileTV = findViewById(R.id.selectedFileTV);
+ previewIV = findViewById(R.id.previewIV);
+
+ // Spinner for categories
+ categorySpinner = findViewById(R.id.categorySpinner);
+ ArrayAdapter adapter = new ArrayAdapter<>(this,
+ android.R.layout.simple_spinner_item,
+ new String[]{"nature","city","landscape","animals","people"}); // categories from API
+ adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ categorySpinner.setAdapter(adapter);
+ categorySpinner.setSelection(0);
+ categorySpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+ @Override public void onItemSelected(AdapterView> parent, android.view.View view, int position, long id) {
+ selectedCategory = new int[]{1,2,3,4,5}[position];
+ }
+ @Override public void onNothingSelected(AdapterView> parent) {}
+ });
+
+ mediaTypeRG.setOnCheckedChangeListener((g, id) -> mediaType = (id == R.id.photoRB) ? "image" : "video");
+
+ selectMediaBtn.setOnClickListener(v -> {
+ Intent i = new Intent(Intent.ACTION_PICK);
+ i.setType(mediaType.equals("image") ? "image/*" : "video/*");
+ picker.launch(i);
+ });
+
+ submitBtn.setOnClickListener(v -> uploadPost());
+ cancelBtn.setOnClickListener(v -> confirmCancel());
+ }
+
+ @Override
+ public void onBackPressed() { confirmCancel(); }
+
+ private void confirmCancel() {
+ new AlertDialog.Builder(this)
+ .setTitle("Cancel post")
+ .setMessage("Are you sure?")
+ .setPositiveButton("Yes", (d, w) -> super.onBackPressed())
+ .setNegativeButton("No", null)
+ .show();
+ }
+
+ private void uploadPost() {
+ if (selectedFileUri == null || descriptionET.getText().toString().trim().isEmpty()) {
+ Toast.makeText(this, "Select file and enter description", Toast.LENGTH_SHORT).show();
+ return;
+ }
+
+ String rawToken = getSharedPreferences("MyAppPrefs", MODE_PRIVATE)
+ .getString("authToken", null);
+
+ if (rawToken == null) {
+ Toast.makeText(this, "Login required", Toast.LENGTH_SHORT).show();
+ return;
+ }
+
+ String authHeader = "Token " + rawToken;
+
+ try {
+ File file = FileUtils.getFileFromUri(this, selectedFileUri);
+ MediaType mediaTypeFile = MediaType.parse(getContentResolver().getType(selectedFileUri));
+ RequestBody fileBody = RequestBody.create(mediaTypeFile, file);
+
+ MultipartBody.Part filePart = MultipartBody.Part.createFormData(
+ mediaType.equals("image") ? "image" : "video",
+ file.getName(),
+ fileBody
+ );
+
+ RequestBody desc = RequestBody.create(MediaType.parse("text/plain"),
+ descriptionET.getText().toString().trim());
+
+ RequestBody ct = RequestBody.create(MediaType.parse("text/plain"), mediaType);
+ RequestBody status = RequestBody.create(MediaType.parse("text/plain"), "public");
+ RequestBody category = RequestBody.create(MediaType.parse("text/plain"), String.valueOf(selectedCategory));
+
+ ApiService apiService = ApiClient.getClient().create(ApiService.class);
+
+ Call call = apiService.createPublication(
+ authHeader,
+ desc,
+ ct,
+ status,
+ category,
+ filePart
+ );
+
+ call.enqueue(new Callback() {
+ @Override
+ public void onResponse(Call call, Response response) {
+ if (response.isSuccessful() && response.body() != null) {
+ Toast.makeText(NewPostActivity.this, "Post created 🎉", Toast.LENGTH_SHORT).show();
+ setResult(RESULT_OK); // signal MainActivity to refresh
+ finish();
+ } else {
+ Toast.makeText(NewPostActivity.this,
+ "Error " + response.code() + ": check fields", Toast.LENGTH_LONG).show();
+ }
+ }
+
+ @Override
+ public void onFailure(Call call, Throwable t) {
+ Toast.makeText(NewPostActivity.this, t.getMessage(), Toast.LENGTH_LONG).show();
+ }
+ });
+
+ } catch (Exception e) {
+ Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show();
+ }
+ }
}
diff --git a/app/src/main/java/com/example/gallery/adapters/PostsAdapter.java b/app/src/main/java/com/example/gallery/adapters/PostsAdapter.java
index 7662b4d..a3a72ac 100644
--- a/app/src/main/java/com/example/gallery/adapters/PostsAdapter.java
+++ b/app/src/main/java/com/example/gallery/adapters/PostsAdapter.java
@@ -1,4 +1,104 @@
package com.example.gallery.adapters;
-public class PostsAdapter {
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.bumptech.glide.Glide;
+import com.example.gallery.R;
+import com.example.gallery.api.ApiClient;
+import com.example.gallery.models.Publication;
+
+import java.util.List;
+
+public class PostsAdapter extends RecyclerView.Adapter {
+
+ private final List publications;
+
+ public PostsAdapter(List publications) {
+ this.publications = publications;
+ }
+
+ public void updateData(List newData) {
+ publications.clear();
+ publications.addAll(newData);
+ notifyDataSetChanged();
+ }
+
+ @NonNull
+ @Override
+ public PostViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ View view = LayoutInflater.from(parent.getContext())
+ .inflate(R.layout.item_post, parent, false);
+ return new PostViewHolder(view);
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull PostViewHolder holder, int position) {
+ Publication pub = publications.get(position);
+
+ holder.descriptionTV.setText(
+ pub.description != null ? pub.description : ""
+ );
+
+ holder.mediaTypeBadge.setText(
+ pub.content_type != null ? pub.content_type.toUpperCase() : ""
+ );
+
+ String mediaPath = null;
+
+ if ("image".equals(pub.content_type)) {
+ mediaPath = pub.image;
+ } else if ("video".equals(pub.content_type)) {
+ mediaPath = pub.video;
+ }
+
+ if (mediaPath != null && !mediaPath.isEmpty()) {
+
+ String fullUrl;
+
+ // ✅ CRITICAL FIX: handle both relative & absolute URLs
+ if (mediaPath.startsWith("http")) {
+ fullUrl = mediaPath;
+ } else {
+ fullUrl = ApiClient.BASE_URL + mediaPath;
+ }
+
+ Log.d("POST_IMAGE_URL", fullUrl);
+
+ Glide.with(holder.itemView.getContext())
+ .load(fullUrl)
+ .placeholder(R.drawable.image_placeholder_background)
+ .error(R.drawable.image_placeholder_background)
+ .centerCrop()
+ .into(holder.mediaIV);
+
+ } else {
+ holder.mediaIV.setImageResource(R.drawable.image_placeholder_background);
+ }
+ }
+
+ @Override
+ public int getItemCount() {
+ return publications.size();
+ }
+
+ static class PostViewHolder extends RecyclerView.ViewHolder {
+ TextView descriptionTV;
+ TextView mediaTypeBadge;
+ ImageView mediaIV;
+
+ public PostViewHolder(@NonNull View itemView) {
+ super(itemView);
+ descriptionTV = itemView.findViewById(R.id.postDescription);
+ mediaIV = itemView.findViewById(R.id.postImage);
+ mediaTypeBadge = itemView.findViewById(R.id.mediaTypeBadge);
+ }
+ }
}
diff --git a/app/src/main/java/com/example/gallery/api/ApiClient.java b/app/src/main/java/com/example/gallery/api/ApiClient.java
index a66e98f..772ea2f 100644
--- a/app/src/main/java/com/example/gallery/api/ApiClient.java
+++ b/app/src/main/java/com/example/gallery/api/ApiClient.java
@@ -5,10 +5,12 @@ import retrofit2.converter.gson.GsonConverterFactory;
public class ApiClient {
- private static final String BASE_URL = "https://gallery.steve-dekart.xyz/";
+ // Base URL of your backend
+ public static final String BASE_URL = "https://gallery.steve-dekart.xyz/";
private static Retrofit retrofit;
+ // Returns singleton Retrofit client
public static Retrofit getClient() {
if (retrofit == null) {
retrofit = new Retrofit.Builder()
@@ -18,4 +20,4 @@ public class ApiClient {
}
return retrofit;
}
-}
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/gallery/api/ApiService.java b/app/src/main/java/com/example/gallery/api/ApiService.java
index 64ef21b..e63aaca 100644
--- a/app/src/main/java/com/example/gallery/api/ApiService.java
+++ b/app/src/main/java/com/example/gallery/api/ApiService.java
@@ -3,17 +3,25 @@ package com.example.gallery.api;
import com.example.gallery.UserResponse;
import com.example.gallery.models.LoginRequest;
import com.example.gallery.models.LoginResponse;
+import com.example.gallery.models.Publication;
+import com.example.gallery.models.PublicationListResponse;
import com.example.gallery.models.RegisterRequest;
import com.example.gallery.models.RegisterResponse;
+import okhttp3.MultipartBody;
+import okhttp3.RequestBody;
import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.GET;
import retrofit2.http.Header;
+import retrofit2.http.Multipart;
import retrofit2.http.POST;
+import retrofit2.http.Part;
public interface ApiService {
+ /* ===================== AUTH ===================== */
+
@POST("api/auth/register/")
Call register(@Body RegisterRequest request);
@@ -22,4 +30,22 @@ public interface ApiService {
@GET("api/auth/me/")
Call getMe(@Header("Authorization") String token);
-}
\ No newline at end of file
+
+ /* ================== PUBLICATIONS ================= */
+
+ @GET("api/publications/")
+ Call getPublications(
+ @Header("Authorization") String token
+ );
+
+ @Multipart
+ @POST("api/publications/")
+ Call createPublication(
+ @Header("Authorization") String authHeader,
+ @Part("description") RequestBody description,
+ @Part("content_type") RequestBody contentType,
+ @Part("status") RequestBody status,
+ @Part("category") RequestBody category,
+ @Part MultipartBody.Part file
+ );
+}
diff --git a/app/src/main/java/com/example/gallery/models/FileUtils.java b/app/src/main/java/com/example/gallery/models/FileUtils.java
index 6b3b203..24c7fcd 100644
--- a/app/src/main/java/com/example/gallery/models/FileUtils.java
+++ b/app/src/main/java/com/example/gallery/models/FileUtils.java
@@ -1,4 +1,48 @@
package com.example.gallery.models;
+import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
+import android.provider.OpenableColumns;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+
public class FileUtils {
-}
+
+ public static File getFileFromUri(Context context, Uri uri) throws Exception {
+ String fileName = getFileName(context, uri);
+ File tempFile = new File(context.getCacheDir(), fileName);
+ tempFile.createNewFile();
+
+ try (InputStream inputStream = context.getContentResolver().openInputStream(uri);
+ FileOutputStream outputStream = new FileOutputStream(tempFile)) {
+
+ byte[] buf = new byte[1024];
+ int len;
+ while ((len = inputStream.read(buf)) > 0) {
+ outputStream.write(buf, 0, len);
+ }
+ }
+ return tempFile;
+ }
+
+ public static String getFileName(Context context, Uri uri) {
+ String result = null;
+ if ("content".equals(uri.getScheme())) {
+ 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 >= 0) {
+ result = cursor.getString(nameIndex);
+ }
+ }
+ }
+ }
+ if (result == null) {
+ result = uri.getLastPathSegment();
+ }
+ return result;
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/gallery/models/Post.java b/app/src/main/java/com/example/gallery/models/Post.java
index 2b21c98..6789a65 100644
--- a/app/src/main/java/com/example/gallery/models/Post.java
+++ b/app/src/main/java/com/example/gallery/models/Post.java
@@ -1,4 +1,16 @@
package com.example.gallery.models;
public class Post {
+ private int id;
+ private String description;
+ private String media_type;
+ private String file_url;
+ private String username;
+
+ // getters
+ public int getId() { return id; }
+ public String getDescription() { return description; }
+ public String getMedia_type() { return media_type; }
+ public String getFile_url() { return file_url; }
+ public String getUsername() { return username; }
}
diff --git a/app/src/main/java/com/example/gallery/models/PostResponse.java b/app/src/main/java/com/example/gallery/models/PostResponse.java
index bb06647..c1e0654 100644
--- a/app/src/main/java/com/example/gallery/models/PostResponse.java
+++ b/app/src/main/java/com/example/gallery/models/PostResponse.java
@@ -1,4 +1,11 @@
package com.example.gallery.models;
public class PostResponse {
-}
+ private boolean success;
+ private String message;
+ private Post post;
+
+ public boolean isSuccess() { return success; }
+ public String getMessage() { return message; }
+ public Post getPost() { return post; }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/gallery/models/Publication.java b/app/src/main/java/com/example/gallery/models/Publication.java
index 7d851c8..c21537e 100644
--- a/app/src/main/java/com/example/gallery/models/Publication.java
+++ b/app/src/main/java/com/example/gallery/models/Publication.java
@@ -1,4 +1,11 @@
package com.example.gallery.models;
public class Publication {
+ public int pk;
+ public String image;
+ public String video;
+ public String content_type;
+ public String description;
+ public String time_created;
}
+
diff --git a/app/src/main/java/com/example/gallery/models/PublicationListResponse.java b/app/src/main/java/com/example/gallery/models/PublicationListResponse.java
index 984b9ed..ce8b512 100644
--- a/app/src/main/java/com/example/gallery/models/PublicationListResponse.java
+++ b/app/src/main/java/com/example/gallery/models/PublicationListResponse.java
@@ -1,4 +1,11 @@
package com.example.gallery.models;
+import java.util.List;
+
public class PublicationListResponse {
+ public int count;
+ public int page;
+ public int page_size;
+ public int total_pages;
+ public List results;
}
diff --git a/app/src/main/java/com/example/gallery/models/PublicationRequest.java b/app/src/main/java/com/example/gallery/models/PublicationRequest.java
index 96d7e83..868c740 100644
--- a/app/src/main/java/com/example/gallery/models/PublicationRequest.java
+++ b/app/src/main/java/com/example/gallery/models/PublicationRequest.java
@@ -1,4 +1,9 @@
package com.example.gallery.models;
public class PublicationRequest {
+ public String image;
+ public String video;
+ public String content_type;
+ public String description;
+ public int category;
}
diff --git a/app/src/main/res/layout/activity_login.xml b/app/src/main/res/layout/activity_login.xml
index 5f796f2..ff46383 100644
--- a/app/src/main/res/layout/activity_login.xml
+++ b/app/src/main/res/layout/activity_login.xml
@@ -97,14 +97,14 @@
+ android:focusable="true"
+ android:gravity="center"
+ android:text="Don't have an account? Register"
+ android:textColor="#03396c"
+ android:textSize="14sp" />
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index 2ba8472..aeb59f2 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -1,5 +1,6 @@
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+ android:layout_margin="16dp"
+ app:layout_constraintTop_toTopOf="@id/toolbar"
+ app:layout_constraintStart_toStartOf="parent"/>
+
+ android:layout_marginStart="16dp"
+ app:layout_constraintTop_toBottomOf="@id/Loginbtn"
+ app:layout_constraintStart_toStartOf="parent"/>
+
+ android:layout_margin="16dp"
+ android:visibility="gone"
+ app:layout_constraintTop_toTopOf="@id/toolbar"
+ app:layout_constraintStart_toStartOf="parent"/>
-
\ No newline at end of file
+
+
+
diff --git a/app/src/main/res/layout/activity_new_post.xml b/app/src/main/res/layout/activity_new_post.xml
index 56907e5..6579639 100644
--- a/app/src/main/res/layout/activity_new_post.xml
+++ b/app/src/main/res/layout/activity_new_post.xml
@@ -6,125 +6,126 @@
android:layout_height="match_parent"
tools:context=".NewPostActivity">
-
+ android:layout_height="match_parent">
-
-
-
-
-
+ android:orientation="vertical"
+ android:padding="16dp">
-
-
-
-
-
-
-
-
-
+ android:text="Create New Post"
+ android:textSize="24sp"
+ android:layout_marginBottom="24dp"/>
-
+ android:text="Description"
+ android:textSize="16sp"/>
-
+
-
+
-
+
-
+
-
+
+
-
+
-
+
-
+
-
\ No newline at end of file
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/item_post.xml b/app/src/main/res/layout/item_post.xml
index 3676462..14de3be 100644
--- a/app/src/main/res/layout/item_post.xml
+++ b/app/src/main/res/layout/item_post.xml
@@ -85,7 +85,7 @@
android:layout_marginBottom="16dp"
android:contentDescription="Post content"/>
-
+