diff --git a/Screenshot_20260114_182156.png b/Screenshot_20260114_182156.png new file mode 100644 index 0000000..eae64e9 Binary files /dev/null and b/Screenshot_20260114_182156.png differ diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 663a763..4b1e167 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,23 +1,28 @@ - + + + + tools:targetApi="31"> + + android:windowSoftInputMode="adjustResize|stateHidden" + tools:ignore="Instantiatable" /> @@ -33,7 +38,6 @@ - \ No newline at end of file diff --git a/app/src/main/java/com/example/gallery/LoginActivity.java b/app/src/main/java/com/example/gallery/LoginActivity.java index 5c34323..1091410 100644 --- a/app/src/main/java/com/example/gallery/LoginActivity.java +++ b/app/src/main/java/com/example/gallery/LoginActivity.java @@ -20,7 +20,8 @@ import retrofit2.Response; public class LoginActivity extends AppCompatActivity { - private EditText usernameEdit, passwordEdit; + private EditText usernameEdit; + private EditText passwordEdit; private Button loginBtn; private TextView registerTV; @@ -29,12 +30,19 @@ public class LoginActivity extends AppCompatActivity { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); + // Views usernameEdit = findViewById(R.id.usernameTxt); passwordEdit = findViewById(R.id.userpasswordTxt); loginBtn = findViewById(R.id.btnLogin); registerTV = findViewById(R.id.registerTV); + // Login button loginBtn.setOnClickListener(v -> login()); + + // Register text → RegisterActivity + registerTV.setOnClickListener(v -> { + startActivity(new Intent(LoginActivity.this, RegisterActivity.class)); + }); } private void login() { @@ -52,27 +60,33 @@ public class LoginActivity extends AppCompatActivity { apiService.login(request).enqueue(new Callback() { @Override public void onResponse(Call call, Response response) { + if (response.isSuccessful() && response.body() != null) { - // 🔑 STORE RAW TOKEN ONLY + // ✅ Save auth state getSharedPreferences("MyAppPrefs", MODE_PRIVATE) .edit() .putString("authToken", response.body().getToken()) .putBoolean("isLoggedIn", true) .apply(); - Toast.makeText(LoginActivity.this, "Login successful", Toast.LENGTH_SHORT).show(); + 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(); + Toast.makeText(LoginActivity.this, + "Invalid username or password", Toast.LENGTH_SHORT).show(); } } @Override public void onFailure(Call call, Throwable t) { - Toast.makeText(LoginActivity.this, "Server error: " + t.getMessage(), Toast.LENGTH_SHORT).show(); + 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 63610ae..61395e9 100644 --- a/app/src/main/java/com/example/gallery/MainActivity.java +++ b/app/src/main/java/com/example/gallery/MainActivity.java @@ -4,6 +4,9 @@ import android.content.Intent; import android.os.Bundle; import android.view.View; import android.widget.Button; +import android.widget.ImageButton; +import android.widget.LinearLayout; +import android.widget.TextView; import android.widget.Toast; import androidx.appcompat.app.AppCompatActivity; @@ -28,111 +31,173 @@ public class MainActivity extends AppCompatActivity { private Button loginBtn, registerBtn, logoutBtn, newPostBtn; private RecyclerView recyclerView; private PostsAdapter postsAdapter; + private ImageButton burgerMenuBtn; + private LinearLayout dropdownMenu; + private TextView menuLogout, menuNewPost; + private ImageButton filterBtnToolbar; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); 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); + burgerMenuBtn = findViewById(R.id.burgerMenuBtn); + dropdownMenu = findViewById(R.id.dropdownMenu); + menuLogout = findViewById(R.id.menuLogout); + menuNewPost = findViewById(R.id.menuNewPost); + filterBtnToolbar = findViewById(R.id.filterBtnToolbar); - // RecyclerView setup recyclerView.setLayoutManager(new LinearLayoutManager(this)); - postsAdapter = new PostsAdapter(new ArrayList<>()); + + boolean isLoggedIn = getSharedPreferences("MyAppPrefs", MODE_PRIVATE) + .getBoolean("isLoggedIn", false); + + postsAdapter = new PostsAdapter(this, new ArrayList<>(), isLoggedIn); recyclerView.setAdapter(postsAdapter); setupButtons(); + setupDropdownMenu(); updateAuthUI(); loadPublications(); + setupFilterButton(); } private void setupButtons() { - if (loginBtn != null) { - loginBtn.setOnClickListener(v -> - startActivity(new Intent(MainActivity.this, LoginActivity.class)) - ); - } + loginBtn.setOnClickListener(v -> + startActivity(new Intent(this, LoginActivity.class))); - if (registerBtn != null) { - registerBtn.setOnClickListener(v -> - startActivity(new Intent(MainActivity.this, RegisterActivity.class)) - ); - } + registerBtn.setOnClickListener(v -> + startActivity(new Intent(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(); - }); - } + logoutBtn.setOnClickListener(v -> { + getSharedPreferences("MyAppPrefs", MODE_PRIVATE) + .edit().clear().apply(); + updateAuthUI(); + Toast.makeText(this, "Logged out", Toast.LENGTH_SHORT).show(); + }); - if (newPostBtn != null) { - newPostBtn.setOnClickListener(v -> - startActivityForResult( - new Intent(MainActivity.this, NewPostActivity.class), 100) - ); - } + newPostBtn.setOnClickListener(v -> + startActivityForResult( + new Intent(this, NewPostActivity.class), 100)); } + private void setupDropdownMenu() { + burgerMenuBtn.setOnClickListener(v -> + dropdownMenu.setVisibility( + dropdownMenu.getVisibility() == View.VISIBLE + ? View.GONE : View.VISIBLE)); + menuLogout.setOnClickListener(v -> { + getSharedPreferences("MyAppPrefs", MODE_PRIVATE) + .edit().clear().apply(); + updateAuthUI(); + dropdownMenu.setVisibility(View.GONE); + }); + + menuNewPost.setOnClickListener(v -> { + startActivityForResult( + new Intent(this, NewPostActivity.class), 100); + dropdownMenu.setVisibility(View.GONE); + }); + } + //Sortiranje i filtriranje. + private void setupFilterButton() { + + filterBtnToolbar.setOnClickListener(v -> { + + String[] options = { + "Show all posts", + "Only pinned", + "Not pinned", + "Only images", + "Only videos", + "Sort by newest", + "Sort by rating" + }; + new androidx.appcompat.app.AlertDialog.Builder(this) + .setTitle("Filter & Sort") + .setItems(options, (dialog, which) -> { + + switch (which) { + + case 0: //All. + postsAdapter.filterPinned(null); + postsAdapter.filterContentType(null); + break; + + case 1: //Pinned. + postsAdapter.filterPinned(true); + break; + + case 2: //Not pinned. + postsAdapter.filterPinned(false); + break; + + case 3: // images + postsAdapter.filterContentType("image"); + break; + + case 4: // videos + postsAdapter.filterContentType("video"); + break; + + case 5: // newest + postsAdapter.sortBy(PostsAdapter.SortMode.TIME); + break; + + case 6: // rating + postsAdapter.sortBy(PostsAdapter.SortMode.RATING); + break; + } + }) + .show(); + }); + } private void updateAuthUI() { boolean isLoggedIn = getSharedPreferences("MyAppPrefs", MODE_PRIVATE) .getBoolean("isLoggedIn", false); - 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); + loginBtn.setVisibility(isLoggedIn ? View.GONE : View.VISIBLE); + registerBtn.setVisibility(isLoggedIn ? View.GONE : View.VISIBLE); + logoutBtn.setVisibility(isLoggedIn ? View.VISIBLE : View.GONE); + newPostBtn.setVisibility(isLoggedIn ? View.VISIBLE : View.GONE); } - - private void loadPublications() { - ApiService apiService = ApiClient.getClient().create(ApiService.class); - + public void loadPublications() { + ApiService api = ApiClient.getClient().create(ApiService.class); 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() { + api.getPublications(authHeader).enqueue(new Callback() { @Override - public void onResponse(Call call, Response response) { + 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); + List publications = response.body().results; + + // Pass the fully populated list to adapter + postsAdapter.setPosts(publications); } else { Toast.makeText(MainActivity.this, - "Failed to load publications: " + response.code(), Toast.LENGTH_SHORT).show(); + "Failed to load posts", + 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(); + "Network error", + Toast.LENGTH_SHORT).show(); } }); } - - @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(); } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/example/gallery/RegisterActivity.java b/app/src/main/java/com/example/gallery/RegisterActivity.java index 5b8b555..009b21d 100644 --- a/app/src/main/java/com/example/gallery/RegisterActivity.java +++ b/app/src/main/java/com/example/gallery/RegisterActivity.java @@ -5,6 +5,7 @@ import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.EditText; +import android.widget.TextView; import android.widget.Toast; import androidx.appcompat.app.AppCompatActivity; @@ -22,6 +23,7 @@ public class RegisterActivity extends AppCompatActivity { EditText username, email, ime, prezime, index, password; Button btnRegister; + TextView loginTV; @Override protected void onCreate(Bundle savedInstanceState) { @@ -35,9 +37,14 @@ public class RegisterActivity extends AppCompatActivity { index = findViewById(R.id.indexEditText); password = findViewById(R.id.passwordEditText); btnRegister = findViewById(R.id.btnRegister); + loginTV = findViewById(R.id.loginTV); Toast.makeText(this, "RegisterActivity loaded", Toast.LENGTH_SHORT).show(); +loginTV.setOnClickListener(v -> { + startActivity(new Intent(RegisterActivity.this, LoginActivity.class)); + }); + btnRegister.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { @@ -48,9 +55,7 @@ public class RegisterActivity extends AppCompatActivity { String s = index.getText().toString().trim(); String p = password.getText().toString().trim(); - // --------------------------- - // ✅ FRONTEND VALIDATIONS - // --------------------------- + if (u.isEmpty() || u.length() > 150) { username.setError("Username must be 1-150 characters"); return; diff --git a/app/src/main/java/com/example/gallery/VideoPlayerActivity.java b/app/src/main/java/com/example/gallery/VideoPlayerActivity.java new file mode 100644 index 0000000..e00d3a8 --- /dev/null +++ b/app/src/main/java/com/example/gallery/VideoPlayerActivity.java @@ -0,0 +1,32 @@ +package com.example.gallery; + +import android.net.Uri; +import android.os.Bundle; +import android.widget.MediaController; +import android.widget.VideoView; +import androidx.appcompat.app.AppCompatActivity; + +public class VideoPlayerActivity extends AppCompatActivity { + + private VideoView videoView; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_video_player); + + videoView = findViewById(R.id.videoView); + + String videoUrl = getIntent().getStringExtra("videoUrl"); + if (videoUrl != null) { + Uri videoUri = Uri.parse(videoUrl); + videoView.setVideoURI(videoUri); + + MediaController mediaController = new MediaController(this); + mediaController.setAnchorView(videoView); + videoView.setMediaController(mediaController); + + videoView.start(); + } + } +} 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 a3a72ac..92dca03 100644 --- a/app/src/main/java/com/example/gallery/adapters/PostsAdapter.java +++ b/app/src/main/java/com/example/gallery/adapters/PostsAdapter.java @@ -1,104 +1,244 @@ package com.example.gallery.adapters; -import android.util.Log; +import android.content.Context; +import android.content.Intent; +import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.FrameLayout; import android.widget.ImageView; +import android.widget.RatingBar; import android.widget.TextView; +import android.widget.Toast; import androidx.annotation.NonNull; import androidx.recyclerview.widget.RecyclerView; import com.bumptech.glide.Glide; import com.example.gallery.R; +import com.example.gallery.VideoPlayerActivity; import com.example.gallery.api.ApiClient; +import com.example.gallery.api.ApiService; import com.example.gallery.models.Publication; +import com.example.gallery.models.RatingRequest; +import com.example.gallery.models.RatingResponse; +import java.util.ArrayList; +import java.util.Collections; import java.util.List; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; + public class PostsAdapter extends RecyclerView.Adapter { - private final List publications; + private final Context context; + private final ApiService apiService; + private final boolean isLoggedIn; - public PostsAdapter(List publications) { - this.publications = publications; + private final List allPosts = new ArrayList<>(); + private final List visiblePosts = new ArrayList<>(); + + private Boolean pinnedFilter = null; + private String contentTypeFilter = null; + private SortMode sortMode = SortMode.TIME; + + public enum SortMode { TIME, RATING } + + public PostsAdapter(Context context, List posts, boolean isLoggedIn) { + this.context = context; + this.isLoggedIn = isLoggedIn; + this.apiService = ApiClient.getClient().create(ApiService.class); + setPosts(posts); } - public void updateData(List newData) { - publications.clear(); - publications.addAll(newData); + public void setPosts(List posts) { + allPosts.clear(); + if (posts != null) allPosts.addAll(posts); + applyFilters(); + } + + public void filterPinned(Boolean pinned) { + pinnedFilter = pinned; + applyFilters(); + } + + public void filterContentType(String type) { + contentTypeFilter = type; + applyFilters(); + } + + public void sortBy(SortMode mode) { + sortMode = mode; + applyFilters(); + } + + private void applyFilters() { + visiblePosts.clear(); + + for (Publication p : allPosts) { + if (pinnedFilter != null && p.is_pinned != pinnedFilter) continue; + if (contentTypeFilter != null && + !contentTypeFilter.equalsIgnoreCase(p.content_type)) continue; + visiblePosts.add(p); + } + + if (sortMode == SortMode.TIME) { + Collections.sort(visiblePosts, + (a, b) -> b.time_created.compareTo(a.time_created)); + } else { + Collections.sort(visiblePosts, + (a, b) -> Float.compare(b.average_score, a.average_score)); + } + notifyDataSetChanged(); } @NonNull @Override public PostViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - View view = LayoutInflater.from(parent.getContext()) + View view = LayoutInflater.from(context) .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 : "" - ); + Publication post = visiblePosts.get(position); + // ---------- USER SCORE ---------- + int userScore = post.user_score != null ? post.user_score : 0; + holder.userRatingBar.setOnRatingBarChangeListener(null); + holder.userRatingBar.setRating(userScore); + holder.yourRating.setText(String.valueOf(userScore)); + + // ---------- TEXT ---------- + holder.postDescription.setText(post.description == null ? "" : post.description); + holder.postUserName.setText(post.username == null ? "User" : post.username); holder.mediaTypeBadge.setText( - pub.content_type != null ? pub.content_type.toUpperCase() : "" - ); + post.content_type == null ? "MEDIA" : post.content_type.toUpperCase()); - String mediaPath = null; + // ---------- MEDIA ---------- + if ("video".equalsIgnoreCase(post.content_type)) { + Glide.with(context).asBitmap().load(post.video).into(holder.postImage); + holder.videoPlayButton.setVisibility(View.VISIBLE); - 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); + View.OnClickListener play = v -> { + Intent i = new Intent(context, VideoPlayerActivity.class); + i.putExtra("videoUrl", post.video); + context.startActivity(i); + }; + holder.postImage.setOnClickListener(play); + holder.videoPlayButton.setOnClickListener(play); } else { - holder.mediaIV.setImageResource(R.drawable.image_placeholder_background); + holder.videoPlayButton.setVisibility(View.GONE); + Glide.with(context).load(post.image).into(holder.postImage); } + + // ---------- AVERAGE ---------- + holder.txtAverageValue.setText(String.format("%.1f", post.average_score)); + holder.averageRatingBar.setRating(post.average_score); + + if (!isLoggedIn) { + holder.userRatingBar.setIsIndicator(true); + return; + } + + holder.userRatingBar.setIsIndicator(false); + + holder.userRatingBar.setOnRatingBarChangeListener((bar, rating, fromUser) -> { + if (!fromUser) return; + + int score = Math.round(rating); + int adapterPosition = holder.getAdapterPosition(); + if (adapterPosition == RecyclerView.NO_POSITION) return; + + Publication current = visiblePosts.get(adapterPosition); + + String token = context.getSharedPreferences("MyAppPrefs", Context.MODE_PRIVATE) + .getString("authToken", null); + + apiService.ratePublication("Token " + token, + new RatingRequest(current.pk, score)) + .enqueue(new Callback() { + @Override + public void onResponse(@NonNull Call call, + @NonNull Response response) { + + if (!response.isSuccessful() || response.body() == null) return; + + RatingResponse body = response.body(); + + current.user_score = score; + + if (body.average_score != null) { + current.average_score = body.average_score; + } + + for (Publication p : allPosts) { + if (p.pk == current.pk) { + p.user_score = current.user_score; + p.average_score = current.average_score; + break; + } + } + + holder.yourRating.setText(String.valueOf(current.user_score)); + holder.averageRatingBar.setRating(current.average_score); + holder.txtAverageValue.setText( + String.format("%.1f", current.average_score) + ); + + notifyItemChanged(adapterPosition); + } + + @Override + public void onFailure(@NonNull Call call, + @NonNull Throwable t) { + Toast.makeText(context, + "Network error", Toast.LENGTH_SHORT).show(); + } + }); + }); } @Override public int getItemCount() { - return publications.size(); + return visiblePosts.size(); } static class PostViewHolder extends RecyclerView.ViewHolder { - TextView descriptionTV; - TextView mediaTypeBadge; - ImageView mediaIV; - public PostViewHolder(@NonNull View itemView) { + RatingBar averageRatingBar, userRatingBar; + TextView txtAverageValue, yourRating, postDescription, postUserName, mediaTypeBadge; + ImageView postImage, videoPlayButton; + + PostViewHolder(View itemView) { super(itemView); - descriptionTV = itemView.findViewById(R.id.postDescription); - mediaIV = itemView.findViewById(R.id.postImage); + + averageRatingBar = itemView.findViewById(R.id.averageRatingBar); + userRatingBar = itemView.findViewById(R.id.userRatingBar); + txtAverageValue = itemView.findViewById(R.id.averageRatingText); + yourRating = itemView.findViewById(R.id.yourRating); + postDescription = itemView.findViewById(R.id.postDescription); + postUserName = itemView.findViewById(R.id.postUserName); mediaTypeBadge = itemView.findViewById(R.id.mediaTypeBadge); + postImage = itemView.findViewById(R.id.postImage); + + FrameLayout parent = (FrameLayout) postImage.getParent(); + videoPlayButton = new ImageView(itemView.getContext()); + videoPlayButton.setImageResource(R.drawable.ic_launcher_background); + FrameLayout.LayoutParams params = new FrameLayout.LayoutParams( + FrameLayout.LayoutParams.WRAP_CONTENT, + FrameLayout.LayoutParams.WRAP_CONTENT + ); + params.gravity = Gravity.CENTER; + parent.addView(videoPlayButton); + videoPlayButton.setVisibility(View.GONE); } } } 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 e63aaca..b0e34ed 100644 --- a/app/src/main/java/com/example/gallery/api/ApiService.java +++ b/app/src/main/java/com/example/gallery/api/ApiService.java @@ -5,6 +5,8 @@ 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.RatingRequest; +import com.example.gallery.models.RatingResponse; import com.example.gallery.models.RegisterRequest; import com.example.gallery.models.RegisterResponse; @@ -17,11 +19,11 @@ import retrofit2.http.Header; import retrofit2.http.Multipart; import retrofit2.http.POST; import retrofit2.http.Part; +import retrofit2.http.Path; public interface ApiService { - /* ===================== AUTH ===================== */ - + /* ===================== AUTHENTICATION ===================== */ @POST("api/auth/register/") Call register(@Body RegisterRequest request); @@ -32,12 +34,10 @@ public interface ApiService { Call getMe(@Header("Authorization") String token); /* ================== PUBLICATIONS ================= */ - @GET("api/publications/") Call getPublications( @Header("Authorization") String token ); - @Multipart @POST("api/publications/") Call createPublication( @@ -48,4 +48,10 @@ public interface ApiService { @Part("category") RequestBody category, @Part MultipartBody.Part file ); + /* ================== RATING ================= */ + @POST("api/publications/rate/") + Call ratePublication( + @Header("Authorization") String authHeader, + @Body RatingRequest request + ); } 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 c21537e..94f5036 100644 --- a/app/src/main/java/com/example/gallery/models/Publication.java +++ b/app/src/main/java/com/example/gallery/models/Publication.java @@ -1,11 +1,20 @@ package com.example.gallery.models; -public class Publication { +import java.io.Serializable; + +public class Publication implements Serializable { + public int pk; + public String description; public String image; public String video; public String content_type; - public String description; + + public boolean is_pinned; + + public Float average_score; + public Integer user_score; + + public String username; public String time_created; } - diff --git a/app/src/main/java/com/example/gallery/models/Rating.java b/app/src/main/java/com/example/gallery/models/Rating.java new file mode 100644 index 0000000..47e6e0c --- /dev/null +++ b/app/src/main/java/com/example/gallery/models/Rating.java @@ -0,0 +1,6 @@ +package com.example.gallery.models; + +public class Rating { + public float score; + public String user; +} diff --git a/app/src/main/java/com/example/gallery/models/RatingRequest.java b/app/src/main/java/com/example/gallery/models/RatingRequest.java new file mode 100644 index 0000000..3f1fa0e --- /dev/null +++ b/app/src/main/java/com/example/gallery/models/RatingRequest.java @@ -0,0 +1,10 @@ +package com.example.gallery.models; +public class RatingRequest { + public int publication; + public float score; + + public RatingRequest(int publication, float score) { + this.publication = publication; + this.score = score; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/gallery/models/RatingResponse.java b/app/src/main/java/com/example/gallery/models/RatingResponse.java new file mode 100644 index 0000000..48c51e7 --- /dev/null +++ b/app/src/main/java/com/example/gallery/models/RatingResponse.java @@ -0,0 +1,7 @@ +package com.example.gallery.models; + +public class RatingResponse { + public String detail; + public Float average_score; + public Float user_score; +} diff --git a/app/src/main/res/layout/activity_video_player.xml b/app/src/main/res/layout/activity_video_player.xml new file mode 100644 index 0000000..33bd9f2 --- /dev/null +++ b/app/src/main/res/layout/activity_video_player.xml @@ -0,0 +1,10 @@ + + + + + diff --git a/app/src/main/res/layout/item_post.xml b/app/src/main/res/layout/item_post.xml index 653e2c3..2708203 100644 --- a/app/src/main/res/layout/item_post.xml +++ b/app/src/main/res/layout/item_post.xml @@ -40,7 +40,6 @@ android:textSize="16sp" android:textStyle="bold" android:textColor="#011f4b"/> - @@ -57,7 +56,6 @@ android:paddingEnd="14dp" android:paddingTop="6dp" android:paddingBottom="6dp"/> - @@ -67,6 +65,9 @@ android:background="#b3cde0" android:layout_marginBottom="16dp"/> + - - + + android:orientation="horizontal"> + android:secondaryProgressTint="#aaccee"/> - + android:textStyle="bold"/> - + android:orientation="horizontal" + android:layout_marginBottom="12dp" + android:gravity="center_vertical"> + + + + + - + android:progressTint="#005b96" + android:secondaryProgressTint="#aaccee"/> - \ No newline at end of file +