diff --git a/app/build.gradle b/app/build.gradle index 9ac3707f8..cab3fea58 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -58,6 +58,7 @@ android { productFlavors { blue {} green { + resValue "string", "app_name", APP_NAME + " Test" applicationIdSuffix ".test" versionNameSuffix "-" + getGitSha() } @@ -105,10 +106,10 @@ project.tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all { ext.lifecycleVersion = "2.2.0" ext.roomVersion = '2.2.5' ext.retrofitVersion = '2.9.0' -ext.okhttpVersion = '4.8.1' +ext.okhttpVersion = '4.9.0' ext.glideVersion = '4.11.0' -ext.daggerVersion = '2.28.3' -ext.materialdrawerVersion = '8.1.8' +ext.daggerVersion = '2.30.1' +ext.materialdrawerVersion = '8.2.0' repositories { maven { @@ -120,22 +121,22 @@ repositories { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" - implementation "androidx.core:core-ktx:1.3.1" + implementation "androidx.core:core-ktx:1.3.2" implementation "androidx.appcompat:appcompat:1.2.0" implementation "androidx.fragment:fragment-ktx:1.2.5" - implementation "androidx.browser:browser:1.2.0" + implementation "androidx.browser:browser:1.3.0" implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0" implementation "androidx.recyclerview:recyclerview:1.1.0" - implementation "androidx.exifinterface:exifinterface:1.2.0" + implementation "androidx.exifinterface:exifinterface:1.3.2" implementation "androidx.cardview:cardview:1.0.0" - implementation "androidx.preference:preference:1.1.1" + implementation "androidx.preference:preference-ktx:1.1.1" implementation "androidx.sharetarget:sharetarget:1.0.0" implementation "androidx.emoji:emoji:1.1.0" implementation "androidx.emoji:emoji-appcompat:1.1.0" implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycleVersion" implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycleVersion" implementation "androidx.lifecycle:lifecycle-reactivestreams-ktx:$lifecycleVersion" - implementation "androidx.constraintlayout:constraintlayout:1.1.3" + implementation "androidx.constraintlayout:constraintlayout:2.0.4" implementation "androidx.paging:paging-runtime-ktx:2.1.2" implementation "androidx.viewpager2:viewpager2:1.0.0" implementation "androidx.work:work-runtime:2.4.0" @@ -151,13 +152,14 @@ dependencies { implementation "com.squareup.okhttp3:okhttp:$okhttpVersion" implementation "com.squareup.okhttp3:logging-interceptor:$okhttpVersion" + implementation "com.squareup.okhttp3:okhttp-tls:$okhttpVersion" - implementation "org.conscrypt:conscrypt-android:2.4.0" + implementation "org.conscrypt:conscrypt-android:2.5.1" implementation "com.github.bumptech.glide:glide:$glideVersion" implementation "com.github.bumptech.glide:okhttp3-integration:$glideVersion" - implementation "io.reactivex.rxjava2:rxjava:2.2.19" + implementation "io.reactivex.rxjava2:rxjava:2.2.20" implementation "io.reactivex.rxjava2:rxandroid:2.1.1" implementation "io.reactivex.rxjava2:rxkotlin:2.4.0" @@ -170,7 +172,7 @@ dependencies { implementation "com.google.dagger:dagger-android-support:$daggerVersion" kapt "com.google.dagger:dagger-android-processor:$daggerVersion" - implementation "com.github.connyduck:sparkbutton:4.0.0" + implementation "com.github.connyduck:sparkbutton:4.1.0" implementation "com.github.chrisbanes:PhotoView:2.3.0" @@ -182,14 +184,14 @@ dependencies { implementation "de.c1710:filemojicompat:1.0.17" - testImplementation "androidx.test.ext:junit:1.1.1" - testImplementation "org.robolectric:robolectric:4.3.1" - testImplementation "org.mockito:mockito-inline:3.3.3" + testImplementation "androidx.test.ext:junit:1.1.2" + testImplementation "org.robolectric:robolectric:4.4" + testImplementation "org.mockito:mockito-inline:3.6.28" testImplementation "com.nhaarman.mockitokotlin2:mockito-kotlin:2.2.0" - androidTestImplementation "androidx.test.espresso:espresso-core:3.2.0" + androidTestImplementation "androidx.test.espresso:espresso-core:3.3.0" androidTestImplementation "androidx.room:room-testing:$roomVersion" - androidTestImplementation "androidx.test.ext:junit:1.1.1" + androidTestImplementation "androidx.test.ext:junit:1.1.2" implementation 'net.accelf:easter:1.0.2' } diff --git a/app/src/main/java/com/keylesspalace/tusky/MainActivity.kt b/app/src/main/java/com/keylesspalace/tusky/MainActivity.kt index eabe6201c..335364379 100644 --- a/app/src/main/java/com/keylesspalace/tusky/MainActivity.kt +++ b/app/src/main/java/com/keylesspalace/tusky/MainActivity.kt @@ -47,6 +47,7 @@ import androidx.lifecycle.Lifecycle import androidx.preference.PreferenceManager import androidx.viewpager2.widget.MarginPageTransformer import com.bumptech.glide.Glide +import com.bumptech.glide.RequestManager import com.bumptech.glide.load.resource.bitmap.RoundedCorners import com.bumptech.glide.request.target.CustomTarget import com.bumptech.glide.request.target.FixedSizeDrawable @@ -129,6 +130,8 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje private val preferences by lazy { PreferenceManager.getDefaultSharedPreferences(this) } + private lateinit var glide: RequestManager + private val emojiInitCallback = object : InitCallback() { override fun onInitialized() { if (!isDestroyed) { @@ -139,7 +142,9 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - if (accountManager.activeAccount == null) { + + val activeAccount = accountManager.activeAccount + if (activeAccount == null) { // will be redirected to LoginActivity by BaseActivity return } @@ -157,11 +162,8 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje } } val accountRequested = accountId != -1L - if (accountRequested) { - val account = accountManager.activeAccount - if (account == null || accountId != account.id) { - accountManager.setActiveAccount(accountId) - } + if (accountRequested && accountId != activeAccount.id) { + accountManager.setActiveAccount(accountId) } if (canHandleMimeType(intent.type)) { // Sharing to Tusky from an external app @@ -173,8 +175,7 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje showAccountChooserDialog(getString(R.string.action_share_as), true, object : AccountSelectionListener { override fun onAccountSelected(account: AccountEntity) { val requestedId = account.id - val activeAccount = accountManager.activeAccount - if (activeAccount != null && requestedId == activeAccount.id) { + if (requestedId == activeAccount.id) { // The correct account is already active forwardShare(intent) } else { @@ -193,14 +194,15 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje window.statusBarColor = Color.TRANSPARENT // don't draw a status bar, the DrawerLayout and the MaterialDrawerLayout have their own setContentView(R.layout.activity_main) + glide = Glide.with(this) + viewQuickToot.attachViewModel(quickTootViewModel, this) composeButton.setOnClickListener(viewQuickToot::onFABClicked) val hideTopToolbar = preferences.getBoolean(PrefKeys.HIDE_TOP_TOOLBAR, false) mainToolbar.visible(!hideTopToolbar) - val navIconSize = resources.getDimensionPixelSize(R.dimen.avatar_toolbar_nav_icon_size) - mainToolbar.navigationIcon = FixedSizeDrawable(getDrawable(R.drawable.avatar_default), navIconSize, navIconSize) + loadDrawerAvatar(activeAccount.profilePictureUrl, true) mainToolbar.menu.add(R.string.action_search).apply { setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM) @@ -256,8 +258,10 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje viewQuickToot.handleEvent(event) } - // Flush old media that was cached for sharing - deleteStaleCachedMedia(applicationContext.getExternalFilesDir("Tusky")) + Schedulers.io().scheduleDirect { + // Flush old media that was cached for sharing + deleteStaleCachedMedia(applicationContext.getExternalFilesDir("Tusky")) + } } override fun onResume() { @@ -381,13 +385,11 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje DrawerImageLoader.init(object : AbstractDrawerImageLoader() { override fun set(imageView: ImageView, uri: Uri, placeholder: Drawable, tag: String?) { if (animateAvatars) { - Glide.with(imageView.context) - .load(uri) + glide.load(uri) .placeholder(placeholder) .into(imageView) } else { - Glide.with(imageView.context) - .asBitmap() + glide.asBitmap() .load(uri) .placeholder(placeholder) .into(imageView) @@ -395,7 +397,7 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje } override fun cancel(imageView: ImageView) { - Glide.with(imageView.context).clear(imageView) + glide.clear(imageView) } override fun placeholder(ctx: Context, tag: String?): Drawable { @@ -814,29 +816,11 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje } private fun onFetchUserInfoSuccess(me: Account) { - Glide.with(this) - .asBitmap() + glide.asBitmap() .load(me.header) .into(header.accountHeaderBackground) - val navIconSize = resources.getDimensionPixelSize(R.dimen.avatar_toolbar_nav_icon_size) - - Glide.with(this) - .asDrawable() - .override(navIconSize) - .load(me.avatar) - .transform( - RoundedCorners(resources.getDimensionPixelSize(R.dimen.avatar_radius_36dp)) - ) - .into(object : CustomTarget() { - override fun onResourceReady(resource: Drawable, transition: Transition?) { - mainToolbar.navigationIcon = resource - } - - override fun onLoadCleared(placeholder: Drawable?) { - mainToolbar.navigationIcon = placeholder - } - }) + loadDrawerAvatar(me.avatar, false) accountManager.updateActiveAccount(me) NotificationHelper.createNotificationChannelsForAccount(accountManager.activeAccount!!, this) @@ -861,6 +845,36 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje updateShortcut(this, accountManager.activeAccount!!) } + private fun loadDrawerAvatar(avatarUrl: String, showPlaceholder: Boolean) { + val navIconSize = resources.getDimensionPixelSize(R.dimen.avatar_toolbar_nav_icon_size) + + glide.asDrawable() + .load(avatarUrl) + .transform( + RoundedCorners(resources.getDimensionPixelSize(R.dimen.avatar_radius_36dp)) + ) + .apply { + if (showPlaceholder) { + placeholder(R.drawable.avatar_default) + } + } + .into(object : CustomTarget(navIconSize, navIconSize) { + + override fun onLoadStarted(placeholder: Drawable?) { + if(placeholder != null) { + mainToolbar.navigationIcon = FixedSizeDrawable(placeholder, navIconSize, navIconSize) + } + } + override fun onResourceReady(resource: Drawable, transition: Transition?) { + mainToolbar.navigationIcon = resource + } + + override fun onLoadCleared(placeholder: Drawable?) { + mainToolbar.navigationIcon = placeholder + } + }) + } + private fun fetchAnnouncements() { mastodonApi.listAnnouncements(false) .observeOn(AndroidSchedulers.mainThread()) @@ -877,7 +891,7 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje } private fun updateAnnouncementsBadge() { - mainDrawer.updateBadge(DRAWER_ITEM_ANNOUNCEMENTS, StringHolder(if (unreadAnnouncementsCount == 0) null else unreadAnnouncementsCount.toString())) + mainDrawer.updateBadge(DRAWER_ITEM_ANNOUNCEMENTS, StringHolder(if (unreadAnnouncementsCount <= 0) null else unreadAnnouncementsCount.toString())) } private fun updateProfiles() { diff --git a/app/src/main/java/com/keylesspalace/tusky/TuskyApplication.kt b/app/src/main/java/com/keylesspalace/tusky/TuskyApplication.kt index 7fb762d23..562f644e1 100644 --- a/app/src/main/java/com/keylesspalace/tusky/TuskyApplication.kt +++ b/app/src/main/java/com/keylesspalace/tusky/TuskyApplication.kt @@ -25,7 +25,9 @@ import androidx.work.WorkManager import com.keylesspalace.tusky.components.notifications.NotificationWorkerFactory import com.keylesspalace.tusky.di.AppInjector import com.keylesspalace.tusky.settings.PrefKeys -import com.keylesspalace.tusky.util.* +import com.keylesspalace.tusky.util.EmojiCompatFont +import com.keylesspalace.tusky.util.LocaleManager +import com.keylesspalace.tusky.util.ThemeUtils import com.uber.autodispose.AutoDisposePlugins import dagger.android.DispatchingAndroidInjector import dagger.android.HasAndroidInjector @@ -38,11 +40,21 @@ class TuskyApplication : Application(), HasAndroidInjector { @Inject lateinit var androidInjector: DispatchingAndroidInjector + @Inject lateinit var notificationWorkerFactory: NotificationWorkerFactory override fun onCreate() { - + // Uncomment me to get StrictMode violation logs +// if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { +// StrictMode.setThreadPolicy(StrictMode.ThreadPolicy.Builder() +// .detectDiskReads() +// .detectDiskWrites() +// .detectNetwork() +// .detectUnbufferedIo() +// .penaltyLog() +// .build()) +// } super.onCreate() Security.insertProviderAt(Conscrypt.newProvider(), 1) @@ -64,16 +76,16 @@ class TuskyApplication : Application(), HasAndroidInjector { val theme = preferences.getString("appTheme", ThemeUtils.APP_THEME_DEFAULT) ThemeUtils.setAppNightMode(theme) + RxJavaPlugins.setErrorHandler { + Log.w("RxJava", "undeliverable exception", it) + } + WorkManager.initialize( this, androidx.work.Configuration.Builder() .setWorkerFactory(notificationWorkerFactory) .build() ) - - RxJavaPlugins.setErrorHandler { - Log.w("RxJava", "undeliverable exception", it) - } } override fun attachBaseContext(base: Context) { diff --git a/app/src/main/java/com/keylesspalace/tusky/adapter/ListSelectionAdapter.kt b/app/src/main/java/com/keylesspalace/tusky/adapter/ListSelectionAdapter.kt index e5470df6b..f9b19c697 100644 --- a/app/src/main/java/com/keylesspalace/tusky/adapter/ListSelectionAdapter.kt +++ b/app/src/main/java/com/keylesspalace/tusky/adapter/ListSelectionAdapter.kt @@ -22,7 +22,6 @@ import android.view.ViewGroup import android.widget.ArrayAdapter import com.keylesspalace.tusky.R import com.keylesspalace.tusky.entity.MastoList -import com.keylesspalace.tusky.util.ThemeUtils import kotlinx.android.synthetic.main.item_picker_list.view.* class ListSelectionAdapter(context: Context) : ArrayAdapter(context, R.layout.item_autocomplete_hashtag) { @@ -34,10 +33,7 @@ class ListSelectionAdapter(context: Context) : ArrayAdapter(context, ?: layoutInflater.inflate(R.layout.item_picker_list, parent, false) getItem(position)?.let { list -> - val title = view.title - title.text = list.title - val icon = ThemeUtils.getTintedDrawable(context, R.drawable.ic_list, R.attr.iconColor) - title.setCompoundDrawablesRelativeWithIntrinsicBounds(icon, null, null, null) + view.title.text = list.title } return view diff --git a/app/src/main/java/com/keylesspalace/tusky/adapter/PreviewPollOptionsAdapter.kt b/app/src/main/java/com/keylesspalace/tusky/adapter/PreviewPollOptionsAdapter.kt index bb77cd274..328e96267 100644 --- a/app/src/main/java/com/keylesspalace/tusky/adapter/PreviewPollOptionsAdapter.kt +++ b/app/src/main/java/com/keylesspalace/tusky/adapter/PreviewPollOptionsAdapter.kt @@ -22,7 +22,6 @@ import android.widget.TextView import androidx.core.widget.TextViewCompat import androidx.recyclerview.widget.RecyclerView import com.keylesspalace.tusky.R -import com.keylesspalace.tusky.util.ThemeUtils class PreviewPollOptionsAdapter: RecyclerView.Adapter() { @@ -55,9 +54,7 @@ class PreviewPollOptionsAdapter: RecyclerView.Adapter() { R.drawable.ic_radio_button_unchecked_18dp } - val iconDrawable = ThemeUtils.getTintedDrawable(textView.context, iconId, android.R.attr.textColorTertiary) - - TextViewCompat.setCompoundDrawablesRelativeWithIntrinsicBounds(textView, iconDrawable, null, null, null) + TextViewCompat.setCompoundDrawablesRelativeWithIntrinsicBounds(textView, iconId, 0, 0, 0) textView.text = options[position] 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 4e33e784d..5d0322e74 100644 --- a/app/src/main/java/com/keylesspalace/tusky/adapter/StatusBaseViewHolder.java +++ b/app/src/main/java/com/keylesspalace/tusky/adapter/StatusBaseViewHolder.java @@ -60,7 +60,6 @@ import java.text.SimpleDateFormat; import java.util.Date; import java.util.List; import java.util.Locale; -import java.util.Objects; import at.connyduck.sparkbutton.SparkButton; import at.connyduck.sparkbutton.helpers.Utils; @@ -648,9 +647,7 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder { // Set the icon next to the label. int drawableId = getLabelIcon(attachments.get(0).getType()); - Drawable drawable = Objects.requireNonNull(context.getDrawable(drawableId)); - ThemeUtils.setDrawableTint(context, drawable, android.R.attr.textColorTertiary); - mediaLabel.setCompoundDrawablesWithIntrinsicBounds(drawable, null, null, null); + mediaLabel.setCompoundDrawablesWithIntrinsicBounds(drawableId, 0, 0, 0); setAttachmentClickListener(mediaLabel, listener, i, attachment, false); } else { diff --git a/app/src/main/java/com/keylesspalace/tusky/adapter/TabAdapter.kt b/app/src/main/java/com/keylesspalace/tusky/adapter/TabAdapter.kt index cd877a15e..b4517dc6a 100644 --- a/app/src/main/java/com/keylesspalace/tusky/adapter/TabAdapter.kt +++ b/app/src/main/java/com/keylesspalace/tusky/adapter/TabAdapter.kt @@ -15,6 +15,7 @@ package com.keylesspalace.tusky.adapter +import android.content.res.ColorStateList import android.view.LayoutInflater import android.view.MotionEvent import android.view.View @@ -68,8 +69,7 @@ class TabAdapter(private var data: List, } else { holder.itemView.textView.setText(tab.text) } - val iconDrawable = ThemeUtils.getTintedDrawable(context, tab.icon, android.R.attr.textColorSecondary) - holder.itemView.textView.setCompoundDrawablesRelativeWithIntrinsicBounds(iconDrawable, null, null, null) + holder.itemView.textView.setCompoundDrawablesRelativeWithIntrinsicBounds(tab.icon, 0, 0, 0) if (small) { holder.itemView.textView.setOnClickListener { listener.onTabAdded(tab) @@ -110,6 +110,7 @@ class TabAdapter(private var data: List, val chip = holder.itemView.chipGroup.getChildAt(i).takeUnless { it.id == R.id.actionChip } as Chip? ?: Chip(context).apply { holder.itemView.chipGroup.addView(this, holder.itemView.chipGroup.size - 1) + chipIconTint = ColorStateList.valueOf(ThemeUtils.getColor(context, android.R.attr.textColorPrimary)) } chip.text = arg @@ -118,8 +119,7 @@ class TabAdapter(private var data: List, chip.chipIcon = null chip.setOnClickListener(null) } else { - val cancelIcon = ThemeUtils.getTintedDrawable(context, R.drawable.ic_cancel_24dp, android.R.attr.textColorPrimary) - chip.chipIcon = cancelIcon + chip.setChipIconResource(R.drawable.ic_cancel_24dp) chip.setOnClickListener { listener.onChipClicked(tab, holder.adapterPosition, i) } 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 c4fa93f24..e8431709f 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 @@ -27,10 +27,12 @@ import com.google.android.material.chip.ChipGroup import com.keylesspalace.tusky.R import com.keylesspalace.tusky.entity.Announcement import com.keylesspalace.tusky.entity.Emoji +import com.keylesspalace.tusky.interfaces.LinkListener +import com.keylesspalace.tusky.util.LinkHelper import com.keylesspalace.tusky.util.emojify import kotlinx.android.synthetic.main.item_announcement.view.* -interface AnnouncementActionListener { +interface AnnouncementActionListener: LinkListener { fun openReactionPicker(announcementId: String, target: View) fun addReaction(announcementId: String, name: String) fun removeReaction(announcementId: String, name: String) @@ -59,13 +61,12 @@ class AnnouncementAdapter( } inner class AnnouncementViewHolder(private val view: View) : RecyclerView.ViewHolder(view) { - private val text: TextView = view.text private val chips: ChipGroup = view.chipGroup private val addReactionChip: Chip = view.addReactionChip fun bind(item: Announcement) { - text.text = item.content + LinkHelper.setClickableText(text, item.content, null, listener, false) item.reactions.forEachIndexed { i, reaction -> (chips.getChildAt(i)?.takeUnless { it.id == R.id.addReactionChip } as Chip? diff --git a/app/src/main/java/com/keylesspalace/tusky/components/announcements/AnnouncementsActivity.kt b/app/src/main/java/com/keylesspalace/tusky/components/announcements/AnnouncementsActivity.kt index f9c0ae725..45277b8aa 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/announcements/AnnouncementsActivity.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/announcements/AnnouncementsActivity.kt @@ -22,11 +22,9 @@ import android.view.MenuItem import android.view.View import android.widget.PopupWindow import androidx.activity.viewModels -import androidx.lifecycle.Observer import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager -import com.keylesspalace.tusky.BaseActivity -import com.keylesspalace.tusky.R +import com.keylesspalace.tusky.* import com.keylesspalace.tusky.adapter.EmojiAdapter import com.keylesspalace.tusky.adapter.OnEmojiSelectedListener import com.keylesspalace.tusky.di.Injectable @@ -37,7 +35,7 @@ import kotlinx.android.synthetic.main.activity_announcements.* import kotlinx.android.synthetic.main.toolbar_basic.* import javax.inject.Inject -class AnnouncementsActivity : BaseActivity(), AnnouncementActionListener, OnEmojiSelectedListener, Injectable { +class AnnouncementsActivity : BottomSheetActivity(), AnnouncementActionListener, OnEmojiSelectedListener, Injectable { @Inject lateinit var viewModelFactory: ViewModelFactory @@ -79,7 +77,7 @@ class AnnouncementsActivity : BaseActivity(), AnnouncementActionListener, OnEmoj announcementsList.addItemDecoration(divider) announcementsList.adapter = adapter - viewModel.announcements.observe(this, Observer { + viewModel.announcements.observe(this) { when (it) { is Success -> { progressBar.hide() @@ -104,11 +102,11 @@ class AnnouncementsActivity : BaseActivity(), AnnouncementActionListener, OnEmoj errorMessageView.show() } } - }) + } - viewModel.emojis.observe(this, Observer { + viewModel.emojis.observe(this) { picker.adapter = EmojiAdapter(it, this) - }) + } viewModel.load() progressBar.show() @@ -147,6 +145,24 @@ class AnnouncementsActivity : BaseActivity(), AnnouncementActionListener, OnEmoj viewModel.removeReaction(announcementId, name) } + override fun onViewTag(tag: String?) { + val intent = Intent(this, ViewTagActivity::class.java) + intent.putExtra("hashtag", tag) + startActivityWithSlideInAnimation(intent) + } + + override fun onViewAccount(id: String?) { + if (id != null) { + viewAccount(id) + } + } + + override fun onViewUrl(url: String?, text: String?) { + if (url != null) { + viewUrl(url) + } + } + companion object { fun newIntent(context: Context) = Intent(context, AnnouncementsActivity::class.java) } diff --git a/app/src/main/java/com/keylesspalace/tusky/components/announcements/AnnouncementsViewModel.kt b/app/src/main/java/com/keylesspalace/tusky/components/announcements/AnnouncementsViewModel.kt index 2fd1fbae4..964cc739a 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/announcements/AnnouncementsViewModel.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/announcements/AnnouncementsViewModel.kt @@ -51,7 +51,7 @@ class AnnouncementsViewModel @Inject constructor( .map> { Either.Left(it) } .onErrorResumeNext( mastodonApi.getInstance() - .map { Either.Right(it) } + .map { Either.Right(it) } ) ) { emojis, either -> either.asLeftOrNull()?.copy(emojiList = emojis) diff --git a/app/src/main/java/com/keylesspalace/tusky/components/compose/ComposeActivity.kt b/app/src/main/java/com/keylesspalace/tusky/components/compose/ComposeActivity.kt index b9beb2ea0..f30c9d5c2 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/compose/ComposeActivity.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/compose/ComposeActivity.kt @@ -626,8 +626,7 @@ class ComposeActivity : BaseActivity(), Status.Visibility.UNLEAKABLE -> R.drawable.ic_low_vision_24dp else -> R.drawable.ic_lock_open_24dp } - val drawable = ThemeUtils.getTintedDrawable(this, iconRes, android.R.attr.textColorTertiary) - composeToggleVisibilityButton.setImageDrawable(drawable) + composeToggleVisibilityButton.setImageResource(iconRes) } private fun showComposeOptions() { 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 d2ddfeabf..74d276318 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 @@ -19,10 +19,8 @@ import android.net.Uri import android.util.Log import androidx.core.net.toUri import androidx.lifecycle.LiveData -import androidx.lifecycle.MediatorLiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.Observer -import androidx.work.impl.utils.LiveDataUtils import com.keylesspalace.tusky.adapter.ComposeAutoCompleteAdapter import com.keylesspalace.tusky.components.compose.ComposeActivity.QueuedMedia import com.keylesspalace.tusky.components.search.SearchType @@ -35,7 +33,6 @@ import com.keylesspalace.tusky.network.MastodonApi import com.keylesspalace.tusky.service.ServiceClient import com.keylesspalace.tusky.service.TootToSend import com.keylesspalace.tusky.util.* -import io.reactivex.Observable.empty import io.reactivex.Observable.just import io.reactivex.disposables.Disposable import io.reactivex.rxkotlin.Singles diff --git a/app/src/main/java/com/keylesspalace/tusky/components/compose/view/ComposeScheduleView.java b/app/src/main/java/com/keylesspalace/tusky/components/compose/view/ComposeScheduleView.java index ca6639369..a1a99a7dc 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/compose/view/ComposeScheduleView.java +++ b/app/src/main/java/com/keylesspalace/tusky/components/compose/view/ComposeScheduleView.java @@ -26,13 +26,13 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; import androidx.constraintlayout.widget.ConstraintLayout; +import androidx.core.content.ContextCompat; import com.google.android.material.datepicker.CalendarConstraints; import com.google.android.material.datepicker.DateValidatorPointForward; import com.google.android.material.datepicker.MaterialDatePicker; import com.keylesspalace.tusky.R; import com.keylesspalace.tusky.fragment.TimePickerFragment; -import com.keylesspalace.tusky.util.ThemeUtils; import java.text.DateFormat; import java.text.ParseException; @@ -106,7 +106,7 @@ public class ComposeScheduleView extends ConstraintLayout { } private void setEditIcons() { - Drawable icon = ThemeUtils.getTintedDrawable(getContext(), R.drawable.ic_create_24dp, android.R.attr.textColorTertiary); + Drawable icon = ContextCompat.getDrawable(getContext(), R.drawable.ic_create_24dp); if (icon == null) { return; } 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 3020f2071..14c9e480b 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 @@ -295,7 +295,7 @@ public class NotificationHelper { .setSmallIcon(R.drawable.ic_notify) .setContentIntent(summary ? summaryResultPendingIntent : eventResultPendingIntent) .setDeleteIntent(deletePendingIntent) - .setColor(BuildConfig.DEBUG ? Color.parseColor("#19A341") : ContextCompat.getColor(context, R.color.tusky_blue)) + .setColor(BuildConfig.FLAVOR == "green" ? Color.parseColor("#19A341") : ContextCompat.getColor(context, R.color.tusky_blue)) .setGroup(account.getAccountId()) .setAutoCancel(true) .setShortcutId(Long.toString(account.getId())) diff --git a/app/src/main/java/com/keylesspalace/tusky/components/preference/AccountPreferencesFragment.kt b/app/src/main/java/com/keylesspalace/tusky/components/preference/AccountPreferencesFragment.kt index af882977e..286b49b56 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/preference/AccountPreferencesFragment.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/preference/AccountPreferencesFragment.kt @@ -16,10 +16,10 @@ package com.keylesspalace.tusky.components.preference import android.content.Intent -import android.graphics.drawable.Drawable import android.os.Build import android.os.Bundle import android.util.Log +import androidx.annotation.DrawableRes import androidx.preference.PreferenceFragmentCompat import com.google.android.material.snackbar.Snackbar import com.keylesspalace.tusky.* @@ -71,7 +71,7 @@ class AccountPreferencesFragment : PreferenceFragmentCompat(), Injectable { preference { setTitle(R.string.title_tab_preferences) - icon = getTintedIcon(R.drawable.ic_tabs) + setIcon(R.drawable.ic_tabs) setOnPreferenceClickListener { val intent = Intent(context, TabPreferenceActivity::class.java) activity?.startActivity(intent) @@ -83,7 +83,7 @@ class AccountPreferencesFragment : PreferenceFragmentCompat(), Injectable { preference { setTitle(R.string.action_view_mutes) - icon = getTintedIcon(R.drawable.ic_mute_24dp) + setIcon(R.drawable.ic_mute_24dp) setOnPreferenceClickListener { val intent = Intent(context, AccountListActivity::class.java) intent.putExtra("type", AccountListActivity.Type.MUTES) @@ -112,7 +112,7 @@ class AccountPreferencesFragment : PreferenceFragmentCompat(), Injectable { preference { setTitle(R.string.title_domain_mutes) - icon = getTintedIcon(R.drawable.ic_mute_24dp) + setIcon(R.drawable.ic_mute_24dp) setOnPreferenceClickListener { val intent = Intent(context, InstanceListActivity::class.java) activity?.startActivity(intent) @@ -132,11 +132,9 @@ class AccountPreferencesFragment : PreferenceFragmentCompat(), Injectable { val visibility = accountManager.activeAccount?.defaultPostPrivacy ?: Status.Visibility.PUBLIC value = visibility.serverString() - icon = getIconForVisibility(visibility) + setIcon(getIconForVisibility(visibility)) setOnPreferenceChangeListener { _, newValue -> - icon = getIconForVisibility( - Status.Visibility.byString(newValue as String) - ) + setIcon(getIconForVisibility(Status.Visibility.byString(newValue as String))) syncWithServer(visibility = newValue) eventHub.dispatch(PreferenceChangedEvent(key)) true @@ -151,9 +149,9 @@ class AccountPreferencesFragment : PreferenceFragmentCompat(), Injectable { val sensitivity = accountManager.activeAccount?.defaultMediaSensitivity ?: false setDefaultValue(sensitivity) - icon = getIconForSensitivity(sensitivity) + setIcon(getIconForSensitivity(sensitivity)) setOnPreferenceChangeListener { _, newValue -> - icon = getIconForSensitivity(newValue as Boolean) + setIcon(getIconForSensitivity(newValue as Boolean)) syncWithServer(sensitive = newValue) eventHub.dispatch(PreferenceChangedEvent(key)) true @@ -303,30 +301,24 @@ class AccountPreferencesFragment : PreferenceFragmentCompat(), Injectable { } } - private fun getIconForVisibility(visibility: Status.Visibility): Drawable? { - val drawableId = when (visibility) { + @DrawableRes + private fun getIconForVisibility(visibility: Status.Visibility): Int { + return when (visibility) { Status.Visibility.PRIVATE -> R.drawable.ic_lock_outline_24dp Status.Visibility.UNLISTED -> R.drawable.ic_lock_open_24dp else -> R.drawable.ic_public_24dp } - - return getTintedIcon(drawableId) } - private fun getIconForSensitivity(sensitive: Boolean): Drawable? { - val drawableId = if (sensitive) { + @DrawableRes + private fun getIconForSensitivity(sensitive: Boolean): Int { + return if (sensitive) { R.drawable.ic_hide_media_24dp } else { R.drawable.ic_eye_24dp } - - return getTintedIcon(drawableId) - } - - private fun getTintedIcon(iconId: Int): Drawable? { - return ThemeUtils.getTintedDrawable(requireContext(), iconId, R.attr.iconColor) } private fun launchFilterActivity(filterContext: String, titleResource: Int) { diff --git a/app/src/main/java/com/keylesspalace/tusky/components/preference/PreferencesFragment.kt b/app/src/main/java/com/keylesspalace/tusky/components/preference/PreferencesFragment.kt index e1ddd37d0..04bec9aa5 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/preference/PreferencesFragment.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/preference/PreferencesFragment.kt @@ -42,7 +42,6 @@ class PreferencesFragment : PreferenceFragmentCompat(), Injectable { private var httpProxyPref: Preference? = null override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { - val context = requireContext() makePreferenceScreen { lateinit var limitedBandwidthMobilePref: SwitchPreference lateinit var limitedBandwidthTimelinePref: SwitchPreference @@ -121,11 +120,8 @@ class PreferencesFragment : PreferenceFragmentCompat(), Injectable { key = PrefKeys.SHOW_BOT_OVERLAY setTitle(R.string.pref_title_bot_overlay) isSingleLineTitle = false - icon = ThemeUtils.getTintedDrawable( - context, - R.drawable.ic_bot_24dp, - R.attr.iconColor - ) + setIcon(R.drawable.ic_bot_24dp) + } switchPreference { diff --git a/app/src/main/java/com/keylesspalace/tusky/db/AccountManager.kt b/app/src/main/java/com/keylesspalace/tusky/db/AccountManager.kt index aae0bf5a3..138f71a32 100644 --- a/app/src/main/java/com/keylesspalace/tusky/db/AccountManager.kt +++ b/app/src/main/java/com/keylesspalace/tusky/db/AccountManager.kt @@ -62,7 +62,7 @@ class AccountManager @Inject constructor(db: AppDatabase) { accountDao.insertOrReplace(it) } - val maxAccountId = accounts.maxBy { it.id }?.id ?: 0 + val maxAccountId = accounts.maxByOrNull { it.id }?.id ?: 0 val newAccountId = maxAccountId + 1 activeAccount = AccountEntity(id = newAccountId, domain = domain.toLowerCase(Locale.ROOT), accessToken = accessToken, isActive = true) diff --git a/app/src/main/java/com/keylesspalace/tusky/di/NetworkModule.kt b/app/src/main/java/com/keylesspalace/tusky/di/NetworkModule.kt index cdfa1b44a..588ae3ca9 100644 --- a/app/src/main/java/com/keylesspalace/tusky/di/NetworkModule.kt +++ b/app/src/main/java/com/keylesspalace/tusky/di/NetworkModule.kt @@ -25,7 +25,7 @@ import com.keylesspalace.tusky.json.SpannedTypeAdapter import com.keylesspalace.tusky.network.InstanceSwitchAuthInterceptor import com.keylesspalace.tusky.network.MastodonApi import com.keylesspalace.tusky.network.NotestockApi -import com.keylesspalace.tusky.util.OkHttpUtils +import com.keylesspalace.tusky.util.okhttpClient import dagger.Module import dagger.Provides import net.accelf.yuito.HttpToastInterceptor @@ -34,6 +34,7 @@ import okhttp3.logging.HttpLoggingInterceptor import retrofit2.Retrofit import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory import retrofit2.converter.gson.GsonConverterFactory +import retrofit2.create import javax.inject.Singleton /** @@ -57,7 +58,7 @@ class NetworkModule { accountManager: AccountManager, context: Context ): OkHttpClient { - return OkHttpUtils.getCompatibleClientBuilder(context) + return okhttpClient(context) .apply { addInterceptor(InstanceSwitchAuthInterceptor(accountManager)) if (BuildConfig.DEBUG) { @@ -84,13 +85,13 @@ class NetworkModule { @Provides @Singleton - fun providesApi(retrofit: Retrofit): MastodonApi = retrofit.create(MastodonApi::class.java) + fun providesApi(retrofit: Retrofit): MastodonApi = retrofit.create() @Provides @Singleton fun providesNotestockApi(context: Context, gson: Gson): NotestockApi { - val httpClient = OkHttpUtils.getCompatibleClientBuilder(context) + val httpClient = okhttpClient(context) .apply { if (BuildConfig.DEBUG) { addInterceptor(HttpLoggingInterceptor().apply { level = HttpLoggingInterceptor.Level.BASIC }) @@ -105,4 +106,4 @@ class NetworkModule { .build() return retrofit.create(NotestockApi::class.java) } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/keylesspalace/tusky/entity/Attachment.kt b/app/src/main/java/com/keylesspalace/tusky/entity/Attachment.kt index 3517ff09c..1de7bd787 100644 --- a/app/src/main/java/com/keylesspalace/tusky/entity/Attachment.kt +++ b/app/src/main/java/com/keylesspalace/tusky/entity/Attachment.kt @@ -28,7 +28,7 @@ import kotlinx.android.parcel.Parcelize data class Attachment( val id: String, val url: String, - @SerializedName("preview_url") val previewUrl: String, + @SerializedName("preview_url") val previewUrl: String?, // can be null for e.g. audio attachments val meta: MetaData?, val type: Type, val description: String?, diff --git a/app/src/main/java/com/keylesspalace/tusky/fragment/AccountListFragment.kt b/app/src/main/java/com/keylesspalace/tusky/fragment/AccountListFragment.kt index d15835e3b..da9893a22 100644 --- a/app/src/main/java/com/keylesspalace/tusky/fragment/AccountListFragment.kt +++ b/app/src/main/java/com/keylesspalace/tusky/fragment/AccountListFragment.kt @@ -330,6 +330,7 @@ class AccountListFragment : BaseFragment(), AccountActionListener, Injectable { private fun fetchRelationships(ids: List) { api.relationships(ids) + .observeOn(AndroidSchedulers.mainThread()) .autoDispose(from(this)) .subscribe(::onFetchRelationshipsSuccess) { onFetchRelationshipsFailure(ids) diff --git a/app/src/main/java/com/keylesspalace/tusky/fragment/TimelineFragment.java b/app/src/main/java/com/keylesspalace/tusky/fragment/TimelineFragment.java index 57f5fb5c2..4ea9de6a7 100644 --- a/app/src/main/java/com/keylesspalace/tusky/fragment/TimelineFragment.java +++ b/app/src/main/java/com/keylesspalace/tusky/fragment/TimelineFragment.java @@ -502,6 +502,7 @@ public class TimelineFragment extends SFragment implements // home, notifications, public, thread switch (kind) { case HOME: + case LIST: return filterContext.contains(Filter.HOME); case PUBLIC_FEDERATED: case PUBLIC_LOCAL: diff --git a/app/src/main/java/com/keylesspalace/tusky/util/CustomEmojiHelper.kt b/app/src/main/java/com/keylesspalace/tusky/util/CustomEmojiHelper.kt index 14a0ceb57..679f38d36 100644 --- a/app/src/main/java/com/keylesspalace/tusky/util/CustomEmojiHelper.kt +++ b/app/src/main/java/com/keylesspalace/tusky/util/CustomEmojiHelper.kt @@ -54,7 +54,7 @@ fun CharSequence.emojify(emojis: List?, view: View) : CharSequence { while(matcher.find()) { val span = EmojiSpan(WeakReference(view)) - builder.setSpan(span, matcher.start(), matcher.end(), 0); + builder.setSpan(span, matcher.start(), matcher.end(), 0) Glide.with(view) .asBitmap() .load(url) @@ -89,7 +89,7 @@ class EmojiSpan(val viewWeakReference: WeakReference) : ReplacementSpan() drawable.setBounds(0, 0, emojiSize, emojiSize) var transY = bottom - drawable.bounds.bottom - transY -= paint.fontMetricsInt.descent / 2; + transY -= paint.fontMetricsInt.descent / 2 canvas.translate(x, transY.toFloat()) drawable.draw(canvas) diff --git a/app/src/main/java/com/keylesspalace/tusky/util/OkHttpUtils.java b/app/src/main/java/com/keylesspalace/tusky/util/OkHttpUtils.java deleted file mode 100644 index 22e13e5ec..000000000 --- a/app/src/main/java/com/keylesspalace/tusky/util/OkHttpUtils.java +++ /dev/null @@ -1,87 +0,0 @@ -/* Copyright 2017 Andrew Dawson - * - * This file is part of Tusky. - * - * Tusky is free software: you can redistribute it and/or modify it under the terms of the GNU - * Lesser 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 Lesser - * General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License along with Tusky. If - * not, see . */ - -package com.keylesspalace.tusky.util; - -import android.content.Context; -import android.content.SharedPreferences; -import android.os.Build; - -import androidx.annotation.NonNull; -import androidx.preference.PreferenceManager; - -import com.keylesspalace.tusky.BuildConfig; - -import java.net.InetSocketAddress; -import java.net.Proxy; -import java.util.concurrent.TimeUnit; - -import okhttp3.Cache; -import okhttp3.Interceptor; -import okhttp3.OkHttpClient; -import okhttp3.Request; - -public class OkHttpUtils { - - @NonNull - public static OkHttpClient.Builder getCompatibleClientBuilder(@NonNull Context context) { - - SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context); - - boolean httpProxyEnabled = preferences.getBoolean("httpProxyEnabled", false); - String httpServer = preferences.getString("httpProxyServer", ""); - int httpPort; - try { - httpPort = Integer.parseInt(preferences.getString("httpProxyPort", "-1")); - } catch (NumberFormatException e) { - // user has entered wrong port, fall back to no proxy - httpPort = -1; - } - - int cacheSize = 25*1024*1024; // 25 MiB - - OkHttpClient.Builder builder = new OkHttpClient.Builder() - .addInterceptor(getUserAgentInterceptor()) - .readTimeout(30, TimeUnit.SECONDS) - .writeTimeout(30, TimeUnit.SECONDS) - .cache(new Cache(context.getCacheDir(), cacheSize)); - - if (httpProxyEnabled && !httpServer.isEmpty() && (httpPort > 0) && (httpPort < 65535)) { - InetSocketAddress address = InetSocketAddress.createUnresolved(httpServer, httpPort); - builder.proxy(new Proxy(Proxy.Type.HTTP, address)); - } - - return builder; - } - - /** - * Add a custom User-Agent that contains Tusky & Android Version to all requests - * Example: - * User-Agent: Tusky/1.1.2 Android/5.0.2 - */ - @NonNull - private static Interceptor getUserAgentInterceptor() { - return chain -> { - Request originalRequest = chain.request(); - Request requestWithUserAgent = originalRequest.newBuilder() - .header("User-Agent", "Tusky/"+ BuildConfig.VERSION_NAME+" Android/"+Build.VERSION.RELEASE) - .build(); - return chain.proceed(requestWithUserAgent); - }; - } - -} - - diff --git a/app/src/main/java/com/keylesspalace/tusky/util/OkHttpUtils.kt b/app/src/main/java/com/keylesspalace/tusky/util/OkHttpUtils.kt new file mode 100644 index 000000000..3e1b89c6a --- /dev/null +++ b/app/src/main/java/com/keylesspalace/tusky/util/OkHttpUtils.kt @@ -0,0 +1,115 @@ +/* Copyright 2020 Tusky Contributors + * + * This file is part of Tusky. + * + * Tusky is free software: you can redistribute it and/or modify it under the terms of the GNU + * Lesser 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 Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along with Tusky. If + * not, see . */ + +package com.keylesspalace.tusky.util + +import android.content.Context +import android.os.Build +import androidx.preference.PreferenceManager +import com.keylesspalace.tusky.BuildConfig +import okhttp3.Cache +import okhttp3.OkHttp +import okhttp3.OkHttpClient +import okhttp3.tls.HandshakeCertificates +import java.io.ByteArrayInputStream +import java.net.InetSocketAddress +import java.net.Proxy +import java.security.cert.CertificateFactory +import java.security.cert.X509Certificate +import java.util.concurrent.TimeUnit + +fun okhttpClient(context: Context): OkHttpClient.Builder { + val preferences = PreferenceManager.getDefaultSharedPreferences(context) + + val httpProxyEnabled = preferences.getBoolean("httpProxyEnabled", false) + val httpServer = preferences.getNonNullString("httpProxyServer", "") + val httpPort = preferences.getNonNullString("httpProxyPort", "-1").toIntOrNull() ?: -1 + + val cacheSize = 25 * 1024 * 1024 // 25 MiB + val builder = OkHttpClient.Builder() + .addInterceptor { chain -> + /** + * Add a custom User-Agent that contains Tusky, Android and Okhttp Version to all requests + * Example: + * User-Agent: Tusky/1.1.2 Android/5.0.2 + * */ + val requestWithUserAgent = chain.request().newBuilder() + .header( + "User-Agent", + "Tusky/${BuildConfig.VERSION_NAME} Android/${Build.VERSION.RELEASE} OkHttp/${OkHttp.VERSION}" + ) + .build() + chain.proceed(requestWithUserAgent) + } + .readTimeout(30, TimeUnit.SECONDS) + .writeTimeout(30, TimeUnit.SECONDS) + .cache(Cache(context.cacheDir, cacheSize.toLong())) + + if (httpProxyEnabled && httpServer.isNotEmpty() && httpPort > 0 && httpPort < 65535) { + val address = InetSocketAddress.createUnresolved(httpServer, httpPort) + builder.proxy(Proxy(Proxy.Type.HTTP, address)) + } + + // trust the new Let's Encrypt root certificate that is not available on Android < 7.1.1 + // new cert https://letsencrypt.org/certs/isrgrootx1.pem + // see https://letsencrypt.org/2020/11/06/own-two-feet.html + // see https://stackoverflow.com/questions/64844311/certpathvalidatorexception-connecting-to-a-lets-encrypt-host-on-android-m-or-ea + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { + val isgCert = """ + -----BEGIN CERTIFICATE----- + MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw + TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh + cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4 + WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu + ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY + MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc + h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+ + 0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U + A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW + T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH + B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC + B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv + KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn + OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn + jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw + qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI + rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV + HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq + hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL + ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ + 3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK + NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5 + ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur + TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC + jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc + oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq + 4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA + mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d + emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc= + -----END CERTIFICATE----- + """.trimIndent() + val cf = CertificateFactory.getInstance("X.509") + val isgCertificate = cf.generateCertificate(ByteArrayInputStream(isgCert.toByteArray(charset("UTF-8")))) + val certificates = HandshakeCertificates.Builder() + .addTrustedCertificate(isgCertificate as X509Certificate) + .addPlatformTrustedCertificates() + .build() + builder.sslSocketFactory( + certificates.sslSocketFactory(), + certificates.trustManager + ) + } + return builder +} diff --git a/app/src/main/java/com/keylesspalace/tusky/util/StatusViewHelper.kt b/app/src/main/java/com/keylesspalace/tusky/util/StatusViewHelper.kt index cb4651fd3..2fb9ad428 100644 --- a/app/src/main/java/com/keylesspalace/tusky/util/StatusViewHelper.kt +++ b/app/src/main/java/com/keylesspalace/tusky/util/StatusViewHelper.kt @@ -23,7 +23,6 @@ import android.view.View import android.widget.ImageView import android.widget.TextView import androidx.annotation.DrawableRes -import androidx.appcompat.content.res.AppCompatResources import com.bumptech.glide.Glide import com.keylesspalace.tusky.R import com.keylesspalace.tusky.entity.Attachment @@ -220,9 +219,7 @@ class StatusViewHelper(private val itemView: View) { // Set the icon next to the label. val drawableId = getLabelIcon(attachments[0].type) - val drawable = AppCompatResources.getDrawable(context, drawableId) - ThemeUtils.setDrawableTint(context, drawable!!, android.R.attr.textColorTertiary) - mediaLabel.setCompoundDrawablesWithIntrinsicBounds(drawable, null, null, null) + mediaLabel.setCompoundDrawablesWithIntrinsicBounds(drawableId, 0, 0, 0) mediaLabel.setOnClickListener { listener.onViewMedia(null, 0) } } diff --git a/app/src/main/java/com/keylesspalace/tusky/util/ThemeUtils.java b/app/src/main/java/com/keylesspalace/tusky/util/ThemeUtils.java index 7888f7ce0..56552e9bb 100644 --- a/app/src/main/java/com/keylesspalace/tusky/util/ThemeUtils.java +++ b/app/src/main/java/com/keylesspalace/tusky/util/ThemeUtils.java @@ -24,9 +24,7 @@ import android.util.TypedValue; import androidx.annotation.AttrRes; import androidx.annotation.ColorInt; -import androidx.annotation.DrawableRes; import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatDelegate; /** @@ -60,17 +58,6 @@ public class ThemeUtils { return dimen; } - /** this can be replaced with drawableTint in xml once minSdkVersion >= 23 */ - @Nullable - public static Drawable getTintedDrawable(@NonNull Context context, @DrawableRes int drawableId, @AttrRes int colorAttr) { - Drawable drawable = context.getDrawable(drawableId); - if(drawable == null) { - return null; - } - setDrawableTint(context, drawable, colorAttr); - return drawable; - } - public static void setDrawableTint(Context context, Drawable drawable, @AttrRes int attribute) { drawable.setColorFilter(getColor(context, attribute), PorterDuff.Mode.SRC_IN); } diff --git a/app/src/main/res/layout/activity_announcements.xml b/app/src/main/res/layout/activity_announcements.xml index c0504b83c..9e40e9df0 100644 --- a/app/src/main/res/layout/activity_announcements.xml +++ b/app/src/main/res/layout/activity_announcements.xml @@ -36,4 +36,6 @@ tools:src="@drawable/elephant_error" tools:visibility="visible" /> + + diff --git a/app/src/main/res/layout/activity_compose.xml b/app/src/main/res/layout/activity_compose.xml index e4537e94e..87edfdf49 100644 --- a/app/src/main/res/layout/activity_compose.xml +++ b/app/src/main/res/layout/activity_compose.xml @@ -166,10 +166,10 @@ + android:scrollbars="none" + android:visibility="gone" /> + app:srcCompat="@drawable/ic_attach_file_24dp" + app:tooltipText="@string/action_add_media" /> + app:srcCompat="@drawable/ic_cw_24dp" + app:tooltipText="@string/action_content_warning" /> + app:srcCompat="@drawable/ic_emoji_24dp" + app:tooltipText="@string/action_emoji_keyboard" /> + app:srcCompat="@drawable/ic_access_time" + app:tooltipText="@string/action_schedule_toot" /> + app:layout_scrollFlags="scroll|enterAlways" + app:navigationContentDescription="@string/action_open_drawer" /> + android:textStyle="normal|bold" + app:drawableStartCompat="@drawable/ic_list" + app:drawableTint="?attr/iconColor" /> diff --git a/app/src/main/res/layout/item_conversation.xml b/app/src/main/res/layout/item_conversation.xml index a2dd4e3db..d746f99ec 100644 --- a/app/src/main/res/layout/item_conversation.xml +++ b/app/src/main/res/layout/item_conversation.xml @@ -340,6 +340,7 @@ android:importantForAccessibility="no" android:textSize="?attr/status_text_medium" android:visibility="gone" + app:drawableTint="?android:attr/textColorTertiary" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> @@ -353,6 +354,7 @@ android:importantForAccessibility="no" android:textSize="?attr/status_text_medium" android:visibility="gone" + app:drawableTint="?android:attr/textColorTertiary" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/status_media_label_0" /> @@ -366,6 +368,7 @@ android:importantForAccessibility="no" android:textSize="?attr/status_text_medium" android:visibility="gone" + app:drawableTint="?android:attr/textColorTertiary" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/status_media_label_1" /> @@ -379,6 +382,7 @@ android:importantForAccessibility="no" android:textSize="?attr/status_text_medium" android:visibility="gone" + app:drawableTint="?android:attr/textColorTertiary" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/status_media_label_2" /> diff --git a/app/src/main/res/layout/item_emoji_pref.xml b/app/src/main/res/layout/item_emoji_pref.xml index 539677f10..d8755a3dd 100644 --- a/app/src/main/res/layout/item_emoji_pref.xml +++ b/app/src/main/res/layout/item_emoji_pref.xml @@ -6,8 +6,8 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:background="?attr/selectableItemBackground" - android:paddingBottom="8dp" - android:paddingTop="8dp"> + android:paddingTop="8dp" + android:paddingBottom="8dp"> + app:srcCompat="@drawable/ic_emoji_24dp" + app:tint="#0000" /> @@ -58,8 +60,8 @@ style="?android:attr/progressBarStyleHorizontal" android:layout_width="0dp" android:layout_height="wrap_content" - android:layout_marginEnd="72dp" android:layout_marginTop="8dp" + android:layout_marginEnd="72dp" android:indeterminate="false" android:visibility="gone" app:layout_constraintEnd_toEndOf="parent" diff --git a/app/src/main/res/layout/item_poll_preview_option.xml b/app/src/main/res/layout/item_poll_preview_option.xml index d7f5887a6..e8fa98499 100644 --- a/app/src/main/res/layout/item_poll_preview_option.xml +++ b/app/src/main/res/layout/item_poll_preview_option.xml @@ -1,5 +1,6 @@ \ No newline at end of file + android:maxEms="20" + app:drawableTint="?android:attr/textColorTertiary" /> \ No newline at end of file diff --git a/app/src/main/res/layout/item_report_status.xml b/app/src/main/res/layout/item_report_status.xml index b7ed05552..56a2dea92 100644 --- a/app/src/main/res/layout/item_report_status.xml +++ b/app/src/main/res/layout/item_report_status.xml @@ -198,8 +198,8 @@ app:layout_constraintLeft_toLeftOf="@+id/status_media_preview_container" app:layout_constraintTop_toTopOf="@+id/status_media_preview_container" app:srcCompat="@drawable/ic_eye_24dp" - tools:visibility="visible" - app:tint="@color/white" /> + app:tint="@color/white" + tools:visibility="visible" /> diff --git a/app/src/main/res/layout/item_status.xml b/app/src/main/res/layout/item_status.xml index cdf709b69..053be82d5 100644 --- a/app/src/main/res/layout/item_status.xml +++ b/app/src/main/res/layout/item_status.xml @@ -168,9 +168,9 @@ android:foreground="?attr/selectableItemBackground" android:minHeight="80dp" android:orientation="vertical" + app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="@id/status_display_name" app:layout_constraintTop_toBottomOf="@+id/button_toggle_content" - app:layout_constraintEnd_toEndOf="parent" tools:visibility="gone"> @@ -424,6 +425,7 @@ android:importantForAccessibility="no" android:textSize="?attr/status_text_medium" android:visibility="gone" + app:drawableTint="?android:attr/textColorTertiary" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/status_media_label_0" /> @@ -437,6 +439,7 @@ android:importantForAccessibility="no" android:textSize="?attr/status_text_medium" android:visibility="gone" + app:drawableTint="?android:attr/textColorTertiary" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/status_media_label_1" /> @@ -450,6 +453,7 @@ android:importantForAccessibility="no" android:textSize="?attr/status_text_medium" android:visibility="gone" + app:drawableTint="?android:attr/textColorTertiary" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/status_media_label_2" /> diff --git a/app/src/main/res/layout/item_status_detailed.xml b/app/src/main/res/layout/item_status_detailed.xml index d50deab66..d176456be 100644 --- a/app/src/main/res/layout/item_status_detailed.xml +++ b/app/src/main/res/layout/item_status_detailed.xml @@ -356,6 +356,7 @@ android:importantForAccessibility="no" android:textSize="?attr/status_text_medium" android:visibility="gone" + app:drawableTint="?android:attr/textColorTertiary" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> @@ -369,6 +370,7 @@ android:importantForAccessibility="no" android:textSize="?attr/status_text_medium" android:visibility="gone" + app:drawableTint="?android:attr/textColorTertiary" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/status_media_label_0" /> @@ -382,6 +384,7 @@ android:importantForAccessibility="no" android:textSize="?attr/status_text_medium" android:visibility="gone" + app:drawableTint="?android:attr/textColorTertiary" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/status_media_label_1" /> @@ -395,6 +398,7 @@ android:importantForAccessibility="no" android:textSize="?attr/status_text_medium" android:visibility="gone" + app:drawableTint="?android:attr/textColorTertiary" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/status_media_label_2" /> diff --git a/app/src/main/res/layout/item_tab_preference.xml b/app/src/main/res/layout/item_tab_preference.xml index b0926cead..9eb164c3e 100644 --- a/app/src/main/res/layout/item_tab_preference.xml +++ b/app/src/main/res/layout/item_tab_preference.xml @@ -32,6 +32,7 @@ android:paddingBottom="8dp" android:textColor="?android:attr/textColorSecondary" android:textSize="?attr/status_text_large" + app:drawableTint="?android:attr/textColorSecondary" app:layout_constraintBottom_toTopOf="@id/chipGroup" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toEndOf="@id/imageView" diff --git a/app/src/main/res/layout/item_tab_preference_small.xml b/app/src/main/res/layout/item_tab_preference_small.xml index bee49eb21..15daafe08 100644 --- a/app/src/main/res/layout/item_tab_preference_small.xml +++ b/app/src/main/res/layout/item_tab_preference_small.xml @@ -1,17 +1,19 @@ + android:textSize="?attr/status_text_large" + app:drawableStartCompat="@drawable/ic_home_24dp" + app:drawableTint="?android:attr/textColorSecondary" /> diff --git a/app/src/main/res/layout/view_compose_schedule.xml b/app/src/main/res/layout/view_compose_schedule.xml index b07270f6a..7ae003c47 100644 --- a/app/src/main/res/layout/view_compose_schedule.xml +++ b/app/src/main/res/layout/view_compose_schedule.xml @@ -23,6 +23,7 @@ android:paddingBottom="16dp" android:textColor="?android:textColorTertiary" android:textSize="?attr/status_text_medium" + app:drawableTint="?android:attr/textColorTertiary" app:layout_constraintBottom_toTopOf="@id/invalidScheduleWarning" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="1" @@ -39,11 +40,11 @@ android:paddingBottom="16dp" android:textColor="?android:textColorTertiary" android:textSize="?attr/status_text_medium" + android:visibility="gone" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="1" app:layout_constraintStart_toStartOf="parent" - tools:text="@string/warning_scheduling_interval" - android:visibility="gone" /> + tools:text="@string/warning_scheduling_interval" /> \ No newline at end of file diff --git a/app/src/main/res/values-bn-rBD/strings.xml b/app/src/main/res/values-bn-rBD/strings.xml index e14d254ec..2fb78dd8f 100644 --- a/app/src/main/res/values-bn-rBD/strings.xml +++ b/app/src/main/res/values-bn-rBD/strings.xml @@ -381,7 +381,7 @@ ভোট বন্ধ \'%s এ শেষ হবে\' - " <!-- ১৫ ভোট • ১ ঘন্টা বাকি --> %1$s • %2$s" + %1$s • %2$s ছবি %s এর জন্য ক্রিয়া আপনি কি আপনার সমস্ত বিজ্ঞপ্তি স্থায়ীভাবে মুছে ফেলতে চান\? diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index 79e9564b2..29ef088a8 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -475,11 +475,7 @@ Odkrýt oznámení od %s Odkrýt %s Ztišit @%s\? - - - - - + %s požádal/a aby vás mohl/a sledovat Zobrazit dialogové okno s potvrzením při boostování \ No newline at end of file diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 0170f1673..65592e3ff 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -101,7 +101,7 @@ Akzeptieren Ablehnen Suche - Gespeicherte Beiträge + Entwürfe Beitragssichtbarkeit Inhaltswarnung Emoji @@ -465,4 +465,9 @@ %d St. in %d T. %d J. + Gespeichert! + Private Notiz über diesen Account + Titel der Hauptnavigation verstecken + Im Moment gibt es keine Ankündigungen. + Ankündigungen diff --git a/app/src/main/res/values-eo/strings.xml b/app/src/main/res/values-eo/strings.xml index 97d294544..b45c98472 100644 --- a/app/src/main/res/values-eo/strings.xml +++ b/app/src/main/res/values-eo/strings.xml @@ -164,9 +164,9 @@ Sciigi per vibro Sciigi per lumo Sciigi al mi kiam - menciita - sekvita - viaj mesaĝoj estas diskonigitaj + iu mencias min + iu sekvas min + miaj mesaĝoj estas diskonigitaj miaj mesaĝoj estas stelumitaj Aspekto Temo de la apo @@ -363,7 +363,7 @@ Moviĝi GIF profilbildojn Enketoj Sciigoj pri enketoj kiuj finiĝis - Kradvortoj sen # + Kradvorto sen # Viŝi Filtri Apliki @@ -373,15 +373,14 @@ Agoj por bildo %s %1$s • %2$s - - + %s voĉdono + %s voĉdonoj finiĝos je %s finiĝita Voĉdoni Enketo al kiu vi voĉdonis finiĝis Enketo kiu vi kreis finiĝis - Kaŝitaj domajnoj Kaŝitaj domajnoj Silentigi %s @@ -437,4 +436,50 @@ Vi ne havas iun ajn planitan mesaĝon. Petoj de sekvado Kradvortoj + + %s homo + %s homoj + + Aldoni kradvorton + Sciigoj pri petoj de sekvado + Montri buntajn transirojn por kaŝitaj aŭdovidaĵoj + Kaŝi la sciigojn + Silentigi @%s\? + Bloki @%s\? + Malsilentigi la konversacion + Silentigi la konversacion + Malsilentigi %s + Silentigi sciigojn de %s + Malsilentigi sciigojn de %s + Malsilentigi %s + %s petis sekvi vin + Anoncoj + + %d minuto restas + %d minutoj restas + + + %d sekundo restas + %d sekundoj restas + + + %d horo restas + %d horoj restas + + + %d tago restas + %d tagoj restas + + Pozicio de la ĉefa naviga breto + iu petas sekvi min + Malsupro + Supro + Konservita! + Via privata noto pri ĉi tiu konto + Kaŝi la titolon de la supra ilobreto + Montri antaŭvidojn de ligiloj en tempolinioj + Montri konfirman fenestron antaŭ ol diskonigi + Estas neniu anonco. + Ebligi ŝovumadon por ŝanĝi inter la langetoj + Mastodon havas minimuman intervalon de planado de 5 minutoj. \ No newline at end of file diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 5893f448a..637e47438 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -475,4 +475,8 @@ Silenciar notificaciones desde %s Dejar de silenciar notificaciones desde %s Ocultar el título de la barra de herramientas superior + ¡Guardado! + Tu nota privada acerca de esta cuenta + No hay anuncios. + Anuncios diff --git a/app/src/main/res/values-eu/strings.xml b/app/src/main/res/values-eu/strings.xml index d905fe13b..0d7f5b56c 100644 --- a/app/src/main/res/values-eu/strings.xml +++ b/app/src/main/res/values-eu/strings.xml @@ -450,10 +450,7 @@ Traolak Ez erakutsi jakinarazpenak Desmututu %s - - Pertsona %1 - %2 pertsona - + Ezkutatu goiko tresna-barraren izenburua Erakutsi berrespen-abisua tuta bultzatu aurretik Erakutsi esteken aurrebista denbora-lerroetan diff --git a/app/src/main/res/values-fa/strings.xml b/app/src/main/res/values-fa/strings.xml index 59a968767..54470e167 100644 --- a/app/src/main/res/values-fa/strings.xml +++ b/app/src/main/res/values-fa/strings.xml @@ -93,7 +93,7 @@ پذیرش رد جست‌وجو - پیش‌نویس + پیش‌نویس‌ها نمایانی بوق هشدار محتوا صفحه‌کلید اموجی @@ -148,27 +148,27 @@ فرسته‌هایم تقویت شدند فرسته‌هایم برگزیده شدند ظاهر - تم برنامه + زمینهٔ کاره خط‌ زمانی‌ها - روشن - سیاه + تاریک + روشن سیاه خودکار در غروب مرورگر استفاده از زبانه‌های سفارشی کروم - پنهان کردن دکمه ایجاد هنگام پیمایش + نهفتن دکمهٔ ایجاد، هنگام پیمایش فیلتر کردن خط زمانی زبانه‌ها نمایش تقویت‌ها نمایش پاسخ‌ها بارگیری پیش‌نمایش رسانه - پراکسی - پراکسی HTTP - فعال‌سازی پراکسی HTTP + پیشکار + پیشکار HTTP + به کار انداختن پیشکار HTTP کارساز پیشکار HTTP درگاه پیشکار HTTP محرمانگی پیش‌گزیدهٔ فرسته - همواره رسانه را به عنوان حساس نشانه‌گذاری کن + علامت‌گذاری همیشگی رسانه به عنوان حساس در حال انتشار (همگام با کارساز) ناتوانی در هم‌گام‌سازی تنظیمات عمومی @@ -279,7 +279,7 @@ سنجاق‌شده دامنه‌های نهفته \@%s - این‌حا هیچ‌چیزی نیست. + این‌جا هیچ‌چیزی نیست. برداشتن تقویت برداشتن برگزیدگی حذف و بازنویسی @@ -289,11 +289,11 @@ افزودن زبانه پیوندها اشاره‌ها - هشتگ‌ها + برچسب‌ها گشودن تقویت‌کنندهٔ بوق نمایش تقویت‌ها نمایش برگزیده‌ها - هشتگ‌ها + برچسب‌ها اشاره‌ها پیوندها گشودن رسانه #%d @@ -305,11 +305,11 @@ می‌خواهید این بوق را پاک و بازنویسی کنید؟ نهفتن تمام دامنه پایان نظرسنجی‌ها - صافی‌ها - استفاده از طرح سیستم + پالایه‌ها + استفاده از طراحی سامانه زبان نمایش نشانگر برای بات‌ها - پویانمایی آواتار gif + پویانمایی آواتارهای جیف نظرسنجی‌ها آگاهی‌ها دربارهٔ نظرسنجی‌های پایان‌یافته تاسکی %s @@ -364,7 +364,7 @@ مستقیم نظرسنجی با گزینه‌ها: %1$s، %2$s، %3$s، %4$s؛ %5$s نام فهرست - هشتگ بدون # + برچسب بدون # پاک‌سازی پالایش اعمال @@ -434,15 +434,15 @@ هیچ پیش‌نویسی ندارید. هیچ وضعیت زمان‌بسته‌ای ندارید. ماستودون، بازهٔ زمان‌بندی‌ای با کمینهٔ ۵ دقیقه دارد. - نمایش گفت‌وگوی تأیید پیش از تقویت + نمایش گفت‌وگوی تأیید، پیش از تقویت پیش‌نمایش پیوندها در خط‌زمانی‌ها به کار انداختن اشارهٔ کشیدنی برای تعویض بین زبانه‌ها %s نفر %s نفر - هشتگ‌ها - افزودن هشتگ + برچسب‌ها + افزودن برچسب آگاهی‌ها دربارهٔ درخواست‌های پی‌گیری درخواست‌های پی‌گیری درخواست پی‌گیری @@ -470,4 +470,8 @@ نهفتن عنوان نوارابزار بالایی کنش‌ها برای تصویر %s + ذخیره شد! + یادداشت خصوصیتان دربارهٔ این حساب + هیچ اعلامیه‌ای وجود ندارد. + اعلامیه‌ها diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index a6bb4daae..14c99e673 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -39,7 +39,7 @@ Brouillons Licences \@%s - %s a boosté + %s a partagé Contenu sensible Média caché Cliquer pour voir @@ -49,7 +49,7 @@ Replier Rien ici. Il n’y a aucun pouet ici pour l’instant. Glissez vers le bas pour actualiser ! - %s a boosté votre pouet + %s a partagé votre pouet %s a ajouté votre pouet à ses favoris %s vous suit Signaler @%s @@ -69,8 +69,8 @@ Ne plus suivre Bloquer Débloquer - Cacher les boosts - Afficher les boosts + Cacher les partages + Afficher les partages Signaler Supprimer POUET @@ -109,8 +109,8 @@ Liens Mentions Hashtags - Afficher l’auteur·rice du boost - Afficher les boosts + Afficher l’auteur·rice du partage + Afficher les partages Montrer les favoris Hashtags Mentions @@ -167,10 +167,10 @@ Notifier avec un son Notifier avec une vibration Notifier avec une lumière - Me notifier lorsque + Me notifier quand on me mentionne - On me suit - Mes pouets sont boostés + on vient de me suivre + mes pouets sont partagés mes pouets sont mis en favoris Apparence Thème de l’application @@ -187,7 +187,7 @@ Langue Filtrage des fils Onglets - Afficher les boosts + Afficher les partages Afficher les réponses Montrer les miniatures des médias Proxy @@ -212,8 +212,8 @@ Notifications pour les nouvelles mentions Nouveaux abonnés Notifications pour les nouveaux abonnés - Boosts - Notifications quand vos pouets sont boostés + Partages + Notifications quand vos pouets sont partagés Favoris Notifications quand vos pouets sont mis en favoris %s vous a mentionné @@ -316,8 +316,8 @@ Échec du téléchargement Robot %1$s a déménagé vers : - Booster vers l’audience originale - Annuler le boost + Partager à l’audience originale + Annuler le partage Yuito contient du code et des ressources issus des projets open source suivants : Sous licence Apache (copie ci-dessous) CC-BY 4.0 @@ -335,10 +335,10 @@ %1$s Favoris - %s Boost - %s Boosts + %s Partage + %s Partages - Boosté par + Partagé par Mis en favoris par %1$s %1$s et %2$s @@ -362,7 +362,7 @@ Direct Nom de la liste - Hastags sans # + Hashtag sans # Nettoyer Filtrer Appliquer @@ -376,7 +376,7 @@ Terminé Voter Sondages - Les sondages sont clos + les sondages se terminent Notifications pour les sondages terminés Un sondage que vous avez créé est terminé @@ -403,7 +403,7 @@ Domaines cachés Domaines cachés Masquer %s - %s n’est plus masqué + %s n’est plus masqué·e Masquer le domaine entier L’ensemble d’émojis actuel de Google Continuer @@ -452,28 +452,28 @@ Les fichiers audio doivent avoir moins de 40 Mo. Vous n’avez aucun brouillon. Vous n’avez aucun pouet planifié. - L’intervalle minimum de planification sur Mastodon est de5 minutes. + L’intervalle minimum de planification sur Mastodon est de 5 minutes. Demandes d\'abonnement Bloquer @%s \? - Afficher une boite de confirmation avant de booster - Afficher des aperçus des liens dans les fils + Afficher une fenêtre de confirmation avant de partager + Afficher les aperçus des liens dans les fils %s a demandé à vous suivre Notifications à propos des demandes d’abonnement - Demande d’abonnement + on demande à me suivre Mettre en sourdine @%s \? Enlever la sourdine à la conversation - Silencer la conversation - Activer les gestes de glissement pour passer d’un onglet à l’autre + Masquer la conversation + Activer le glissement pour changer d’onglet Hashtags - Ajouter hashtag + Ajouter un hashtag Afficher des dégradés en couleur pour les médias cachés Bas Haut Position de navigation principale Ne plus masquer %s Cacher les notifications - Silencier les notifications de %s - Ne plus silencier les notifications de %s + Masquer les notifications de %s + Ne plus masquer les notifications de %s Ne plus masquer %s %s personne @@ -484,4 +484,8 @@ %s voix %s voix + Sauvegardé ! + Votre note privée sur ce compte + Il n’y a pas d’annonce. + Annonces diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml index 1853a62fd..e3ce2a277 100644 --- a/app/src/main/res/values-hu/strings.xml +++ b/app/src/main/res/values-hu/strings.xml @@ -472,4 +472,8 @@ Értesítések némításának feloldása tőle %s %s kéri, hogy követhessen Felső eszköztár címének elrejtése + Elmentve! + Saját, mások számára nem látható megjegyzés erről a fiókról + Nincsenek közlemények. + Közlemények diff --git a/app/src/main/res/values-is/strings.xml b/app/src/main/res/values-is/strings.xml index 9ce6c6ccd..4e27ac529 100644 --- a/app/src/main/res/values-is/strings.xml +++ b/app/src/main/res/values-is/strings.xml @@ -415,8 +415,8 @@ Fylgjendabeiðnir Myllumerki - %1$s Eftirlæti - %1$s Eftirlæti + %1$s eftirlæti + %1$s eftirlæti %s Endurbirting @@ -438,4 +438,33 @@ %d dagur eftir %d dagar eftir + Vistað! + Þí eigin einkaathugasemd um þennan aðgang + Fela titil á verkfærastikunni efst + Birta staðfestingarglugga áður en endurbirting fer fram + Birta forskoðun tengla á tímalínum + Það eru engar tilkynningar. + Virkja strokuhreyfingu til að skipta milli flipa + + %s aðili + %s aðilar + + Bæta við myllumerki + Tilkynningar um fylgjendabeiðnir + Neðst + Efst + Aðalstaða leiðsagnar + Birta litstigla í stað falins myndefnis + beiðni um að fylgja + Fela tilkynningar + Þagga niður í @%s\? + Loka á @%s\? + Hætta að þagga niður í samtölum + Þagga niður í samtölum + Afþagga %s + Þagga tilkynningar frá %s + Afþagga tilkynningar frá %s + Afþagga %s + %s bað um að fylgjast með þér + Tilkynningar \ No newline at end of file diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 5c2576e9a..7ccd04276 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -414,8 +414,8 @@ %d minuti rimasti - %d secondo - %d secondi + %d secondo rimasto + %d secondi rimasti Continua Indietro @@ -464,4 +464,23 @@ La dimensione dei file audio deve essere inferiore a 40 MB. Smetti di silenziare %s Richieste di seguirti + Salvato! + La tua nota privata su questo account + Nascondi il titolo della barra degli strumenti in alto + Mostra la finestra di dialogo di conferma prima del boosting + Mostra le anteprime dei collegamenti nelle sequenze temporali + Mastodon ha un intervallo minimo di programmazione di 5 minuti. + Non ci sono annunci. + Non hai stati pianificati. + Abilita il gesto di scorrimento per passare da una scheda all\'altra + Notifiche sulle richieste di essere seguiti + Parte inferiore + In cima + Posizione di navigazione principale + Mostra sfumature colorate per i media nascosti + Nascondi notifiche + Disattiva le notifiche da %s + Riattiva le notifiche da %s + Annunci + Richieste di seguirti \ No newline at end of file diff --git a/app/src/main/res/values-no-rNB/strings.xml b/app/src/main/res/values-no-rNB/strings.xml index cf038d992..cbdb4fedc 100644 --- a/app/src/main/res/values-no-rNB/strings.xml +++ b/app/src/main/res/values-no-rNB/strings.xml @@ -465,4 +465,6 @@ Skjul tittelen på den øverste verktøylinjen Lagret! Ditt private notat om denne kontoen + Det er ingen kunngjøringer. + Kunngjøringer \ No newline at end of file diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 5e4427a82..0c4830ddf 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -500,4 +500,9 @@ Заблокировать уведомления от %s Получать уведомления от %s Разблокировать %s + Сохранено! + Ваша личная заметка об этой учётной записи + Скрыть заголовок в верхней панели + Объявлений нет. + Объявления \ No newline at end of file diff --git a/app/src/main/res/values-sa/strings.xml b/app/src/main/res/values-sa/strings.xml index 5c71c35a9..a322838e8 100644 --- a/app/src/main/res/values-sa/strings.xml +++ b/app/src/main/res/values-sa/strings.xml @@ -369,7 +369,6 @@ जालस्थानप्रदर्शनं समयतालिकायां दर्शयतु मास्टोडोने पञ्चनिमेषपरिमितो न्यूनतमः कालबद्धसमयः । न ते कालबद्धदौत्यानि सन्ति । - प्रकटनान्वेषणे विफलता सम्पाद्यताम् मतम् %d बहूनि मतानि diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index 9c2f8d75e..3907fae3c 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -480,4 +480,8 @@ Dölj aviseringar Tysta aviseringar från %s Aktivera aviseringar från %s + Sparat! + Din privata notering om detta kontot + Det finns inga meddelanden. + Meddelanden \ No newline at end of file diff --git a/app/src/main/res/values-vi/strings.xml b/app/src/main/res/values-vi/strings.xml index d01438b55..e6a93e82c 100644 --- a/app/src/main/res/values-vi/strings.xml +++ b/app/src/main/res/values-vi/strings.xml @@ -39,7 +39,7 @@ Không tìm thấy trình duyệt web. Tài khoản không đúng Không được để trống. - Không có Internet! Xin kiểm tra kết nối và thử lại! + Rớt mạng! Xin kiểm tra kết nối và thử lại! Đã có lỗi xảy ra. Máy chủ này không cấp quyền truy cập. Danh sách @@ -48,7 +48,7 @@ Làm tươi Tìm kiếm Trang cá nhân - Riêng bạn + Tài khoản Cài đặt Đăng xuất Xong @@ -97,7 +97,7 @@ Tải về Chia sẻ với tư cách … Mở với tư cách %s - Sao chép URL + Chép URL Đang tải %1$s Mở tập tin #%d Links @@ -174,7 +174,7 @@ Mở rộng Hiển thị Nội dung bị ẩn - Nội dung nhạy cảm + Nhạy cảm %s chia sẻ \@%s Giấy phép @@ -236,7 +236,7 @@ Thông báo Nhắn tin: Chỉ người được nhắc tới mới thấy Người theo dõi: Ai đã theo dõi mới xem được - Mở: Công khai, không hiện trên bảng tin + Riêng tư: Không hiện trên bảng tin Công khai: Mọi người đều có thể thấy Ẩn @%s\? Chặn @%s\? @@ -253,20 +253,20 @@ Nhỏ Kích thức phông chữ Người theo dõi - Mở + Riêng tư Công khai Dưới màn hình Trên màn hình Vị trí menu Đồng bộ hoá thất bại Đăng (đồng bộ với máy chủ) - Luôn đánh dấu nội dung là nhạy cảm + Tài khoản nhạy cảm Trạng thái tút mặc định - HTTP proxy server - HTTP proxy port - Bật HTTP proxy - HTTP proxy - Proxy + Máy chủ proxy + Cổng + Bật proxy + Dùng proxy + Vượt tường lửa Thông báo khi của bạn được chia sẻ Chia sẻ Thông báo về lượt yêu cầu theo dõi @@ -278,7 +278,7 @@ Powered by Tusky Tusky %s Tài khoản bị khóa - Thông báo khi những cuộc bình chọn kết thúc + Thông báo khi một cuộc bình chọn kết thúc Bình chọn Thông báo khi ai đó thích tút của bạn Lượt thích @@ -326,7 +326,7 @@ 30 phút 5 phút Bình chọn - Vuốt để chuyển qua lại giữa các tab + Vuốt qua lại giữa các tab Hiện bộ lọc thông báo Không thể tìm thấy Người @@ -350,7 +350,7 @@ %d ngày nữa kết thúc Cuộc bình chọn bạn tạo đã kết thúc - Cuộc bình chọn bạn tham gia đã kết thúc + Cuộc bình chọn của bạn đã kết thúc Bình chọn Kết thúc kết thúc lúc %s @@ -358,9 +358,9 @@ %s người - %s phiếu + %s người - %1$s • %2$s + %1$s • %2$s Mô tả cho hình %s Viết Viết tút @@ -373,10 +373,10 @@ Không cần dấu # Thêm hashtag Tên danh sách - Những lựa chọn: %1$s, %2$s, %3$s, %4$s; %5$s + Lượt bình chọn: %1$s, %2$s, %3$s, %4$s; %5$s Tin nhắn Người theo dõi - Mở + Riêng tư Công khai Đã lưu Đã thích @@ -455,4 +455,8 @@ Bỏ ẩn %s Bỏ ẩn %s Ẩn tiêu đề tab + Đã lưu! + Ghi chú của bạn + Chưa có thông báo. + Tin tức \ No newline at end of file diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index c4a9c9886..bd147cc59 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -477,8 +477,8 @@ %s 请求关注你 导航栏位置 隐藏顶部工具栏标题 - - %s 人 - - + 本站暂无公告。 + 公告 + 已保存 + 此账号的备注 diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 648c7d4c5..412541f16 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -81,6 +81,8 @@ @style/Widget.MaterialComponents.Chip.Choice + @style/TuskyPreferenceTheme + @color/colorInfo @@ -105,6 +107,10 @@ 3dp + +