Fali jos auto-update kada se oceni nesto
This commit is contained in:
parent
cd3b3f6dcc
commit
2cbd885b62
BIN
Screenshot_20260114_182156.png
Normal file
BIN
Screenshot_20260114_182156.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.1 MiB |
@ -1,23 +1,28 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools">
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
<uses-permission android:name="android.permission.INTERNET"/>
|
|
||||||
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
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"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
|
android:networkSecurityConfig="@xml/network_security_config"
|
||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/Theme.Gallery"
|
android:theme="@style/Theme.Gallery"
|
||||||
tools:targetApi="31"
|
tools:targetApi="31">
|
||||||
android:networkSecurityConfig="@xml/network_security_config">
|
<activity
|
||||||
|
android:name=".VideoPlayerActivity"
|
||||||
|
android:exported="false" />
|
||||||
<activity
|
<activity
|
||||||
android:name=".NewPostActivity"
|
android:name=".NewPostActivity"
|
||||||
android:exported="false"
|
android:exported="false"
|
||||||
tools:ignore="Instantiatable"
|
android:windowSoftInputMode="adjustResize|stateHidden"
|
||||||
android:windowSoftInputMode="adjustResize|stateHidden"/>
|
tools:ignore="Instantiatable" />
|
||||||
<activity
|
<activity
|
||||||
android:name=".RegisterActivity"
|
android:name=".RegisterActivity"
|
||||||
android:exported="false" />
|
android:exported="false" />
|
||||||
@ -33,7 +38,6 @@
|
|||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
@ -20,7 +20,8 @@ import retrofit2.Response;
|
|||||||
|
|
||||||
public class LoginActivity extends AppCompatActivity {
|
public class LoginActivity extends AppCompatActivity {
|
||||||
|
|
||||||
private EditText usernameEdit, passwordEdit;
|
private EditText usernameEdit;
|
||||||
|
private EditText passwordEdit;
|
||||||
private Button loginBtn;
|
private Button loginBtn;
|
||||||
private TextView registerTV;
|
private TextView registerTV;
|
||||||
|
|
||||||
@ -29,12 +30,19 @@ public class LoginActivity extends AppCompatActivity {
|
|||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setContentView(R.layout.activity_login);
|
setContentView(R.layout.activity_login);
|
||||||
|
|
||||||
|
// Views
|
||||||
usernameEdit = findViewById(R.id.usernameTxt);
|
usernameEdit = findViewById(R.id.usernameTxt);
|
||||||
passwordEdit = findViewById(R.id.userpasswordTxt);
|
passwordEdit = findViewById(R.id.userpasswordTxt);
|
||||||
loginBtn = findViewById(R.id.btnLogin);
|
loginBtn = findViewById(R.id.btnLogin);
|
||||||
registerTV = findViewById(R.id.registerTV);
|
registerTV = findViewById(R.id.registerTV);
|
||||||
|
|
||||||
|
// Login button
|
||||||
loginBtn.setOnClickListener(v -> login());
|
loginBtn.setOnClickListener(v -> login());
|
||||||
|
|
||||||
|
// Register text → RegisterActivity
|
||||||
|
registerTV.setOnClickListener(v -> {
|
||||||
|
startActivity(new Intent(LoginActivity.this, RegisterActivity.class));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void login() {
|
private void login() {
|
||||||
@ -52,27 +60,33 @@ public class LoginActivity extends AppCompatActivity {
|
|||||||
apiService.login(request).enqueue(new Callback<LoginResponse>() {
|
apiService.login(request).enqueue(new Callback<LoginResponse>() {
|
||||||
@Override
|
@Override
|
||||||
public void onResponse(Call<LoginResponse> call, Response<LoginResponse> response) {
|
public void onResponse(Call<LoginResponse> call, Response<LoginResponse> response) {
|
||||||
|
|
||||||
if (response.isSuccessful() && response.body() != null) {
|
if (response.isSuccessful() && response.body() != null) {
|
||||||
|
|
||||||
// 🔑 STORE RAW TOKEN ONLY
|
// ✅ Save auth state
|
||||||
getSharedPreferences("MyAppPrefs", MODE_PRIVATE)
|
getSharedPreferences("MyAppPrefs", MODE_PRIVATE)
|
||||||
.edit()
|
.edit()
|
||||||
.putString("authToken", response.body().getToken())
|
.putString("authToken", response.body().getToken())
|
||||||
.putBoolean("isLoggedIn", true)
|
.putBoolean("isLoggedIn", true)
|
||||||
.apply();
|
.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));
|
startActivity(new Intent(LoginActivity.this, MainActivity.class));
|
||||||
finish();
|
finish();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(LoginActivity.this, "Login failed", Toast.LENGTH_SHORT).show();
|
Toast.makeText(LoginActivity.this,
|
||||||
|
"Invalid username or password", Toast.LENGTH_SHORT).show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onFailure(Call<LoginResponse> call, Throwable t) {
|
public void onFailure(Call<LoginResponse> 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();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,6 +4,9 @@ import android.content.Intent;
|
|||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
|
import android.widget.ImageButton;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
@ -28,111 +31,173 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
private Button loginBtn, registerBtn, logoutBtn, newPostBtn;
|
private Button loginBtn, registerBtn, logoutBtn, newPostBtn;
|
||||||
private RecyclerView recyclerView;
|
private RecyclerView recyclerView;
|
||||||
private PostsAdapter postsAdapter;
|
private PostsAdapter postsAdapter;
|
||||||
|
private ImageButton burgerMenuBtn;
|
||||||
|
private LinearLayout dropdownMenu;
|
||||||
|
private TextView menuLogout, menuNewPost;
|
||||||
|
private ImageButton filterBtnToolbar;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setContentView(R.layout.activity_main);
|
setContentView(R.layout.activity_main);
|
||||||
|
|
||||||
// Initialize all views BEFORE using them
|
|
||||||
loginBtn = findViewById(R.id.Loginbtn);
|
loginBtn = findViewById(R.id.Loginbtn);
|
||||||
registerBtn = findViewById(R.id.Registerbtn);
|
registerBtn = findViewById(R.id.Registerbtn);
|
||||||
logoutBtn = findViewById(R.id.btnLogout);
|
logoutBtn = findViewById(R.id.btnLogout);
|
||||||
newPostBtn = findViewById(R.id.newPostBtn);
|
newPostBtn = findViewById(R.id.newPostBtn);
|
||||||
recyclerView = findViewById(R.id.postsRecyclerView);
|
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));
|
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);
|
recyclerView.setAdapter(postsAdapter);
|
||||||
|
|
||||||
setupButtons();
|
setupButtons();
|
||||||
|
setupDropdownMenu();
|
||||||
updateAuthUI();
|
updateAuthUI();
|
||||||
loadPublications();
|
loadPublications();
|
||||||
|
setupFilterButton();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupButtons() {
|
private void setupButtons() {
|
||||||
if (loginBtn != null) {
|
loginBtn.setOnClickListener(v ->
|
||||||
loginBtn.setOnClickListener(v ->
|
startActivity(new Intent(this, LoginActivity.class)));
|
||||||
startActivity(new Intent(MainActivity.this, LoginActivity.class))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (registerBtn != null) {
|
registerBtn.setOnClickListener(v ->
|
||||||
registerBtn.setOnClickListener(v ->
|
startActivity(new Intent(this, RegisterActivity.class)));
|
||||||
startActivity(new Intent(MainActivity.this, RegisterActivity.class))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (logoutBtn != null) {
|
logoutBtn.setOnClickListener(v -> {
|
||||||
logoutBtn.setOnClickListener(v -> {
|
getSharedPreferences("MyAppPrefs", MODE_PRIVATE)
|
||||||
getSharedPreferences("MyAppPrefs", MODE_PRIVATE).edit().clear().apply();
|
.edit().clear().apply();
|
||||||
updateAuthUI();
|
updateAuthUI();
|
||||||
Toast.makeText(MainActivity.this, "Logged out", Toast.LENGTH_SHORT).show();
|
Toast.makeText(this, "Logged out", Toast.LENGTH_SHORT).show();
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
if (newPostBtn != null) {
|
newPostBtn.setOnClickListener(v ->
|
||||||
newPostBtn.setOnClickListener(v ->
|
startActivityForResult(
|
||||||
startActivityForResult(
|
new Intent(this, NewPostActivity.class), 100));
|
||||||
new Intent(MainActivity.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() {
|
private void updateAuthUI() {
|
||||||
boolean isLoggedIn = getSharedPreferences("MyAppPrefs", MODE_PRIVATE)
|
boolean isLoggedIn = getSharedPreferences("MyAppPrefs", MODE_PRIVATE)
|
||||||
.getBoolean("isLoggedIn", false);
|
.getBoolean("isLoggedIn", false);
|
||||||
|
|
||||||
if (loginBtn != null) loginBtn.setVisibility(isLoggedIn ? View.GONE : View.VISIBLE);
|
loginBtn.setVisibility(isLoggedIn ? View.GONE : View.VISIBLE);
|
||||||
if (registerBtn != null) registerBtn.setVisibility(isLoggedIn ? View.GONE : View.VISIBLE);
|
registerBtn.setVisibility(isLoggedIn ? View.GONE : View.VISIBLE);
|
||||||
if (logoutBtn != null) logoutBtn.setVisibility(isLoggedIn ? View.VISIBLE : View.GONE);
|
logoutBtn.setVisibility(isLoggedIn ? View.VISIBLE : View.GONE);
|
||||||
if (newPostBtn != null) newPostBtn.setVisibility(isLoggedIn ? View.VISIBLE : View.GONE);
|
newPostBtn.setVisibility(isLoggedIn ? View.VISIBLE : View.GONE);
|
||||||
}
|
}
|
||||||
|
public void loadPublications() {
|
||||||
private void loadPublications() {
|
ApiService api = ApiClient.getClient().create(ApiService.class);
|
||||||
ApiService apiService = ApiClient.getClient().create(ApiService.class);
|
|
||||||
|
|
||||||
String token = getSharedPreferences("MyAppPrefs", MODE_PRIVATE)
|
String token = getSharedPreferences("MyAppPrefs", MODE_PRIVATE)
|
||||||
.getString("authToken", null);
|
.getString("authToken", null);
|
||||||
String authHeader = token != null ? "Token " + token : null;
|
String authHeader = token != null ? "Token " + token : null;
|
||||||
|
api.getPublications(authHeader).enqueue(new Callback<PublicationListResponse>() {
|
||||||
Call<PublicationListResponse> call = apiService.getPublications(authHeader);
|
|
||||||
call.enqueue(new Callback<PublicationListResponse>() {
|
|
||||||
@Override
|
@Override
|
||||||
public void onResponse(Call<PublicationListResponse> call, Response<PublicationListResponse> response) {
|
public void onResponse(Call<PublicationListResponse> call,
|
||||||
|
Response<PublicationListResponse> response) {
|
||||||
if (response.isSuccessful() && response.body() != null) {
|
if (response.isSuccessful() && response.body() != null) {
|
||||||
List<Publication> posts = response.body().results;
|
List<Publication> publications = response.body().results;
|
||||||
Toast.makeText(MainActivity.this,
|
|
||||||
"Posts loaded: " + posts.size(),
|
// Pass the fully populated list to adapter
|
||||||
Toast.LENGTH_SHORT).show();
|
postsAdapter.setPosts(publications);
|
||||||
postsAdapter.updateData(posts);
|
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(MainActivity.this,
|
Toast.makeText(MainActivity.this,
|
||||||
"Failed to load publications: " + response.code(), Toast.LENGTH_SHORT).show();
|
"Failed to load posts",
|
||||||
|
Toast.LENGTH_SHORT).show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onFailure(Call<PublicationListResponse> call, Throwable t) {
|
public void onFailure(Call<PublicationListResponse> call, Throwable t) {
|
||||||
Toast.makeText(MainActivity.this,
|
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
|
@Override
|
||||||
protected void onResume() {
|
protected void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
updateAuthUI();
|
updateAuthUI();
|
||||||
loadPublications();
|
loadPublications();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -5,6 +5,7 @@ import android.os.Bundle;
|
|||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
@ -22,6 +23,7 @@ public class RegisterActivity extends AppCompatActivity {
|
|||||||
|
|
||||||
EditText username, email, ime, prezime, index, password;
|
EditText username, email, ime, prezime, index, password;
|
||||||
Button btnRegister;
|
Button btnRegister;
|
||||||
|
TextView loginTV;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
@ -35,9 +37,14 @@ public class RegisterActivity extends AppCompatActivity {
|
|||||||
index = findViewById(R.id.indexEditText);
|
index = findViewById(R.id.indexEditText);
|
||||||
password = findViewById(R.id.passwordEditText);
|
password = findViewById(R.id.passwordEditText);
|
||||||
btnRegister = findViewById(R.id.btnRegister);
|
btnRegister = findViewById(R.id.btnRegister);
|
||||||
|
loginTV = findViewById(R.id.loginTV);
|
||||||
|
|
||||||
Toast.makeText(this, "RegisterActivity loaded", Toast.LENGTH_SHORT).show();
|
Toast.makeText(this, "RegisterActivity loaded", Toast.LENGTH_SHORT).show();
|
||||||
|
|
||||||
|
loginTV.setOnClickListener(v -> {
|
||||||
|
startActivity(new Intent(RegisterActivity.this, LoginActivity.class));
|
||||||
|
});
|
||||||
|
|
||||||
btnRegister.setOnClickListener(new View.OnClickListener() {
|
btnRegister.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
@ -48,9 +55,7 @@ public class RegisterActivity extends AppCompatActivity {
|
|||||||
String s = index.getText().toString().trim();
|
String s = index.getText().toString().trim();
|
||||||
String p = password.getText().toString().trim();
|
String p = password.getText().toString().trim();
|
||||||
|
|
||||||
// ---------------------------
|
|
||||||
// ✅ FRONTEND VALIDATIONS
|
|
||||||
// ---------------------------
|
|
||||||
if (u.isEmpty() || u.length() > 150) {
|
if (u.isEmpty() || u.length() > 150) {
|
||||||
username.setError("Username must be 1-150 characters");
|
username.setError("Username must be 1-150 characters");
|
||||||
return;
|
return;
|
||||||
|
|||||||
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,104 +1,244 @@
|
|||||||
package com.example.gallery.adapters;
|
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.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.FrameLayout;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
|
import android.widget.RatingBar;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import com.bumptech.glide.Glide;
|
import com.bumptech.glide.Glide;
|
||||||
import com.example.gallery.R;
|
import com.example.gallery.R;
|
||||||
|
import com.example.gallery.VideoPlayerActivity;
|
||||||
import com.example.gallery.api.ApiClient;
|
import com.example.gallery.api.ApiClient;
|
||||||
|
import com.example.gallery.api.ApiService;
|
||||||
import com.example.gallery.models.Publication;
|
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 java.util.List;
|
||||||
|
|
||||||
|
import retrofit2.Call;
|
||||||
|
import retrofit2.Callback;
|
||||||
|
import retrofit2.Response;
|
||||||
|
|
||||||
public class PostsAdapter extends RecyclerView.Adapter<PostsAdapter.PostViewHolder> {
|
public class PostsAdapter extends RecyclerView.Adapter<PostsAdapter.PostViewHolder> {
|
||||||
|
|
||||||
private final List<Publication> publications;
|
private final Context context;
|
||||||
|
private final ApiService apiService;
|
||||||
|
private final boolean isLoggedIn;
|
||||||
|
|
||||||
public PostsAdapter(List<Publication> publications) {
|
private final List<Publication> allPosts = new ArrayList<>();
|
||||||
this.publications = publications;
|
private final List<Publication> 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<Publication> posts, boolean isLoggedIn) {
|
||||||
|
this.context = context;
|
||||||
|
this.isLoggedIn = isLoggedIn;
|
||||||
|
this.apiService = ApiClient.getClient().create(ApiService.class);
|
||||||
|
setPosts(posts);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateData(List<Publication> newData) {
|
public void setPosts(List<Publication> posts) {
|
||||||
publications.clear();
|
allPosts.clear();
|
||||||
publications.addAll(newData);
|
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();
|
notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public PostViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
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);
|
.inflate(R.layout.item_post, parent, false);
|
||||||
return new PostViewHolder(view);
|
return new PostViewHolder(view);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBindViewHolder(@NonNull PostViewHolder holder, int position) {
|
public void onBindViewHolder(@NonNull PostViewHolder holder, int position) {
|
||||||
Publication pub = publications.get(position);
|
|
||||||
|
|
||||||
holder.descriptionTV.setText(
|
Publication post = visiblePosts.get(position);
|
||||||
pub.description != null ? pub.description : ""
|
|
||||||
);
|
|
||||||
|
|
||||||
|
// ---------- 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(
|
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)) {
|
View.OnClickListener play = v -> {
|
||||||
mediaPath = pub.image;
|
Intent i = new Intent(context, VideoPlayerActivity.class);
|
||||||
} else if ("video".equals(pub.content_type)) {
|
i.putExtra("videoUrl", post.video);
|
||||||
mediaPath = pub.video;
|
context.startActivity(i);
|
||||||
}
|
};
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
|
holder.postImage.setOnClickListener(play);
|
||||||
|
holder.videoPlayButton.setOnClickListener(play);
|
||||||
} else {
|
} 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<RatingResponse>() {
|
||||||
|
@Override
|
||||||
|
public void onResponse(@NonNull Call<RatingResponse> call,
|
||||||
|
@NonNull Response<RatingResponse> 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<RatingResponse> call,
|
||||||
|
@NonNull Throwable t) {
|
||||||
|
Toast.makeText(context,
|
||||||
|
"Network error", Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getItemCount() {
|
public int getItemCount() {
|
||||||
return publications.size();
|
return visiblePosts.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
static class PostViewHolder extends RecyclerView.ViewHolder {
|
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);
|
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);
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,6 +5,8 @@ import com.example.gallery.models.LoginRequest;
|
|||||||
import com.example.gallery.models.LoginResponse;
|
import com.example.gallery.models.LoginResponse;
|
||||||
import com.example.gallery.models.Publication;
|
import com.example.gallery.models.Publication;
|
||||||
import com.example.gallery.models.PublicationListResponse;
|
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.RegisterRequest;
|
||||||
import com.example.gallery.models.RegisterResponse;
|
import com.example.gallery.models.RegisterResponse;
|
||||||
|
|
||||||
@ -17,11 +19,11 @@ import retrofit2.http.Header;
|
|||||||
import retrofit2.http.Multipart;
|
import retrofit2.http.Multipart;
|
||||||
import retrofit2.http.POST;
|
import retrofit2.http.POST;
|
||||||
import retrofit2.http.Part;
|
import retrofit2.http.Part;
|
||||||
|
import retrofit2.http.Path;
|
||||||
|
|
||||||
public interface ApiService {
|
public interface ApiService {
|
||||||
|
|
||||||
/* ===================== AUTH ===================== */
|
/* ===================== AUTHENTICATION ===================== */
|
||||||
|
|
||||||
@POST("api/auth/register/")
|
@POST("api/auth/register/")
|
||||||
Call<RegisterResponse> register(@Body RegisterRequest request);
|
Call<RegisterResponse> register(@Body RegisterRequest request);
|
||||||
|
|
||||||
@ -32,12 +34,10 @@ public interface ApiService {
|
|||||||
Call<UserResponse> getMe(@Header("Authorization") String token);
|
Call<UserResponse> getMe(@Header("Authorization") String token);
|
||||||
|
|
||||||
/* ================== PUBLICATIONS ================= */
|
/* ================== PUBLICATIONS ================= */
|
||||||
|
|
||||||
@GET("api/publications/")
|
@GET("api/publications/")
|
||||||
Call<PublicationListResponse> getPublications(
|
Call<PublicationListResponse> getPublications(
|
||||||
@Header("Authorization") String token
|
@Header("Authorization") String token
|
||||||
);
|
);
|
||||||
|
|
||||||
@Multipart
|
@Multipart
|
||||||
@POST("api/publications/")
|
@POST("api/publications/")
|
||||||
Call<Publication> createPublication(
|
Call<Publication> createPublication(
|
||||||
@ -48,4 +48,10 @@ public interface ApiService {
|
|||||||
@Part("category") RequestBody category,
|
@Part("category") RequestBody category,
|
||||||
@Part MultipartBody.Part file
|
@Part MultipartBody.Part file
|
||||||
);
|
);
|
||||||
|
/* ================== RATING ================= */
|
||||||
|
@POST("api/publications/rate/")
|
||||||
|
Call<RatingResponse> ratePublication(
|
||||||
|
@Header("Authorization") String authHeader,
|
||||||
|
@Body RatingRequest request
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,11 +1,20 @@
|
|||||||
package com.example.gallery.models;
|
package com.example.gallery.models;
|
||||||
|
|
||||||
public class Publication {
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
public class Publication implements Serializable {
|
||||||
|
|
||||||
public int pk;
|
public int pk;
|
||||||
|
public String description;
|
||||||
public String image;
|
public String image;
|
||||||
public String video;
|
public String video;
|
||||||
public String content_type;
|
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;
|
public String time_created;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
6
app/src/main/java/com/example/gallery/models/Rating.java
Normal file
6
app/src/main/java/com/example/gallery/models/Rating.java
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
package com.example.gallery.models;
|
||||||
|
|
||||||
|
public class Rating {
|
||||||
|
public float score;
|
||||||
|
public String user;
|
||||||
|
}
|
||||||
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
package com.example.gallery.models;
|
||||||
|
|
||||||
|
public class RatingResponse {
|
||||||
|
public String detail;
|
||||||
|
public Float average_score;
|
||||||
|
public Float user_score;
|
||||||
|
}
|
||||||
10
app/src/main/res/layout/activity_video_player.xml
Normal file
10
app/src/main/res/layout/activity_video_player.xml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<VideoView
|
||||||
|
android:id="@+id/videoView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"/>
|
||||||
|
</FrameLayout>
|
||||||
@ -40,7 +40,6 @@
|
|||||||
android:textSize="16sp"
|
android:textSize="16sp"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
android:textColor="#011f4b"/>
|
android:textColor="#011f4b"/>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<!-- Media Type Badge -->
|
<!-- Media Type Badge -->
|
||||||
@ -57,7 +56,6 @@
|
|||||||
android:paddingEnd="14dp"
|
android:paddingEnd="14dp"
|
||||||
android:paddingTop="6dp"
|
android:paddingTop="6dp"
|
||||||
android:paddingBottom="6dp"/>
|
android:paddingBottom="6dp"/>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<!-- Divider -->
|
<!-- Divider -->
|
||||||
@ -67,6 +65,9 @@
|
|||||||
android:background="#b3cde0"
|
android:background="#b3cde0"
|
||||||
android:layout_marginBottom="16dp"/>
|
android:layout_marginBottom="16dp"/>
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
<!-- Post Content/Image -->
|
<!-- Post Content/Image -->
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/postImage"
|
android:id="@+id/postImage"
|
||||||
@ -76,18 +77,7 @@
|
|||||||
android:background="@drawable/image_placeholder_background"
|
android:background="@drawable/image_placeholder_background"
|
||||||
android:layout_marginBottom="16dp"
|
android:layout_marginBottom="16dp"
|
||||||
android:contentDescription="Post content"/>
|
android:contentDescription="Post content"/>
|
||||||
|
</FrameLayout>
|
||||||
<!-- Post Title
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/postTitle"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="Post Title"
|
|
||||||
android:textSize="18sp"
|
|
||||||
android:textStyle="bold"
|
|
||||||
android:textColor="#011f4b"
|
|
||||||
android:layout_marginBottom="8dp"/>
|
|
||||||
-->
|
|
||||||
<!-- Post Description -->
|
<!-- Post Description -->
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/postDescription"
|
android:id="@+id/postDescription"
|
||||||
@ -107,6 +97,7 @@
|
|||||||
|
|
||||||
<!-- Average Rating Section -->
|
<!-- Average Rating Section -->
|
||||||
<TextView
|
<TextView
|
||||||
|
android:id="@+id/txtAverage"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="Average Rating"
|
android:text="Average Rating"
|
||||||
@ -118,58 +109,73 @@
|
|||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="horizontal"
|
android:layout_marginBottom="24dp"
|
||||||
android:gravity="center_vertical"
|
android:gravity="center_vertical"
|
||||||
android:layout_marginBottom="24dp">
|
android:orientation="horizontal">
|
||||||
|
|
||||||
<RatingBar
|
<RatingBar
|
||||||
android:id="@+id/averageRatingBar"
|
android:id="@+id/averageRatingBar"
|
||||||
style="?android:attr/ratingBarStyleSmall"
|
style="?android:attr/ratingBarStyleSmall"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:numStars="5"
|
android:layout_marginEnd="12dp"
|
||||||
android:rating="4.5"
|
|
||||||
android:isIndicator="true"
|
android:isIndicator="true"
|
||||||
|
android:numStars="5"
|
||||||
|
android:stepSize="0.1"
|
||||||
|
android:rating="0"
|
||||||
android:progressTint="#005b96"
|
android:progressTint="#005b96"
|
||||||
android:scaleX="1.2"
|
android:secondaryProgressTint="#aaccee"/>
|
||||||
android:scaleY="1.2"
|
|
||||||
android:layout_marginEnd="12dp"/>
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/averageRatingText"
|
android:id="@+id/averageRatingText"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="4.5"
|
android:text="0.0"
|
||||||
|
android:textColor="#011f4b"
|
||||||
android:textSize="20sp"
|
android:textSize="20sp"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"/>
|
||||||
android:textColor="#011f4b"/>
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<!-- User Rating Section -->
|
<!-- User Rating Section -->
|
||||||
<TextView
|
<LinearLayout
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="Your Rating"
|
android:orientation="horizontal"
|
||||||
android:textSize="14sp"
|
android:layout_marginBottom="12dp"
|
||||||
android:textStyle="bold"
|
android:gravity="center_vertical">
|
||||||
android:textColor="#03396c"
|
|
||||||
android:layout_marginBottom="12dp"/>
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Your Rating"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:textColor="#03396c"
|
||||||
|
android:layout_marginEnd="8dp"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/yourRating"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="0"
|
||||||
|
android:textColor="#011f4b"
|
||||||
|
android:textSize="20sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:layout_marginStart="8dp"/>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
<RatingBar
|
<RatingBar
|
||||||
android:id="@+id/userRatingBar"
|
android:id="@+id/userRatingBar"
|
||||||
|
style="?android:attr/ratingBarStyleSmall"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:numStars="5"
|
android:numStars="5"
|
||||||
android:stepSize="1"
|
android:stepSize="1"
|
||||||
android:rating="0"
|
android:rating="0"
|
||||||
android:progressTint="#005b96"
|
android:isIndicator="false"
|
||||||
android:scaleX="1.3"
|
|
||||||
android:scaleY="1.3"
|
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
android:transformPivotX="0dp"
|
android:progressTint="#005b96"
|
||||||
android:transformPivotY="0dp"/>
|
android:secondaryProgressTint="#aaccee"/>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user