From 0f38ad180a8cc99fdfda93f47db8b41c5dc36306 Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 1 Nov 2020 18:34:53 +0100 Subject: [PATCH] Allow to edit profile + profile picture --- app/build.gradle | 1 + app/src/acad/res/values/strings.xml | 2 + app/src/full/res/values/strings.xml | 3 +- app/src/main/AndroidManifest.xml | 2 +- .../fedilabtube/MyAccountActivity.java | 116 ++++++++++++++++-- .../fedilabtube/PeertubeUploadActivity.java | 2 +- .../fedilabtube/client/PeertubeService.java | 2 +- .../client/RetrofitPeertubeAPI.java | 42 ++++++- .../fedilabtube/client/entities/UserMe.java | 14 +++ .../client/entities/UserSettings.java | 27 +++- .../layout/activity_my_account_settings.xml | 23 +++- 11 files changed, 207 insertions(+), 27 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 0de01da..62394ec 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -105,6 +105,7 @@ dependencies { implementation ("androidx.navigation:navigation-dynamic-features-fragment:2.3.1") implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0' implementation 'androidx.browser:browser:1.2.0' + implementation 'androidx.documentfile:documentfile:1.0.1' testImplementation 'junit:junit:4.13' androidTestImplementation 'androidx.test.ext:junit:1.1.2' androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' diff --git a/app/src/acad/res/values/strings.xml b/app/src/acad/res/values/strings.xml index 2d20a61..6455633 100644 --- a/app/src/acad/res/values/strings.xml +++ b/app/src/acad/res/values/strings.xml @@ -13,6 +13,8 @@ set_autoplay_next_video_choice set_store_in_history + Modifier la photo de profil + Le compte a été mis à jour ! Enregistrer Lire automatiquement la vidéo suivante diff --git a/app/src/full/res/values/strings.xml b/app/src/full/res/values/strings.xml index c7725d4..d1cfad0 100644 --- a/app/src/full/res/values/strings.xml +++ b/app/src/full/res/values/strings.xml @@ -14,7 +14,7 @@ Save Enable history - + Change profile picture Automatic playback If enabled, videos will be played automatically @@ -87,6 +87,7 @@ Download %1$s + The account has been updated! Privacy Logout diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 8b9db85..606b842 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -18,7 +18,7 @@ new Thread(() -> { - UserSettings userSettings = new UserSettings(); - userSettings.setDisplayName(binding.displayname.getText().toString().trim()); - userSettings.setDescription(binding.description.getText().toString().trim()); - try { - RetrofitPeertubeAPI api = new RetrofitPeertubeAPI(MyAccountActivity.this); - api.updateUser(userSettings); - MainActivity.userMe.getAccount().setDisplayName(binding.displayname.getText().toString().trim()); - MainActivity.userMe.getAccount().setDescription(binding.description.getText().toString().trim()); - } catch (Exception | Error e) { - Toasty.error(MyAccountActivity.this, getString(R.string.toast_error), Toasty.LENGTH_LONG).show(); + Helper.loadGiF(MyAccountActivity.this, MainActivity.userMe.getAccount().getAvatar()!=null?MainActivity.userMe.getAccount().getAvatar().getPath():null, binding.profilePicture); + + binding.selectFile.setOnClickListener(v->{ + if (ContextCompat.checkSelfPermission(MyAccountActivity.this, Manifest.permission.READ_EXTERNAL_STORAGE) != + PackageManager.PERMISSION_GRANTED) { + ActivityCompat.requestPermissions(MyAccountActivity.this, + new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, + MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE); + return; } - }).start()); + + Intent intent = new Intent(Intent.ACTION_GET_CONTENT); + intent.addCategory(Intent.CATEGORY_OPENABLE); + intent.setType("*/*"); + String[] mimetypes = {"image/*"}; + intent.putExtra(Intent.EXTRA_MIME_TYPES, mimetypes); + startActivityForResult(intent, PICK_IMAGE); + }); + + + binding.save.setOnClickListener(v -> { + binding.save.setEnabled(false); + new Thread(() -> { + UserSettings userSettings = new UserSettings(); + if( binding.displayname.getText() != null) { + userSettings.setDisplayName(binding.displayname.getText().toString().trim()); + } + if( binding.description.getText() != null) { + userSettings.setDescription(binding.description.getText().toString().trim()); + } + if( inputData != null ) { + userSettings.setAvatarfile(inputData); + userSettings.setFileName(fileName); + } + try { + RetrofitPeertubeAPI api = new RetrofitPeertubeAPI(MyAccountActivity.this); + UserMe.AvatarResponse avatarResponse = api.updateUser(userSettings); + MainActivity.userMe.getAccount().setDisplayName(binding.displayname.getText().toString().trim()); + MainActivity.userMe.getAccount().setDescription(binding.description.getText().toString().trim()); + if( avatarResponse != null && avatarResponse.getAvatar() != null ) { + MainActivity.userMe.getAccount().setAvatar(avatarResponse.getAvatar()); + } + Handler mainHandler = new Handler(Looper.getMainLooper()); + Runnable myRunnable = () -> { + Toasty.info(MyAccountActivity.this, getString(R.string.account_updated), Toasty.LENGTH_LONG).show(); + binding.save.setEnabled(true); + }; + mainHandler.post(myRunnable); + } catch (Exception | Error e) { + Handler mainHandler = new Handler(Looper.getMainLooper()); + Runnable myRunnable = () -> { + Toasty.error(MyAccountActivity.this, getString(R.string.toast_error), Toasty.LENGTH_LONG).show(); + binding.save.setEnabled(true); + }; + mainHandler.post(myRunnable); + + } + }).start(); + }); } @Override @@ -71,4 +140,27 @@ public class MyAccountActivity extends AppCompatActivity { } return super.onOptionsItemSelected(item); } + + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (requestCode == PICK_IMAGE && resultCode == Activity.RESULT_OK) { + if (data == null || data.getData() == null) { + Toasty.error(MyAccountActivity.this, getString(R.string.toot_select_image_error), Toast.LENGTH_LONG).show(); + return; + } + inputData = data.getData(); + DocumentFile documentFile = DocumentFile.fromSingleUri(this, inputData); + if (documentFile != null) { + fileName = documentFile.getName(); + } + Glide.with(MyAccountActivity.this) + .load(inputData) + .thumbnail(0.1f) + .apply(new RequestOptions().transform(new CenterCrop(), new RoundedCorners(10))) + .into(binding.profilePicture); + + } + } } diff --git a/app/src/main/java/app/fedilab/fedilabtube/PeertubeUploadActivity.java b/app/src/main/java/app/fedilab/fedilabtube/PeertubeUploadActivity.java index 4847e3f..5b98d33 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/PeertubeUploadActivity.java +++ b/app/src/main/java/app/fedilab/fedilabtube/PeertubeUploadActivity.java @@ -67,7 +67,7 @@ public class PeertubeUploadActivity extends AppCompatActivity { private final int PICK_IVDEO = 52378; - private final int MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE = 724; + public static final int MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE = 724; private Button set_upload_file, set_upload_submit; private Spinner set_upload_privacy, set_upload_channel; private TextView set_upload_file_name; diff --git a/app/src/main/java/app/fedilab/fedilabtube/client/PeertubeService.java b/app/src/main/java/app/fedilab/fedilabtube/client/PeertubeService.java index 4e56910..54ecd91 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/client/PeertubeService.java +++ b/app/src/main/java/app/fedilab/fedilabtube/client/PeertubeService.java @@ -138,7 +138,7 @@ public interface PeertubeService { @Multipart @POST("users/me/avatar/pick") - Call updateProfilePicture( + Call updateProfilePicture( @Header("Authorization") String credentials, @Part MultipartBody.Part avatarfile); diff --git a/app/src/main/java/app/fedilab/fedilabtube/client/RetrofitPeertubeAPI.java b/app/src/main/java/app/fedilab/fedilabtube/client/RetrofitPeertubeAPI.java index 4d71155..426bd72 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/client/RetrofitPeertubeAPI.java +++ b/app/src/main/java/app/fedilab/fedilabtube/client/RetrofitPeertubeAPI.java @@ -21,9 +21,12 @@ import android.content.SharedPreferences; import android.database.sqlite.SQLiteDatabase; import android.os.Handler; import android.os.Looper; +import android.webkit.MimeTypeMap; +import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; +import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.net.URL; import java.net.URLDecoder; @@ -451,8 +454,9 @@ public class RetrofitPeertubeAPI { * * @param userSettings UserSettings */ - public void updateUser(UserSettings userSettings) throws IOException, Error { + public UserMe.AvatarResponse updateUser(UserSettings userSettings) throws IOException, Error { APIResponse apiResponse = new APIResponse(); + UserMe.AvatarResponse avatarResponse = null; PeertubeService peertubeService = init(); Call updateUser = peertubeService.updateUser(getToken(), userSettings.isVideosHistoryEnabled(), @@ -473,15 +477,45 @@ public class RetrofitPeertubeAPI { if (response.errorBody() != null) { error.setError(response.errorBody().string()); } else { + error.setError(_context.getString(R.string.toast_error)); } throw error; } if (userSettings.getAvatarfile() != null) { - RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data"), userSettings.getAvatarfile()); - MultipartBody.Part bodyThumbnail = MultipartBody.Part.createFormData("avatarfile", userSettings.getAvatarfile().getName(), requestFile); - Call updateProfilePicture = peertubeService.updateProfilePicture(getToken(), bodyThumbnail); + InputStream inputStream = _context.getContentResolver().openInputStream(userSettings.getAvatarfile()); + ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream(); + int bufferSize = 1024; + byte[] buffer = new byte[bufferSize]; + + int len; + while ((len = inputStream.read(buffer)) != -1) { + byteBuffer.write(buffer, 0, len); + } + byte[] imageBytes = byteBuffer.toByteArray(); + String mime = MimeTypeMap.getFileExtensionFromUrl(userSettings.getAvatarfile().toString()); + if( mime == null || mime.trim().length() == 0) { + mime = "png"; + } + RequestBody requestFile = RequestBody.create(MediaType.parse("image/"+mime), imageBytes); + MultipartBody.Part bodyThumbnail = MultipartBody.Part.createFormData("avatarfile", userSettings.getFileName(), requestFile); + Call updateProfilePicture = peertubeService.updateProfilePicture(getToken(), bodyThumbnail); + Response responseAvatar = updateProfilePicture.execute(); + if (response.isSuccessful()) { + avatarResponse = responseAvatar.body(); + } else { + setError(apiResponse, response.code(), response.errorBody()); + Error error = new Error(); + error.setStatusCode(response.code()); + if (response.errorBody() != null) { + error.setError(response.errorBody().string()); + } else { + error.setError(_context.getString(R.string.toast_error)); + } + throw error; + } } + return avatarResponse; } /** diff --git a/app/src/main/java/app/fedilab/fedilabtube/client/entities/UserMe.java b/app/src/main/java/app/fedilab/fedilabtube/client/entities/UserMe.java index f359fbb..7e2656d 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/client/entities/UserMe.java +++ b/app/src/main/java/app/fedilab/fedilabtube/client/entities/UserMe.java @@ -265,4 +265,18 @@ public class UserMe { public void setAutoPlayVideo(boolean autoPlayVideo) { this.autoPlayVideo = autoPlayVideo; } + + + public static class AvatarResponse { + @SerializedName("avatar") + private Avatar avatar; + + public Avatar getAvatar() { + return avatar; + } + + public void setAvatar(Avatar avatar) { + this.avatar = avatar; + } + } } diff --git a/app/src/main/java/app/fedilab/fedilabtube/client/entities/UserSettings.java b/app/src/main/java/app/fedilab/fedilabtube/client/entities/UserSettings.java index 930569c..fdb5dce 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/client/entities/UserSettings.java +++ b/app/src/main/java/app/fedilab/fedilabtube/client/entities/UserSettings.java @@ -14,8 +14,9 @@ package app.fedilab.fedilabtube.client.entities; * You should have received a copy of the GNU General Public License along with TubeLab; if not, * see . */ +import android.net.Uri; + import java.util.List; -import java.io.File; @SuppressWarnings({"unused", "RedundantSuppression"}) public class UserSettings { @@ -27,7 +28,8 @@ public class UserSettings { private List videoLanguages; private String description; private String displayName; - private File avatarfile; + private Uri avatarfile; + private String fileName; public Boolean isVideosHistoryEnabled() { return videosHistoryEnabled; @@ -77,11 +79,11 @@ public class UserSettings { this.displayName = displayName; } - public File getAvatarfile() { + public Uri getAvatarfile() { return avatarfile; } - public void setAvatarfile(File avatarfile) { + public void setAvatarfile(Uri avatarfile) { this.avatarfile = avatarfile; } @@ -104,4 +106,21 @@ public class UserSettings { public void setAutoPlayNextVideo(Boolean autoPlayNextVideo) { this.autoPlayNextVideo = autoPlayNextVideo; } + + public Boolean getAutoPlayNextVideo() { + return autoPlayNextVideo; + } + + public String getFileName() { + return fileName; + } + + public void setFileName(String fileName) { + if( fileName == null) { + this.fileName = "avatar.png"; + } else { + this.fileName = fileName; + } + } } + diff --git a/app/src/main/res/layout/activity_my_account_settings.xml b/app/src/main/res/layout/activity_my_account_settings.xml index 456a564..c89ae1e 100644 --- a/app/src/main/res/layout/activity_my_account_settings.xml +++ b/app/src/main/res/layout/activity_my_account_settings.xml @@ -5,17 +5,34 @@ android:layout_width="match_parent" android:layout_height="match_parent" > - + +