diff --git a/app/lint-baseline.xml b/app/lint-baseline.xml index 0af47faa..15757da0 100644 --- a/app/lint-baseline.xml +++ b/app/lint-baseline.xml @@ -1,17 +1,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - accounts = accountManager.getAllAccountsOrderedByActive(); AccountEntity activeAccount = accountManager.getActiveAccount(); @@ -273,7 +274,7 @@ public abstract class BaseActivity extends AppCompatActivity implements Injectab } } - public void requestPermissions(String[] permissions, PermissionRequester requester) { + public void requestPermissions(@NonNull String[] permissions, @NonNull PermissionRequester requester) { ArrayList permissionsToRequest = new ArrayList<>(); for(String permission: permissions) { if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) { diff --git a/app/src/main/java/com/keylesspalace/tusky/MainActivity.kt b/app/src/main/java/com/keylesspalace/tusky/MainActivity.kt index facf4d06..d32713eb 100644 --- a/app/src/main/java/com/keylesspalace/tusky/MainActivity.kt +++ b/app/src/main/java/com/keylesspalace/tusky/MainActivity.kt @@ -28,6 +28,7 @@ import android.graphics.drawable.Animatable import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.Drawable import android.net.Uri +import android.os.Build import android.os.Bundle import android.text.TextUtils import android.util.Log @@ -180,6 +181,7 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje /** Adapter for the different timeline tabs */ private lateinit var tabAdapter: MainPagerAdapter + @Suppress("DEPRECATION") @SuppressLint("RestrictedApi") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -355,7 +357,10 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje } ) - if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) { + if ( + Build.VERSION.SDK_INT >= 33 && + ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED + ) { ActivityCompat.requestPermissions( this, arrayOf(Manifest.permission.POST_NOTIFICATIONS), @@ -530,7 +535,7 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje override fun placeholder(ctx: Context, tag: String?): Drawable { if (tag == DrawerImageLoader.Tags.PROFILE.name || tag == DrawerImageLoader.Tags.PROFILE_DRAWER_ITEM.name) { - return ctx.getDrawable(R.drawable.avatar_default)!! + return AppCompatResources.getDrawable(ctx, R.drawable.avatar_default)!! } return super.placeholder(ctx, tag) @@ -914,6 +919,7 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje updateShortcut(this, accountManager.activeAccount!!) } + @SuppressLint("CheckResult") private fun loadDrawerAvatar(avatarUrl: String, showPlaceholder: Boolean) { val hideTopToolbar = preferences.getBoolean(PrefKeys.HIDE_TOP_TOOLBAR, false) val animateAvatars = preferences.getBoolean(PrefKeys.ANIMATE_GIF_AVATARS, false) diff --git a/app/src/main/java/com/keylesspalace/tusky/adapter/StatusBaseViewHolder.java b/app/src/main/java/com/keylesspalace/tusky/adapter/StatusBaseViewHolder.java index aa9d3c01..49e70fc7 100644 --- a/app/src/main/java/com/keylesspalace/tusky/adapter/StatusBaseViewHolder.java +++ b/app/src/main/java/com/keylesspalace/tusky/adapter/StatusBaseViewHolder.java @@ -130,7 +130,7 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder { private final Drawable mediaPreviewUnloaded; - protected StatusBaseViewHolder(View itemView) { + protected StatusBaseViewHolder(@NonNull View itemView) { super(itemView); displayName = itemView.findViewById(R.id.status_display_name); username = itemView.findViewById(R.id.status_username); @@ -191,14 +191,14 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder { TouchDelegateHelper.expandTouchSizeToFillRow((ViewGroup) itemView, CollectionsKt.listOfNotNull(replyButton, reblogButton, favouriteButton, bookmarkButton, moreButton)); } - protected void setDisplayName(String name, List customEmojis, StatusDisplayOptions statusDisplayOptions) { + protected void setDisplayName(@NonNull String name, @Nullable List customEmojis, @NonNull StatusDisplayOptions statusDisplayOptions) { CharSequence emojifiedName = CustomEmojiHelper.emojify( name, customEmojis, displayName, statusDisplayOptions.animateEmojis() ); displayName.setText(emojifiedName); } - protected void setUsername(String name) { + protected void setUsername(@Nullable String name) { Context context = username.getContext(); String usernameText = context.getString(R.string.post_username_format, name); username.setText(usernameText); @@ -210,7 +210,7 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder { protected void setSpoilerAndContent(@NonNull StatusViewData.Concrete status, @NonNull StatusDisplayOptions statusDisplayOptions, - final StatusActionListener listener) { + final @NonNull StatusActionListener listener) { Status actionable = status.getActionable(); String spoilerText = actionable.getSpoilerText(); @@ -340,7 +340,7 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder { Collections.singletonList(new CompositeWithOpaqueBackground(avatar))); } - protected void setMetaData(StatusViewData.Concrete statusViewData, StatusDisplayOptions statusDisplayOptions, StatusActionListener listener) { + protected void setMetaData(@NonNull StatusViewData.Concrete statusViewData, @NonNull StatusDisplayOptions statusDisplayOptions, @NonNull StatusActionListener listener) { Status status = statusViewData.getActionable(); Date createdAt = status.getCreatedAt(); @@ -491,9 +491,9 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder { } protected void setMediaPreviews( - final List attachments, + final @NonNull List attachments, boolean sensitive, - final StatusActionListener listener, + final @NonNull StatusActionListener listener, boolean showingContent, boolean useBlurhash ) { @@ -584,8 +584,8 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder { mediaLabels[index].setText(label); } - protected void setMediaLabel(List attachments, boolean sensitive, - final StatusActionListener listener, boolean showingContent) { + protected void setMediaLabel(@NonNull List attachments, boolean sensitive, + final @NonNull StatusActionListener listener, boolean showingContent) { Context context = itemView.getContext(); for (int i = 0; i < mediaLabels.length; i++) { TextView mediaLabel = mediaLabels[i]; @@ -606,7 +606,7 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder { } } - private void setAttachmentClickListener(View view, StatusActionListener listener, + private void setAttachmentClickListener(View view, @NonNull StatusActionListener listener, int index, Attachment attachment, boolean animateTransition) { view.setOnClickListener(v -> { int position = getBindingAdapterPosition(); @@ -630,10 +630,10 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder { sensitiveMediaShow.setVisibility(View.GONE); } - protected void setupButtons(final StatusActionListener listener, - final String accountId, - final String statusContent, - StatusDisplayOptions statusDisplayOptions) { + protected void setupButtons(final @NonNull StatusActionListener listener, + final @NonNull String accountId, + final @Nullable String statusContent, + @NonNull StatusDisplayOptions statusDisplayOptions) { View.OnClickListener profileButtonClickListener = button -> listener.onViewAccount(accountId); avatar.setOnClickListener(profileButtonClickListener); @@ -752,8 +752,8 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder { popup.show(); } - public void setupWithStatus(StatusViewData.Concrete status, final StatusActionListener listener, - StatusDisplayOptions statusDisplayOptions) { + public void setupWithStatus(@NonNull StatusViewData.Concrete status, final @NonNull StatusActionListener listener, + @NonNull StatusDisplayOptions statusDisplayOptions) { this.setupWithStatus(status, listener, statusDisplayOptions, null); } @@ -843,7 +843,7 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder { filteredPlaceholderShowButton.setOnClickListener(view -> listener.clearWarningAction(getBindingAdapterPosition())); } - protected static boolean hasPreviewableAttachment(List attachments) { + protected static boolean hasPreviewableAttachment(@NonNull List attachments) { for (Attachment attachment : attachments) { if (attachment.getType() == Attachment.Type.AUDIO || attachment.getType() == Attachment.Type.UNKNOWN) { return false; @@ -918,7 +918,8 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder { } } - protected static CharSequence getVisibilityDescription(Context context, Status.Visibility visibility) { + @NonNull + protected static CharSequence getVisibilityDescription(@NonNull Context context, @Nullable Status.Visibility visibility) { if (visibility == null) { return ""; @@ -967,7 +968,8 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder { } } - protected CharSequence getFavsText(Context context, int count) { + @NonNull + protected CharSequence getFavsText(@NonNull Context context, int count) { if (count > 0) { String countString = numberFormat.format(count); return HtmlCompat.fromHtml(context.getResources().getQuantityString(R.plurals.favs, count, countString), HtmlCompat.FROM_HTML_MODE_LEGACY); @@ -976,7 +978,8 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder { } } - protected CharSequence getReblogsText(Context context, int count) { + @NonNull + protected CharSequence getReblogsText(@NonNull Context context, int count) { if (count > 0) { String countString = numberFormat.format(count); return HtmlCompat.fromHtml(context.getResources().getQuantityString(R.plurals.reblogs, count, countString), HtmlCompat.FROM_HTML_MODE_LEGACY); @@ -1077,11 +1080,11 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder { } protected void setupCard( - final StatusViewData.Concrete status, + final @NonNull StatusViewData.Concrete status, boolean expanded, - final CardViewMode cardViewMode, - final StatusDisplayOptions statusDisplayOptions, - final StatusActionListener listener + final @NonNull CardViewMode cardViewMode, + final @NonNull StatusDisplayOptions statusDisplayOptions, + final @NonNull StatusActionListener listener ) { if (cardView == null) { return; diff --git a/app/src/main/java/com/keylesspalace/tusky/adapter/StatusDetailedViewHolder.java b/app/src/main/java/com/keylesspalace/tusky/adapter/StatusDetailedViewHolder.java index 76eda110..08145f09 100644 --- a/app/src/main/java/com/keylesspalace/tusky/adapter/StatusDetailedViewHolder.java +++ b/app/src/main/java/com/keylesspalace/tusky/adapter/StatusDetailedViewHolder.java @@ -35,7 +35,7 @@ public class StatusDetailedViewHolder extends StatusBaseViewHolder { private static final DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.SHORT); - public StatusDetailedViewHolder(View view) { + public StatusDetailedViewHolder(@NonNull View view) { super(view); reblogs = view.findViewById(R.id.status_reblogs); favourites = view.findViewById(R.id.status_favourites); @@ -43,7 +43,7 @@ public class StatusDetailedViewHolder extends StatusBaseViewHolder { } @Override - protected void setMetaData(StatusViewData.Concrete statusViewData, StatusDisplayOptions statusDisplayOptions, StatusActionListener listener) { + protected void setMetaData(@NonNull StatusViewData.Concrete statusViewData, @NonNull StatusDisplayOptions statusDisplayOptions, @NonNull StatusActionListener listener) { Status status = statusViewData.getActionable(); diff --git a/app/src/main/java/com/keylesspalace/tusky/adapter/StatusViewHolder.java b/app/src/main/java/com/keylesspalace/tusky/adapter/StatusViewHolder.java index 304cf93a..327f7cfb 100644 --- a/app/src/main/java/com/keylesspalace/tusky/adapter/StatusViewHolder.java +++ b/app/src/main/java/com/keylesspalace/tusky/adapter/StatusViewHolder.java @@ -51,7 +51,7 @@ public class StatusViewHolder extends StatusBaseViewHolder { private final TextView favouritedCountLabel; private final TextView reblogsCountLabel; - public StatusViewHolder(View itemView) { + public StatusViewHolder(@NonNull View itemView) { super(itemView); statusInfo = itemView.findViewById(R.id.status_info); contentCollapseButton = itemView.findViewById(R.id.button_toggle_content); diff --git a/app/src/main/java/com/keylesspalace/tusky/components/announcements/AnnouncementAdapter.kt b/app/src/main/java/com/keylesspalace/tusky/components/announcements/AnnouncementAdapter.kt index 8f30c5e4..65725480 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/announcements/AnnouncementAdapter.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/announcements/AnnouncementAdapter.kt @@ -15,6 +15,7 @@ package com.keylesspalace.tusky.components.announcements +import android.annotation.SuppressLint import android.os.Build import android.text.SpannableStringBuilder import android.view.ContextThemeWrapper @@ -55,6 +56,7 @@ class AnnouncementAdapter( return BindingHolder(binding) } + @SuppressLint("SetTextI18n") override fun onBindViewHolder(holder: BindingHolder, position: Int) { val item = items[position] diff --git a/app/src/main/java/com/keylesspalace/tusky/components/compose/ComposeViewModel.kt b/app/src/main/java/com/keylesspalace/tusky/components/compose/ComposeViewModel.kt index 0919d29d..78cf25f5 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/compose/ComposeViewModel.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/compose/ComposeViewModel.kt @@ -275,7 +275,7 @@ class ComposeViewModel @Inject constructor( val mediaUris: MutableList = mutableListOf() val mediaDescriptions: MutableList = mutableListOf() val mediaFocus: MutableList = mutableListOf() - media.value.forEach { item -> + for (item in media.value) { mediaUris.add(item.uri.toString()) mediaDescriptions.add(item.description) mediaFocus.add(item.focus) diff --git a/app/src/main/java/com/keylesspalace/tusky/components/compose/MediaUploader.kt b/app/src/main/java/com/keylesspalace/tusky/components/compose/MediaUploader.kt index 58c3cf2a..caab8401 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/compose/MediaUploader.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/compose/MediaUploader.kt @@ -15,6 +15,7 @@ package com.keylesspalace.tusky.components.compose +import android.annotation.SuppressLint import android.content.ContentResolver import android.content.Context import android.media.MediaMetadataRetriever @@ -246,6 +247,7 @@ class MediaUploader @Inject constructor( private val contentResolver = context.contentResolver + @SuppressLint("Recycle") // stream is closed in ProgressRequestBody private suspend fun upload(media: QueuedMedia): Flow { return callbackFlow { var mimeType = contentResolver.getType(media.uri) diff --git a/app/src/main/java/com/keylesspalace/tusky/components/notifications/NotificationHelper.java b/app/src/main/java/com/keylesspalace/tusky/components/notifications/NotificationHelper.java index f7292391..15a39780 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/notifications/NotificationHelper.java +++ b/app/src/main/java/com/keylesspalace/tusky/components/notifications/NotificationHelper.java @@ -149,7 +149,7 @@ public class NotificationHelper { * @return the new notification */ @NonNull - public static android.app.Notification make(final Context context, NotificationManager notificationManager, Notification body, AccountEntity account, boolean isFirstOfBatch) { + public static android.app.Notification make(final @NonNull Context context, @NonNull NotificationManager notificationManager, @NonNull Notification body, @NonNull AccountEntity account, boolean isFirstOfBatch) { body = body.rewriteToStatusTypeIfNeeded(account.getAccountId()); String mastodonNotificationId = body.getId(); int accountId = (int) account.getId(); @@ -270,7 +270,7 @@ public class NotificationHelper { * @param notificationManager the system's NotificationManager * @param account the account for which the notification should be shown */ - public static void updateSummaryNotifications(Context context, NotificationManager notificationManager, AccountEntity account) { + public static void updateSummaryNotifications(@NonNull Context context, @NonNull NotificationManager notificationManager, @NonNull AccountEntity account) { // Map from the channel ID to a list of notifications in that channel. Those are the // notifications that will be summarised. Map> channelGroups = new HashMap<>(); @@ -608,7 +608,7 @@ public class NotificationHelper { } - public static void enablePullNotifications(Context context) { + public static void enablePullNotifications(@NonNull Context context) { WorkManager workManager = WorkManager.getInstance(context); workManager.cancelAllWorkByTag(NOTIFICATION_PULL_TAG); @@ -636,7 +636,7 @@ public class NotificationHelper { Log.d(TAG, "enabled notification checks with "+ PeriodicWorkRequest.MIN_PERIODIC_INTERVAL_MILLIS + "ms interval"); } - public static void disablePullNotifications(Context context) { + public static void disablePullNotifications(@NonNull Context context) { WorkManager.getInstance(context).cancelAllWorkByTag(NOTIFICATION_PULL_TAG); Log.d(TAG, "disabled notification checks"); } @@ -652,7 +652,7 @@ public class NotificationHelper { } } - public static boolean filterNotification(NotificationManager notificationManager, AccountEntity account, @NonNull Notification notification) { + public static boolean filterNotification(@NonNull NotificationManager notificationManager, @NonNull AccountEntity account, @NonNull Notification notification) { return filterNotification(notificationManager, account, notification.getType()); } diff --git a/app/src/main/java/com/keylesspalace/tusky/fragment/SFragment.kt b/app/src/main/java/com/keylesspalace/tusky/fragment/SFragment.kt index a9923683..3cb32134 100644 --- a/app/src/main/java/com/keylesspalace/tusky/fragment/SFragment.kt +++ b/app/src/main/java/com/keylesspalace/tusky/fragment/SFragment.kt @@ -474,7 +474,7 @@ abstract class SFragment : Fragment(), Injectable { private fun requestDownloadAllMedia(status: Status) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { val permissions = arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE) - (activity as BaseActivity).requestPermissions(permissions) { _: Array?, grantResults: IntArray -> + (activity as BaseActivity).requestPermissions(permissions) { _, grantResults -> if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) { downloadAllMedia(status) } else { diff --git a/app/src/main/java/com/keylesspalace/tusky/interfaces/AccountActionListener.java b/app/src/main/java/com/keylesspalace/tusky/interfaces/AccountActionListener.kt similarity index 63% rename from app/src/main/java/com/keylesspalace/tusky/interfaces/AccountActionListener.java rename to app/src/main/java/com/keylesspalace/tusky/interfaces/AccountActionListener.kt index c353d0f3..654b50dd 100644 --- a/app/src/main/java/com/keylesspalace/tusky/interfaces/AccountActionListener.java +++ b/app/src/main/java/com/keylesspalace/tusky/interfaces/AccountActionListener.kt @@ -12,12 +12,11 @@ * * You should have received a copy of the GNU General Public License along with Tusky; if not, * see . */ +package com.keylesspalace.tusky.interfaces -package com.keylesspalace.tusky.interfaces; - -public interface AccountActionListener { - void onViewAccount(String id); - void onMute(final boolean mute, final String id, final int position, final boolean notifications); - void onBlock(final boolean block, final String id, final int position); - void onRespondToFollowRequest(final boolean accept, final String id, final int position); +interface AccountActionListener { + fun onViewAccount(id: String) + fun onMute(mute: Boolean, id: String, position: Int, notifications: Boolean) + fun onBlock(block: Boolean, id: String, position: Int) + fun onRespondToFollowRequest(accept: Boolean, id: String, position: Int) } diff --git a/app/src/main/java/com/keylesspalace/tusky/interfaces/PermissionRequester.java b/app/src/main/java/com/keylesspalace/tusky/interfaces/PermissionRequester.java deleted file mode 100644 index ca83e085..00000000 --- a/app/src/main/java/com/keylesspalace/tusky/interfaces/PermissionRequester.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.keylesspalace.tusky.interfaces; - -public interface PermissionRequester { - void onRequestPermissionsResult(String[] permissions, int[] grantResults); -} \ No newline at end of file diff --git a/app/src/main/java/com/keylesspalace/tusky/interfaces/PermissionRequester.kt b/app/src/main/java/com/keylesspalace/tusky/interfaces/PermissionRequester.kt new file mode 100644 index 00000000..d31bd1fe --- /dev/null +++ b/app/src/main/java/com/keylesspalace/tusky/interfaces/PermissionRequester.kt @@ -0,0 +1,5 @@ +package com.keylesspalace.tusky.interfaces + +fun interface PermissionRequester { + fun onRequestPermissionsResult(permissions: Array, grantResults: IntArray) +} diff --git a/app/src/main/java/com/keylesspalace/tusky/network/ProgressRequestBody.java b/app/src/main/java/com/keylesspalace/tusky/network/ProgressRequestBody.java deleted file mode 100644 index f499ed5e..00000000 --- a/app/src/main/java/com/keylesspalace/tusky/network/ProgressRequestBody.java +++ /dev/null @@ -1,76 +0,0 @@ -/* Copyright 2017 Andrew Dawson - * - * This file is a part of Tusky. - * - * This program is free software; you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation; either version 3 of the - * License, or (at your option) any later version. - * - * Tusky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even - * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General - * Public License for more details. - * - * You should have received a copy of the GNU General Public License along with Tusky; if not, - * see . */ - -package com.keylesspalace.tusky.network; - -import androidx.annotation.NonNull; - -import java.io.IOException; -import java.io.InputStream; - -import okhttp3.MediaType; -import okhttp3.RequestBody; -import okio.BufferedSink; - -public final class ProgressRequestBody extends RequestBody { - private final InputStream content; - private final long contentLength; - private final UploadCallback uploadListener; - private final MediaType mediaType; - - private static final int DEFAULT_BUFFER_SIZE = 2048; - - public interface UploadCallback { - void onProgressUpdate(int percentage); - } - - public ProgressRequestBody(final InputStream content, long contentLength, final MediaType mediaType, final UploadCallback listener) { - this.content = content; - this.contentLength = contentLength; - this.mediaType = mediaType; - this.uploadListener = listener; - } - - @Override - public MediaType contentType() { - return mediaType; - } - - @Override - public long contentLength() { - return contentLength; - } - - @Override - public void writeTo(@NonNull BufferedSink sink) throws IOException { - - byte[] buffer = new byte[DEFAULT_BUFFER_SIZE]; - long uploaded = 0; - - try { - int read; - while ((read = content.read(buffer)) != -1) { - uploadListener.onProgressUpdate((int)(100 * uploaded / contentLength)); - - uploaded += read; - sink.write(buffer, 0, read); - } - - uploadListener.onProgressUpdate((int)(100 * uploaded / contentLength)); - } finally { - content.close(); - } - } -} diff --git a/app/src/main/java/com/keylesspalace/tusky/network/ProgressRequestBody.kt b/app/src/main/java/com/keylesspalace/tusky/network/ProgressRequestBody.kt new file mode 100644 index 00000000..f74b0c1a --- /dev/null +++ b/app/src/main/java/com/keylesspalace/tusky/network/ProgressRequestBody.kt @@ -0,0 +1,55 @@ +/* Copyright 2017 Andrew Dawson + * + * This file is a part of Tusky. + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * Tusky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with Tusky; if not, + * see . */ +package com.keylesspalace.tusky.network + +import okhttp3.MediaType +import okhttp3.RequestBody +import okio.BufferedSink +import java.io.IOException +import java.io.InputStream + +class ProgressRequestBody(private val content: InputStream, private val contentLength: Long, private val mediaType: MediaType, private val uploadListener: UploadCallback) : RequestBody() { + fun interface UploadCallback { + fun onProgressUpdate(percentage: Int) + } + + override fun contentType(): MediaType { + return mediaType + } + + override fun contentLength(): Long { + return contentLength + } + + @Throws(IOException::class) + override fun writeTo(sink: BufferedSink) { + val buffer = ByteArray(DEFAULT_BUFFER_SIZE) + var uploaded: Long = 0 + + content.use { content -> + var read: Int + while (content.read(buffer).also { read = it } != -1) { + uploadListener.onProgressUpdate((100 * uploaded / contentLength).toInt()) + uploaded += read.toLong() + sink.write(buffer, 0, read) + } + uploadListener.onProgressUpdate((100 * uploaded / contentLength).toInt()) + } + } + + companion object { + private const val DEFAULT_BUFFER_SIZE = 2048 + } +} diff --git a/app/src/main/java/com/keylesspalace/tusky/receiver/SendStatusBroadcastReceiver.kt b/app/src/main/java/com/keylesspalace/tusky/receiver/SendStatusBroadcastReceiver.kt index 3ab941e9..861edae6 100644 --- a/app/src/main/java/com/keylesspalace/tusky/receiver/SendStatusBroadcastReceiver.kt +++ b/app/src/main/java/com/keylesspalace/tusky/receiver/SendStatusBroadcastReceiver.kt @@ -15,6 +15,7 @@ package com.keylesspalace.tusky.receiver +import android.annotation.SuppressLint import android.content.BroadcastReceiver import android.content.Context import android.content.Intent @@ -39,6 +40,7 @@ class SendStatusBroadcastReceiver : BroadcastReceiver() { @Inject lateinit var accountManager: AccountManager + @SuppressLint("MissingPermission") override fun onReceive(context: Context, intent: Intent) { AndroidInjection.inject(this, context) diff --git a/app/src/main/java/com/keylesspalace/tusky/util/IOUtils.kt b/app/src/main/java/com/keylesspalace/tusky/util/IOUtils.kt index ece76bdf..3b5c49ad 100644 --- a/app/src/main/java/com/keylesspalace/tusky/util/IOUtils.kt +++ b/app/src/main/java/com/keylesspalace/tusky/util/IOUtils.kt @@ -15,6 +15,7 @@ package com.keylesspalace.tusky.util +import android.annotation.SuppressLint import android.content.ContentResolver import android.net.Uri import java.io.Closeable @@ -34,6 +35,7 @@ fun Closeable?.closeQuietly() { } } +@SuppressLint("Recycle") // The linter can't tell that the stream gets closed by a helper method fun Uri.copyToFile( contentResolver: ContentResolver, file: File diff --git a/app/src/main/res/layout/activity_account.xml b/app/src/main/res/layout/activity_account.xml index 9b6d4f81..2e92acc0 100644 --- a/app/src/main/res/layout/activity_account.xml +++ b/app/src/main/res/layout/activity_account.xml @@ -35,6 +35,7 @@ android:layout_alignTop="@+id/account_header_info" android:background="?attr/colorPrimaryDark" android:scaleType="centerCrop" + android:contentDescription="@string/label_header" app:layout_collapseMode="parallax" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" @@ -279,8 +280,8 @@ android:layout_height="wrap_content" android:layout_marginTop="8dp" android:drawablePadding="6dp" - android:drawableStart="@drawable/ic_briefcase" android:textSize="?attr/status_text_medium" + app:drawableStartCompat="@drawable/ic_briefcase" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" tools:text="Account has moved" /> @@ -471,6 +472,7 @@ android:layout_height="@dimen/account_activity_avatar_size" android:layout_marginStart="16dp" android:padding="3dp" + android:contentDescription="@string/label_avatar" app:layout_anchor="@+id/accountHeaderInfoContainer" app:layout_anchorGravity="top" app:layout_scrollFlags="scroll" diff --git a/app/src/main/res/layout/activity_compose.xml b/app/src/main/res/layout/activity_compose.xml index 367d88ba..7e3bae8b 100644 --- a/app/src/main/res/layout/activity_compose.xml +++ b/app/src/main/res/layout/activity_compose.xml @@ -311,7 +311,7 @@ android:layout_marginEnd="4dp" android:contentDescription="@string/action_toggle_visibility" android:padding="4dp" - android:tint="?android:attr/textColorTertiary" + app:tint="?android:attr/textColorTertiary" app:tooltipText="@string/action_toggle_visibility" tools:src="@drawable/ic_public_24dp" /> diff --git a/app/src/main/res/layout/activity_tab_preference.xml b/app/src/main/res/layout/activity_tab_preference.xml index f1ebf9d8..cd6bce8d 100644 --- a/app/src/main/res/layout/activity_tab_preference.xml +++ b/app/src/main/res/layout/activity_tab_preference.xml @@ -66,7 +66,6 @@ android:layout_height="48dp" android:layout_gravity="bottom" android:background="?attr/colorPrimary" - android:drawableStart="@drawable/ic_plus_24dp" android:drawablePadding="12dp" android:ellipsize="end" android:gravity="center_vertical" @@ -75,7 +74,8 @@ android:paddingEnd="8dp" android:text="@string/action_add_tab" android:textColor="?attr/colorOnPrimary" - android:textSize="?attr/status_text_large" /> + android:textSize="?attr/status_text_large" + app:drawableStartCompat="@drawable/ic_plus_24dp" /> diff --git a/app/src/main/res/layout/dialog_filter.xml b/app/src/main/res/layout/dialog_filter.xml index 64cc6207..376167d9 100644 --- a/app/src/main/res/layout/dialog_filter.xml +++ b/app/src/main/res/layout/dialog_filter.xml @@ -11,6 +11,8 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="@string/filter_add_description" + android:inputType="text" + android:importantForAutofill="no" app:layout_constraintTop_toTopOf="parent" /> diff --git a/app/src/main/res/layout/fragment_report_note.xml b/app/src/main/res/layout/fragment_report_note.xml index 12d1fcbc..047fa9bd 100644 --- a/app/src/main/res/layout/fragment_report_note.xml +++ b/app/src/main/res/layout/fragment_report_note.xml @@ -107,6 +107,7 @@