Compare commits
2 Commits
4746c230e1
...
fc2d998e91
| Author | SHA1 | Date | |
|---|---|---|---|
| fc2d998e91 | |||
| fe404b30e5 |
BIN
ProbnaSlika.png
Normal file
BIN
ProbnaSlika.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.7 MiB |
@ -40,6 +40,8 @@ dependencies {
|
|||||||
|
|
||||||
implementation("com.squareup.retrofit2:retrofit:2.9.0")
|
implementation("com.squareup.retrofit2:retrofit:2.9.0")
|
||||||
implementation("com.squareup.retrofit2:converter-gson: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)
|
testImplementation(libs.junit)
|
||||||
androidTestImplementation(libs.ext.junit)
|
androidTestImplementation(libs.ext.junit)
|
||||||
|
|||||||
@ -16,7 +16,8 @@
|
|||||||
<activity
|
<activity
|
||||||
android:name=".NewPostActivity"
|
android:name=".NewPostActivity"
|
||||||
android:exported="false"
|
android:exported="false"
|
||||||
tools:ignore="Instantiatable" />
|
tools:ignore="Instantiatable"
|
||||||
|
android:windowSoftInputMode="adjustResize|stateHidden"/>
|
||||||
<activity
|
<activity
|
||||||
android:name=".RegisterActivity"
|
android:name=".RegisterActivity"
|
||||||
android:exported="false" />
|
android:exported="false" />
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import android.content.Intent;
|
|||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
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;
|
||||||
@ -12,7 +13,6 @@ import com.example.gallery.api.ApiClient;
|
|||||||
import com.example.gallery.api.ApiService;
|
import com.example.gallery.api.ApiService;
|
||||||
import com.example.gallery.models.LoginRequest;
|
import com.example.gallery.models.LoginRequest;
|
||||||
import com.example.gallery.models.LoginResponse;
|
import com.example.gallery.models.LoginResponse;
|
||||||
import com.example.gallery.UserResponse;
|
|
||||||
|
|
||||||
import retrofit2.Call;
|
import retrofit2.Call;
|
||||||
import retrofit2.Callback;
|
import retrofit2.Callback;
|
||||||
@ -20,84 +20,60 @@ import retrofit2.Response;
|
|||||||
|
|
||||||
public class LoginActivity extends AppCompatActivity {
|
public class LoginActivity extends AppCompatActivity {
|
||||||
|
|
||||||
EditText usernameEdit, passwordEdit;
|
private EditText usernameEdit, passwordEdit;
|
||||||
Button loginBtn;
|
private Button loginBtn;
|
||||||
|
private TextView registerTV;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setContentView(R.layout.activity_login);
|
setContentView(R.layout.activity_login);
|
||||||
|
|
||||||
// Updated ids from your XML
|
|
||||||
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);
|
||||||
|
|
||||||
loginBtn.setOnClickListener(v -> {
|
loginBtn.setOnClickListener(v -> login());
|
||||||
String username = usernameEdit.getText().toString().trim();
|
}
|
||||||
String password = passwordEdit.getText().toString().trim();
|
|
||||||
|
|
||||||
if (username.isEmpty() || password.isEmpty()) {
|
private void login() {
|
||||||
Toast.makeText(LoginActivity.this, "All fields are required", Toast.LENGTH_SHORT).show();
|
String username = usernameEdit.getText().toString().trim();
|
||||||
return;
|
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<LoginResponse>() {
|
||||||
|
@Override
|
||||||
|
public void onResponse(Call<LoginResponse> call, Response<LoginResponse> 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);
|
@Override
|
||||||
LoginRequest request = new LoginRequest(username, password);
|
public void onFailure(Call<LoginResponse> call, Throwable t) {
|
||||||
|
Toast.makeText(LoginActivity.this, "Server error: " + t.getMessage(), Toast.LENGTH_SHORT).show();
|
||||||
// 🔹 Login API call
|
}
|
||||||
apiService.login(request).enqueue(new Callback<LoginResponse>() {
|
|
||||||
@Override
|
|
||||||
public void onResponse(Call<LoginResponse> call, Response<LoginResponse> 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<UserResponse>() {
|
|
||||||
@Override
|
|
||||||
public void onResponse(Call<UserResponse> call, Response<UserResponse> 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<UserResponse> 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<LoginResponse> call, Throwable t) {
|
|
||||||
Toast.makeText(LoginActivity.this, "Server error: " + t.getMessage(), Toast.LENGTH_SHORT).show();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,62 +4,135 @@ 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.Toast;
|
||||||
|
|
||||||
import androidx.activity.EdgeToEdge;
|
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
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 {
|
public class MainActivity extends AppCompatActivity {
|
||||||
|
|
||||||
Button loginBtn, registerBtn, logoutBtn;
|
private Button loginBtn, registerBtn, logoutBtn, newPostBtn;
|
||||||
|
private RecyclerView recyclerView;
|
||||||
|
private PostsAdapter postsAdapter;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
EdgeToEdge.enable(this);
|
|
||||||
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);
|
||||||
|
recyclerView = findViewById(R.id.postsRecyclerView);
|
||||||
|
|
||||||
// Button listeners
|
// RecyclerView setup
|
||||||
loginBtn.setOnClickListener(v -> {
|
recyclerView.setLayoutManager(new LinearLayoutManager(this));
|
||||||
Intent intent = new Intent(MainActivity.this, LoginActivity.class);
|
postsAdapter = new PostsAdapter(new ArrayList<>());
|
||||||
startActivity(intent);
|
recyclerView.setAdapter(postsAdapter);
|
||||||
});
|
|
||||||
|
|
||||||
registerBtn.setOnClickListener(v -> {
|
setupButtons();
|
||||||
Intent intent = new Intent(MainActivity.this, RegisterActivity.class);
|
updateAuthUI();
|
||||||
startActivity(intent);
|
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)
|
boolean isLoggedIn = getSharedPreferences("MyAppPrefs", MODE_PRIVATE)
|
||||||
.getBoolean("isLoggedIn", false);
|
.getBoolean("isLoggedIn", false);
|
||||||
|
|
||||||
if (isLoggedIn) {
|
if (loginBtn != null) loginBtn.setVisibility(isLoggedIn ? View.GONE : View.VISIBLE);
|
||||||
// User is logged in → hide login/register, show logout
|
if (registerBtn != null) registerBtn.setVisibility(isLoggedIn ? View.GONE : View.VISIBLE);
|
||||||
loginBtn.setVisibility(View.GONE);
|
if (logoutBtn != null) logoutBtn.setVisibility(isLoggedIn ? View.VISIBLE : View.GONE);
|
||||||
registerBtn.setVisibility(View.GONE);
|
if (newPostBtn != null) newPostBtn.setVisibility(isLoggedIn ? View.VISIBLE : 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Logout button
|
private void loadPublications() {
|
||||||
logoutBtn.setOnClickListener(v -> {
|
ApiService apiService = ApiClient.getClient().create(ApiService.class);
|
||||||
// Clear token and login state
|
|
||||||
getSharedPreferences("MyAppPrefs", MODE_PRIVATE)
|
|
||||||
.edit()
|
|
||||||
.remove("authToken") // remove saved token
|
|
||||||
.putBoolean("isLoggedIn", false) // set logged out
|
|
||||||
.apply();
|
|
||||||
|
|
||||||
// Refresh activity to reflect state change
|
String token = getSharedPreferences("MyAppPrefs", MODE_PRIVATE)
|
||||||
recreate();
|
.getString("authToken", null);
|
||||||
|
String authHeader = token != null ? "Token " + token : null;
|
||||||
|
|
||||||
|
Call<PublicationListResponse> call = apiService.getPublications(authHeader);
|
||||||
|
call.enqueue(new Callback<PublicationListResponse>() {
|
||||||
|
@Override
|
||||||
|
public void onResponse(Call<PublicationListResponse> call, Response<PublicationListResponse> response) {
|
||||||
|
if (response.isSuccessful() && response.body() != null) {
|
||||||
|
List<Publication> 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<PublicationListResponse> call, Throwable t) {
|
||||||
|
Toast.makeText(MainActivity.this,
|
||||||
|
"Failed to load publications: " + t.getMessage(), 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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -1,4 +1,175 @@
|
|||||||
package com.example.gallery;
|
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<Intent> 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<CharSequence> 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<Publication> call = apiService.createPublication(
|
||||||
|
authHeader,
|
||||||
|
desc,
|
||||||
|
ct,
|
||||||
|
status,
|
||||||
|
category,
|
||||||
|
filePart
|
||||||
|
);
|
||||||
|
|
||||||
|
call.enqueue(new Callback<Publication>() {
|
||||||
|
@Override
|
||||||
|
public void onResponse(Call<Publication> call, Response<Publication> 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<Publication> 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
104
app/src/main/java/com/example/gallery/adapters/PostsAdapter.java
Normal file
104
app/src/main/java/com/example/gallery/adapters/PostsAdapter.java
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
package com.example.gallery.adapters;
|
||||||
|
|
||||||
|
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<PostsAdapter.PostViewHolder> {
|
||||||
|
|
||||||
|
private final List<Publication> publications;
|
||||||
|
|
||||||
|
public PostsAdapter(List<Publication> publications) {
|
||||||
|
this.publications = publications;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateData(List<Publication> 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -5,10 +5,12 @@ import retrofit2.converter.gson.GsonConverterFactory;
|
|||||||
|
|
||||||
public class ApiClient {
|
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;
|
private static Retrofit retrofit;
|
||||||
|
|
||||||
|
// Returns singleton Retrofit client
|
||||||
public static Retrofit getClient() {
|
public static Retrofit getClient() {
|
||||||
if (retrofit == null) {
|
if (retrofit == null) {
|
||||||
retrofit = new Retrofit.Builder()
|
retrofit = new Retrofit.Builder()
|
||||||
|
|||||||
@ -3,17 +3,25 @@ package com.example.gallery.api;
|
|||||||
import com.example.gallery.UserResponse;
|
import com.example.gallery.UserResponse;
|
||||||
import com.example.gallery.models.LoginRequest;
|
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.PublicationListResponse;
|
||||||
import com.example.gallery.models.RegisterRequest;
|
import com.example.gallery.models.RegisterRequest;
|
||||||
import com.example.gallery.models.RegisterResponse;
|
import com.example.gallery.models.RegisterResponse;
|
||||||
|
|
||||||
|
import okhttp3.MultipartBody;
|
||||||
|
import okhttp3.RequestBody;
|
||||||
import retrofit2.Call;
|
import retrofit2.Call;
|
||||||
import retrofit2.http.Body;
|
import retrofit2.http.Body;
|
||||||
import retrofit2.http.GET;
|
import retrofit2.http.GET;
|
||||||
import retrofit2.http.Header;
|
import retrofit2.http.Header;
|
||||||
|
import retrofit2.http.Multipart;
|
||||||
import retrofit2.http.POST;
|
import retrofit2.http.POST;
|
||||||
|
import retrofit2.http.Part;
|
||||||
|
|
||||||
public interface ApiService {
|
public interface ApiService {
|
||||||
|
|
||||||
|
/* ===================== AUTH ===================== */
|
||||||
|
|
||||||
@POST("api/auth/register/")
|
@POST("api/auth/register/")
|
||||||
Call<RegisterResponse> register(@Body RegisterRequest request);
|
Call<RegisterResponse> register(@Body RegisterRequest request);
|
||||||
|
|
||||||
@ -22,4 +30,22 @@ public interface ApiService {
|
|||||||
|
|
||||||
@GET("api/auth/me/")
|
@GET("api/auth/me/")
|
||||||
Call<UserResponse> getMe(@Header("Authorization") String token);
|
Call<UserResponse> getMe(@Header("Authorization") String token);
|
||||||
|
|
||||||
|
/* ================== PUBLICATIONS ================= */
|
||||||
|
|
||||||
|
@GET("api/publications/")
|
||||||
|
Call<PublicationListResponse> getPublications(
|
||||||
|
@Header("Authorization") String token
|
||||||
|
);
|
||||||
|
|
||||||
|
@Multipart
|
||||||
|
@POST("api/publications/")
|
||||||
|
Call<Publication> 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
|
||||||
|
);
|
||||||
}
|
}
|
||||||
48
app/src/main/java/com/example/gallery/models/FileUtils.java
Normal file
48
app/src/main/java/com/example/gallery/models/FileUtils.java
Normal file
@ -0,0 +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;
|
||||||
|
}
|
||||||
|
}
|
||||||
16
app/src/main/java/com/example/gallery/models/Post.java
Normal file
16
app/src/main/java/com/example/gallery/models/Post.java
Normal file
@ -0,0 +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; }
|
||||||
|
}
|
||||||
@ -0,0 +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; }
|
||||||
|
}
|
||||||
@ -0,0 +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;
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +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<Publication> results;
|
||||||
|
}
|
||||||
@ -0,0 +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;
|
||||||
|
}
|
||||||
4
app/src/main/res/drawable/ic_video_placeholder.xml
Normal file
4
app/src/main/res/drawable/ic_video_placeholder.xml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
</selector>
|
||||||
@ -97,14 +97,14 @@
|
|||||||
<!-- Register Text -->
|
<!-- Register Text -->
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/registerTV"
|
android:id="@+id/registerTV"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="281dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="51dp"
|
||||||
android:text="Don't have an account? Register"
|
|
||||||
android:textSize="14sp"
|
|
||||||
android:textColor="#03396c"
|
|
||||||
android:gravity="center"
|
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
android:focusable="true"/>
|
android:focusable="true"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="Don't have an account? Register"
|
||||||
|
android:textColor="#03396c"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:id="@+id/main"
|
android:id="@+id/main"
|
||||||
@ -8,116 +9,69 @@
|
|||||||
android:background="@color/bgColor"
|
android:background="@color/bgColor"
|
||||||
tools:context=".MainActivity">
|
tools:context=".MainActivity">
|
||||||
|
|
||||||
<androidx.drawerlayout.widget.DrawerLayout
|
<!-- Toolbar -->
|
||||||
android:id="@+id/drawer_layout"
|
<androidx.appcompat.widget.Toolbar
|
||||||
android:layout_width="match_parent"
|
android:id="@+id/toolbar"
|
||||||
android:layout_height="match_parent">
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="?attr/actionBarSize"
|
||||||
|
android:background="@color/header"
|
||||||
|
app:title="Gallery"
|
||||||
|
app:titleTextColor="#011f4b"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"/>
|
||||||
|
|
||||||
<!-- Main content -->
|
<!-- RecyclerView Feed -->
|
||||||
<LinearLayout
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
android:layout_width="match_parent"
|
android:id="@+id/postsRecyclerView"
|
||||||
android:layout_height="match_parent"
|
android:layout_width="0dp"
|
||||||
android:orientation="vertical">
|
android:layout_height="0dp"
|
||||||
|
android:padding="16dp"
|
||||||
<androidx.appcompat.widget.Toolbar
|
app:layout_constraintTop_toBottomOf="@id/toolbar"
|
||||||
android:id="@+id/toolbar"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
android:layout_width="match_parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
android:layout_height="?attr/actionBarSize"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
android:background="@color/header"
|
android:contentDescription="Enter How Much Cookies You Want"/>
|
||||||
android:elevation="4dp"
|
|
||||||
app:title="My App"
|
|
||||||
app:titleTextColor="#011f4b">
|
|
||||||
|
|
||||||
<!-- Custom Toolbar Content -->
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:gravity="center_vertical">
|
|
||||||
|
|
||||||
<View
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="1dp"
|
|
||||||
android:layout_weight="1"/>
|
|
||||||
|
|
||||||
<!-- Filter Dropdown Spinner -->
|
|
||||||
<Spinner
|
|
||||||
android:id="@+id/filterButton"
|
|
||||||
android:layout_width="120dp"
|
|
||||||
android:layout_height="40dp"
|
|
||||||
android:background="@drawable/button_background"
|
|
||||||
android:paddingStart="16dp"
|
|
||||||
android:paddingEnd="16dp"
|
|
||||||
android:layout_marginEnd="16dp"
|
|
||||||
android:spinnerMode="dropdown"
|
|
||||||
android:popupBackground="#b3cde0"/>
|
|
||||||
|
|
||||||
<!-- App Logo -->
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/appLogo"
|
|
||||||
android:layout_width="40dp"
|
|
||||||
android:layout_height="40dp"
|
|
||||||
android:src="@color/header"
|
|
||||||
android:layout_marginEnd="16dp"
|
|
||||||
android:contentDescription="App Logo"/>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</androidx.appcompat.widget.Toolbar>
|
|
||||||
|
|
||||||
<!-- Feed/Posts RecyclerView -->
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
|
||||||
android:id="@+id/postsRecyclerView"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:padding="16dp"
|
|
||||||
android:clipToPadding="false"/>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<!-- Left sliding menu -->
|
|
||||||
<com.google.android.material.navigation.NavigationView
|
|
||||||
android:id="@+id/nav_view"
|
|
||||||
android:layout_width="280dp"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:layout_gravity="start"
|
|
||||||
android:background="@color/bgColor"
|
|
||||||
app:headerLayout="@layout/nav_header"
|
|
||||||
app:menu="@menu/drawer_menu" />
|
|
||||||
|
|
||||||
</androidx.drawerlayout.widget.DrawerLayout>
|
|
||||||
|
|
||||||
|
<!-- Login Button -->
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/Loginbtn"
|
android:id="@+id/Loginbtn"
|
||||||
android:layout_width="103dp"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="51dp"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="16dp"
|
|
||||||
android:layout_marginTop="16dp"
|
|
||||||
android:text="Log in"
|
android:text="Log in"
|
||||||
android:visibility="gone"
|
android:layout_margin="16dp"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintTop_toTopOf="@id/toolbar"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintStart_toStartOf="parent"/>
|
||||||
|
|
||||||
|
<!-- Register Button -->
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/Registerbtn"
|
android:id="@+id/Registerbtn"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="16dp"
|
|
||||||
android:layout_marginTop="76dp"
|
|
||||||
android:text="Register"
|
android:text="Register"
|
||||||
android:visibility="gone"
|
android:layout_marginStart="16dp"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintTop_toBottomOf="@id/Loginbtn"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintStart_toStartOf="parent"/>
|
||||||
|
|
||||||
|
<!-- Logout Button -->
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/btnLogout"
|
android:id="@+id/btnLogout"
|
||||||
android:layout_width="101dp"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="58dp"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="16dp"
|
|
||||||
android:layout_marginTop="16dp"
|
|
||||||
android:text="Logout"
|
android:text="Logout"
|
||||||
android:visibility="invisible"
|
android:layout_margin="16dp"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
android:visibility="gone"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="@id/toolbar"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"/>
|
||||||
|
|
||||||
|
<!-- New Post Button -->
|
||||||
|
<Button
|
||||||
|
android:id="@+id/newPostBtn"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="New Post"
|
||||||
|
android:layout_margin="16dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"/>
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
@ -6,125 +6,126 @@
|
|||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:context=".NewPostActivity">
|
tools:context=".NewPostActivity">
|
||||||
|
|
||||||
<LinearLayout
|
<ScrollView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent">
|
||||||
android:orientation="vertical"
|
|
||||||
android:padding="16dp">
|
|
||||||
|
|
||||||
<TextView
|
<LinearLayout
|
||||||
android:id="@+id/headerTV"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="Create New Post"
|
|
||||||
android:textSize="24sp"
|
|
||||||
android:layout_marginBottom="24dp"/>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/titleLabelTV"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/title"
|
|
||||||
android:textSize="16sp"/>
|
|
||||||
|
|
||||||
<EditText
|
|
||||||
android:id="@+id/titleET"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:hint="Enter post title"
|
android:orientation="vertical"
|
||||||
android:inputType="text"
|
android:padding="16dp">
|
||||||
android:layout_marginBottom="16dp"/>
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/descriptionLabelTV"
|
android:id="@+id/headerTV"
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="Description"
|
|
||||||
android:textSize="16sp"/>
|
|
||||||
|
|
||||||
<EditText
|
|
||||||
android:id="@+id/descriptionET"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="120dp"
|
|
||||||
android:hint="Enter post description"
|
|
||||||
android:inputType="textMultiLine"
|
|
||||||
android:gravity="top"
|
|
||||||
android:layout_marginBottom="16dp"/>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/mediaTypeLabelTV"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="Media Type"
|
|
||||||
android:textSize="16sp"/>
|
|
||||||
|
|
||||||
<RadioGroup
|
|
||||||
android:id="@+id/mediaTypeRG"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:layout_marginBottom="16dp">
|
|
||||||
|
|
||||||
<RadioButton
|
|
||||||
android:id="@+id/photoRB"
|
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="Photo"
|
android:text="Create New Post"
|
||||||
android:checked="true"/>
|
android:textSize="24sp"
|
||||||
|
android:layout_marginBottom="24dp"/>
|
||||||
|
|
||||||
<RadioButton
|
<TextView
|
||||||
android:id="@+id/videoRB"
|
android:id="@+id/descriptionLabelTV"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="Video"
|
android:text="Description"
|
||||||
android:layout_marginStart="24dp"/>
|
android:textSize="16sp"/>
|
||||||
|
|
||||||
</RadioGroup>
|
<EditText
|
||||||
|
android:id="@+id/descriptionET"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="120dp"
|
||||||
|
android:hint="Enter post description"
|
||||||
|
android:inputType="textMultiLine"
|
||||||
|
android:gravity="top"
|
||||||
|
android:layout_marginBottom="16dp"/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/selectMediaLabelTV"
|
android:id="@+id/mediaTypeLabelTV"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="Select Media"
|
android:text="Media Type"
|
||||||
android:textSize="16sp"/>
|
android:textSize="16sp"/>
|
||||||
|
|
||||||
<Button
|
<RadioGroup
|
||||||
android:id="@+id/selectMediaBtn"
|
android:id="@+id/mediaTypeRG"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="Choose File"
|
android:orientation="horizontal"
|
||||||
android:layout_marginBottom="16dp"/>
|
android:layout_marginBottom="16dp">
|
||||||
|
|
||||||
<TextView
|
<RadioButton
|
||||||
android:id="@+id/selectedFileTV"
|
android:id="@+id/photoRB"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="No file selected"
|
android:text="Photo"
|
||||||
android:textSize="14sp"
|
android:checked="true"/>
|
||||||
android:layout_marginBottom="16dp"/>
|
|
||||||
|
|
||||||
<ImageView
|
<RadioButton
|
||||||
android:id="@+id/previewIV"
|
android:id="@+id/videoRB"
|
||||||
android:layout_width="200dp"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="200dp"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center"
|
android:text="Video"
|
||||||
android:visibility="gone"
|
android:layout_marginStart="24dp"/>
|
||||||
android:scaleType="centerCrop"
|
</RadioGroup>
|
||||||
android:layout_marginBottom="16dp"
|
|
||||||
android:contentDescription="Preview"/>
|
|
||||||
|
|
||||||
<Button
|
<TextView
|
||||||
android:id="@+id/submitBtn"
|
android:id="@+id/categoryLabelTV"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="Post"/>
|
android:text="Category"
|
||||||
|
android:textSize="16sp"/>
|
||||||
|
|
||||||
<Button
|
<Spinner
|
||||||
android:id="@+id/cancelBtn"
|
android:id="@+id/categorySpinner"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="370dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="48dp"
|
||||||
android:text="Cancel"/>
|
android:layout_marginBottom="16dp" />
|
||||||
|
|
||||||
</LinearLayout>
|
<TextView
|
||||||
|
android:id="@+id/selectMediaLabelTV"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Select Media"
|
||||||
|
android:textSize="16sp"/>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/selectMediaBtn"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Choose File"
|
||||||
|
android:layout_marginBottom="16dp"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/selectedFileTV"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="No file selected"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:layout_marginBottom="16dp"/>
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/previewIV"
|
||||||
|
android:layout_width="200dp"
|
||||||
|
android:layout_height="200dp"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:scaleType="centerCrop"
|
||||||
|
android:layout_marginBottom="16dp"
|
||||||
|
android:contentDescription="Preview"/>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/submitBtn"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Post"
|
||||||
|
android:layout_marginBottom="8dp"/>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/cancelBtn"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Cancel"/>
|
||||||
|
</LinearLayout>
|
||||||
|
</ScrollView>
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
@ -85,7 +85,7 @@
|
|||||||
android:layout_marginBottom="16dp"
|
android:layout_marginBottom="16dp"
|
||||||
android:contentDescription="Post content"/>
|
android:contentDescription="Post content"/>
|
||||||
|
|
||||||
<!-- Post Title -->
|
<!-- Post Title
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/postTitle"
|
android:id="@+id/postTitle"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@ -95,7 +95,7 @@
|
|||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
android:textColor="#011f4b"
|
android:textColor="#011f4b"
|
||||||
android:layout_marginBottom="8dp"/>
|
android:layout_marginBottom="8dp"/>
|
||||||
|
-->
|
||||||
<!-- Post Description -->
|
<!-- Post Description -->
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/postDescription"
|
android:id="@+id/postDescription"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user