Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support profile picture uploading #216

Merged
merged 5 commits into from
Jun 23, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public Call<Map<String, String>> signin(String username, String password) {
return userServiceAPI.signin(Map.of("username", username, "password", password));
}

public Call<Void> signup(String username, String password, String name) {
return userServiceAPI.signup(Map.of("username", username, "password", password, "name", name));
public Call<Void> signup(String username, String password, String name, String profilePicture) {
return userServiceAPI.signup(Map.of("username", username, "password", password, "name", name, "profilePicture", profilePicture));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,17 @@
import static androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_NO;
import static androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_YES;

import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.util.Base64;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.preference.PreferenceManager;
Expand All @@ -16,6 +22,8 @@
import com.example.makore.api.UserAPI;
import com.example.makore.databinding.ActivitySignUpBinding;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.Map;

import retrofit2.Call;
Expand All @@ -26,6 +34,7 @@ public class SignUpActivity extends AppCompatActivity {

private ActivitySignUpBinding binding;
private SharedPreferences sharedpreferences;
private Uri selectedImage;
private SharedPreferences settingsSharedPreferences;
private Boolean _isNightMode = null;

Expand All @@ -45,15 +54,36 @@ protected void onCreate(Bundle savedInstanceState) {
startActivity(intent);
});
sharedpreferences = getSharedPreferences("user", MODE_PRIVATE);
binding.attachProfilePictureBtn.setOnClickListener(view -> {
Intent pickPhoto = new Intent(Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(pickPhoto, 1);
// Clear error on change
binding.attachProfilePictureBtn.setError(null);
});
settingsSharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
binding.signUpButton.setOnClickListener(view -> {
// Get username, password, confirm password, display name and profile picture from UI
String username = binding.editTextUsername.getText().toString();
String password = binding.editTextPassword.getText().toString();
String confirmPassword = binding.editTextConfirmPassword.getText().toString();
String displayName = binding.editTextDisplayName.getText().toString();

boolean isValid = true;

InputStream imageStream;
Bitmap imageBitMap;
String encodedImage = null;
try {
imageStream = getContentResolver().openInputStream(selectedImage);
imageBitMap = BitmapFactory.decodeStream(imageStream);
encodedImage = encodeImage(imageBitMap);
} catch (Exception e) {
binding.attachProfilePictureBtn.setError("Choose a file first");
isValid = false;
}


// Validate username
if (username.isEmpty()) {
binding.editTextUsername.setError("Username is empty");
Expand Down Expand Up @@ -85,15 +115,17 @@ protected void onCreate(Bundle savedInstanceState) {
// Validate display name
if (displayName.isEmpty()) {
binding.editTextDisplayName.setError("Display name is empty");
isValid = false;
} else if (displayName.length() < 3) {
binding.editTextDisplayName.setError("Display name must be at least 3 characters");
isValid = false;
} else if (!displayName.matches("^[a-zA-Z '-.,]+$")) {
binding.editTextDisplayName.setError("Display name can only contain letters, spaces, hyphens, periods, dots, and commas");
isValid = false;
}

UserAPI userAPI = new UserAPI();
if (isValid) {
Call<Void> signunCall = userAPI.signup(username, password, displayName);
Call<Void> signunCall = userAPI.signup(username, password, displayName, encodedImage);
signunCall.enqueue(new Callback<>() {
@Override
public void onResponse(@NonNull Call<Void> call, @NonNull retrofit2.Response<Void> response) {
Expand Down Expand Up @@ -158,4 +190,24 @@ protected void onStart() {
startActivity(intent);
}
}

@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == Activity.RESULT_OK) {
switch (requestCode) {
case 1:
selectedImage = data.getData();
}
}
}

private String encodeImage(Bitmap bm) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bm.compress(Bitmap.CompressFormat.JPEG, 100, baos);
byte[] b = baos.toByteArray();
String encImage = Base64.encodeToString(b, Base64.DEFAULT);

return encImage;
}
}
8 changes: 8 additions & 0 deletions class-library/User.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ public User(string username, string name, string server, string password) : this
Password = password;
}

public User(string username, string name, string server, string password, String profilePicture) : this(username,
name, server, password)
{
ProfilePicture = profilePicture;
}

// Username must contain only letters, numbers, and hyphens
[Key, RegularExpression(@"^[a-zA-Z0-9-]+$")]
// Username must be at least 3 characters long
Expand Down Expand Up @@ -46,4 +52,6 @@ public User(string username, string name, string server, string password) : this

// Dictionary of User Id's as keys and names as values
public IDictionary<string, string> Names { get; set; }

public String ProfilePicture { get; set; }
}
14 changes: 13 additions & 1 deletion web-api/Controllers/ContactsController.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.IdentityModel.Tokens.Jwt;
using System.Net;
using System.Net.Mime;
using System.Security.Claims;
using System.Text;
using System.Text.Json;
Expand Down Expand Up @@ -179,8 +180,19 @@ public IActionResult SignUp([FromBody] JsonElement body)
return BadRequest();
}

string? profilePicture;
try
{
profilePicture = body.GetProperty("profilePicture").GetString();
}
catch
{
byte[] imageBytes = System.IO.File.ReadAllBytes("photos/profilePicture.png");
profilePicture = Convert.ToBase64String(imageBytes);
}

// Create new user
var newUser = new User(username, name, "localhost", password);
var newUser = new User(username, name, "localhost", password, profilePicture);
_usersService.Add(newUser);

return Created("", null);
Expand Down
Binary file added web-api/photos/profilePicture.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 3 additions & 3 deletions web-api/web-api.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNet.SignalR.Core" Version="2.4.3"/>
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.5"/>
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3"/>
<PackageReference Include="Microsoft.AspNet.SignalR.Core" Version="2.4.3" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.5" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" />
</ItemGroup>

<ItemGroup>
Expand Down