From 78b5aa8baf0c34fb5ed00742ec3174dc5bb33fa3 Mon Sep 17 00:00:00 2001 From: Konrad Pozniak Date: Tue, 22 Oct 2019 21:18:20 +0200 Subject: [PATCH] Upgrade api level to Android 10, implement new sharing api (#1537) * upgrade api level to Android 10, resolve compile errors * use androidx.preference.PreferenceManager instead of deprecated platform class * add hyphenation to important TextViews * setBottomSheetCallback -> addBottomSheetCallback * implement new sharing api * improve TuskyTileService so it shows account picker when multiple accounts are present * delete unused AccountChooserService * fix test * improve ShareShortcutHelper * remove debug log statement * improve image loading fallback behavior in ShareShortcutHelper * improve behavior on foldable devices --- app/build.gradle | 7 +- app/src/blue/res/xml-v25/shortcuts.xml | 20 ---- app/src/green/res/xml-v25/shortcuts.xml | 20 ---- app/src/main/AndroidManifest.xml | 20 ++-- .../keylesspalace/tusky/AccountActivity.kt | 2 +- .../tusky/AccountsInListFragment.kt | 3 +- .../com/keylesspalace/tusky/BaseActivity.java | 2 +- .../tusky/BottomSheetActivity.kt | 2 +- .../com/keylesspalace/tusky/MainActivity.java | 18 +++- .../tusky/PreferencesActivity.kt | 9 +- .../keylesspalace/tusky/TuskyApplication.java | 2 +- .../keylesspalace/tusky/ViewMediaActivity.kt | 2 +- .../tusky/adapter/AccountSelectionAdapter.kt | 3 +- .../tusky/adapter/AccountViewHolder.java | 6 +- .../tusky/adapter/BlocksAdapter.java | 8 +- .../tusky/adapter/FollowRequestsAdapter.java | 8 +- .../tusky/adapter/MutesAdapter.java | 8 +- .../conversation/ConversationViewHolder.java | 2 +- .../conversation/ConversationsFragment.kt | 2 +- .../fragments/ReportStatusesFragment.kt | 2 +- .../fragments/SearchStatusesFragment.kt | 5 +- .../com/keylesspalace/tusky/di/AppModule.kt | 2 +- .../tusky/fragment/NotificationsFragment.java | 2 +- .../tusky/fragment/TimelineFragment.java | 36 +++---- .../tusky/fragment/ViewThreadFragment.java | 2 +- .../tusky/service/AccountChooserService.kt | 65 ----------- ...kyTileService.java => TuskyTileService.kt} | 33 +++--- .../keylesspalace/tusky/util/LinkHelper.java | 11 +- .../keylesspalace/tusky/util/LocaleManager.kt | 5 +- .../tusky/util/NotificationHelper.java | 1 + .../keylesspalace/tusky/util/OkHttpUtils.java | 5 +- .../tusky/util/ShareShortcutHelper.kt | 101 ++++++++++++++++++ app/src/main/res/layout/activity_about.xml | 5 +- app/src/main/res/layout/activity_account.xml | 4 +- .../main/res/layout/fragment_view_image.xml | 15 +-- .../main/res/layout/fragment_view_video.xml | 3 +- app/src/main/res/layout/item_status.xml | 2 + .../main/res/layout/item_status_detailed.xml | 2 + .../res/layout/item_status_notification.xml | 73 ++++++------- app/src/main/res/values/dimens.xml | 3 + app/src/main/res/xml/share_shortcuts.xml | 8 ++ .../tusky/ComposeActivityTest.kt | 2 +- .../com/keylesspalace/tusky/FilterTest.kt | 2 +- .../com/keylesspalace/tusky/SpanUtilsTest.kt | 11 +- .../keylesspalace/tusky/util/RickRollTest.kt | 2 +- .../tusky/util/SmartLengthInputFilterTest.kt | 2 +- 46 files changed, 283 insertions(+), 265 deletions(-) delete mode 100644 app/src/blue/res/xml-v25/shortcuts.xml delete mode 100644 app/src/green/res/xml-v25/shortcuts.xml delete mode 100644 app/src/main/java/com/keylesspalace/tusky/service/AccountChooserService.kt rename app/src/main/java/com/keylesspalace/tusky/service/{TuskyTileService.java => TuskyTileService.kt} (50%) create mode 100644 app/src/main/java/com/keylesspalace/tusky/util/ShareShortcutHelper.kt create mode 100644 app/src/main/res/xml/share_shortcuts.xml diff --git a/app/build.gradle b/app/build.gradle index 45f98aadb..a63d95dc5 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -13,11 +13,11 @@ def getGitSha = { -> } android { - compileSdkVersion 28 + compileSdkVersion 29 defaultConfig { applicationId "com.keylesspalace.tusky" minSdkVersion 21 - targetSdkVersion 28 + targetSdkVersion 29 versionCode 68 versionName "9.1" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" @@ -105,6 +105,7 @@ dependencies { implementation 'androidx.exifinterface:exifinterface:1.0.0' implementation 'androidx.cardview:cardview:1.0.0' implementation 'androidx.preference:preference:1.1.0' + implementation 'androidx.sharetarget:sharetarget:1.0.0-beta01' implementation "com.squareup.retrofit2:retrofit:$retrofitVersion" implementation "com.squareup.retrofit2:converter-gson:$retrofitVersion" implementation "com.squareup.retrofit2:adapter-rxjava2:$retrofitVersion" @@ -136,7 +137,7 @@ dependencies { implementation "com.google.dagger:dagger-android:$daggerVersion" implementation "com.google.dagger:dagger-android-support:$daggerVersion" kapt "com.google.dagger:dagger-android-processor:$daggerVersion" - testImplementation 'org.robolectric:robolectric:4.3' + testImplementation 'org.robolectric:robolectric:4.3.1' testImplementation 'org.mockito:mockito-inline:3.1.0' testImplementation 'com.nhaarman.mockitokotlin2:mockito-kotlin:2.2.0' androidTestImplementation('androidx.test.espresso:espresso-core:3.1.1', { diff --git a/app/src/blue/res/xml-v25/shortcuts.xml b/app/src/blue/res/xml-v25/shortcuts.xml deleted file mode 100644 index d0aaa2e80..000000000 --- a/app/src/blue/res/xml-v25/shortcuts.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/app/src/green/res/xml-v25/shortcuts.xml b/app/src/green/res/xml-v25/shortcuts.xml deleted file mode 100644 index 130274fae..000000000 --- a/app/src/green/res/xml-v25/shortcuts.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index edc4856e4..ea510482a 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -31,7 +31,8 @@ + android:resource="@xml/share_shortcuts" /> + + android:configChanges="orientation|screenSize|keyboardHidden|screenLayout|smallestScreenSize"> @@ -91,7 +92,8 @@ + android:value="androidx.sharetarget.ChooserTargetServiceCompat" /> + + android:configChanges="orientation|screenSize|keyboardHidden|screenLayout|smallestScreenSize" /> @@ -153,16 +155,8 @@ + - - - - - (context, R.layout.item_autocomplete_account) { diff --git a/app/src/main/java/com/keylesspalace/tusky/adapter/AccountViewHolder.java b/app/src/main/java/com/keylesspalace/tusky/adapter/AccountViewHolder.java index 119669a99..edd93082b 100644 --- a/app/src/main/java/com/keylesspalace/tusky/adapter/AccountViewHolder.java +++ b/app/src/main/java/com/keylesspalace/tusky/adapter/AccountViewHolder.java @@ -1,13 +1,13 @@ package com.keylesspalace.tusky.adapter; -import androidx.recyclerview.widget.RecyclerView; - import android.content.SharedPreferences; -import android.preference.PreferenceManager; import android.view.View; import android.widget.ImageView; import android.widget.TextView; +import androidx.preference.PreferenceManager; +import androidx.recyclerview.widget.RecyclerView; + import com.keylesspalace.tusky.R; import com.keylesspalace.tusky.entity.Account; import com.keylesspalace.tusky.interfaces.AccountActionListener; diff --git a/app/src/main/java/com/keylesspalace/tusky/adapter/BlocksAdapter.java b/app/src/main/java/com/keylesspalace/tusky/adapter/BlocksAdapter.java index cc861df24..70a44ba8c 100644 --- a/app/src/main/java/com/keylesspalace/tusky/adapter/BlocksAdapter.java +++ b/app/src/main/java/com/keylesspalace/tusky/adapter/BlocksAdapter.java @@ -15,10 +15,6 @@ package com.keylesspalace.tusky.adapter; -import androidx.annotation.NonNull; -import androidx.recyclerview.widget.RecyclerView; - -import android.preference.PreferenceManager; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -26,6 +22,10 @@ import android.widget.ImageButton; import android.widget.ImageView; import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.preference.PreferenceManager; +import androidx.recyclerview.widget.RecyclerView; + import com.keylesspalace.tusky.R; import com.keylesspalace.tusky.entity.Account; import com.keylesspalace.tusky.interfaces.AccountActionListener; diff --git a/app/src/main/java/com/keylesspalace/tusky/adapter/FollowRequestsAdapter.java b/app/src/main/java/com/keylesspalace/tusky/adapter/FollowRequestsAdapter.java index a82a10ea4..37f09f019 100644 --- a/app/src/main/java/com/keylesspalace/tusky/adapter/FollowRequestsAdapter.java +++ b/app/src/main/java/com/keylesspalace/tusky/adapter/FollowRequestsAdapter.java @@ -15,10 +15,6 @@ package com.keylesspalace.tusky.adapter; -import androidx.annotation.NonNull; -import androidx.recyclerview.widget.RecyclerView; - -import android.preference.PreferenceManager; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -26,6 +22,10 @@ import android.widget.ImageButton; import android.widget.ImageView; import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.preference.PreferenceManager; +import androidx.recyclerview.widget.RecyclerView; + import com.keylesspalace.tusky.R; import com.keylesspalace.tusky.entity.Account; import com.keylesspalace.tusky.interfaces.AccountActionListener; diff --git a/app/src/main/java/com/keylesspalace/tusky/adapter/MutesAdapter.java b/app/src/main/java/com/keylesspalace/tusky/adapter/MutesAdapter.java index 5f494658b..a7d145454 100644 --- a/app/src/main/java/com/keylesspalace/tusky/adapter/MutesAdapter.java +++ b/app/src/main/java/com/keylesspalace/tusky/adapter/MutesAdapter.java @@ -1,9 +1,5 @@ package com.keylesspalace.tusky.adapter; -import androidx.annotation.NonNull; -import androidx.recyclerview.widget.RecyclerView; - -import android.preference.PreferenceManager; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -11,6 +7,10 @@ import android.widget.ImageButton; import android.widget.ImageView; import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.preference.PreferenceManager; +import androidx.recyclerview.widget.RecyclerView; + import com.keylesspalace.tusky.R; import com.keylesspalace.tusky.entity.Account; import com.keylesspalace.tusky.interfaces.AccountActionListener; diff --git a/app/src/main/java/com/keylesspalace/tusky/components/conversation/ConversationViewHolder.java b/app/src/main/java/com/keylesspalace/tusky/components/conversation/ConversationViewHolder.java index db2dc2cc2..268fd5b78 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/conversation/ConversationViewHolder.java +++ b/app/src/main/java/com/keylesspalace/tusky/components/conversation/ConversationViewHolder.java @@ -16,7 +16,6 @@ package com.keylesspalace.tusky.components.conversation; import android.content.Context; -import android.preference.PreferenceManager; import android.text.InputFilter; import android.text.TextUtils; import android.view.View; @@ -24,6 +23,7 @@ import android.widget.ImageView; import android.widget.TextView; import android.widget.ToggleButton; +import androidx.preference.PreferenceManager; import androidx.recyclerview.widget.RecyclerView; import com.keylesspalace.tusky.R; diff --git a/app/src/main/java/com/keylesspalace/tusky/components/conversation/ConversationsFragment.kt b/app/src/main/java/com/keylesspalace/tusky/components/conversation/ConversationsFragment.kt index 7799688ec..b6eef4351 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/conversation/ConversationsFragment.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/conversation/ConversationsFragment.kt @@ -17,13 +17,13 @@ package com.keylesspalace.tusky.components.conversation import android.content.Intent import android.os.Bundle -import android.preference.PreferenceManager import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelProviders import androidx.paging.PagedList +import androidx.preference.PreferenceManager import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.SimpleItemAnimator diff --git a/app/src/main/java/com/keylesspalace/tusky/components/report/fragments/ReportStatusesFragment.kt b/app/src/main/java/com/keylesspalace/tusky/components/report/fragments/ReportStatusesFragment.kt index 2fc35d11b..59d15517d 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/report/fragments/ReportStatusesFragment.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/report/fragments/ReportStatusesFragment.kt @@ -16,7 +16,6 @@ package com.keylesspalace.tusky.components.report.fragments import android.os.Bundle -import android.preference.PreferenceManager import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -26,6 +25,7 @@ import androidx.fragment.app.Fragment import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelProviders import androidx.paging.PagedList +import androidx.preference.PreferenceManager import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.SimpleItemAnimator diff --git a/app/src/main/java/com/keylesspalace/tusky/components/search/fragments/SearchStatusesFragment.kt b/app/src/main/java/com/keylesspalace/tusky/components/search/fragments/SearchStatusesFragment.kt index 1362db884..2829e6b68 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/search/fragments/SearchStatusesFragment.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/search/fragments/SearchStatusesFragment.kt @@ -24,7 +24,6 @@ import android.content.Intent import android.content.pm.PackageManager import android.net.Uri import android.os.Environment -import android.preference.PreferenceManager import android.util.Log import android.view.View import android.widget.Toast @@ -36,6 +35,7 @@ import androidx.lifecycle.Lifecycle import androidx.lifecycle.LiveData import androidx.paging.PagedList import androidx.paging.PagedListAdapter +import androidx.preference.PreferenceManager import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager import com.keylesspalace.tusky.* @@ -277,8 +277,7 @@ class SearchStatusesFragment : SearchFragment { val clipboard = activity!!.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager - val clip = ClipData.newPlainText(null, statusUrl) - clipboard.primaryClip = clip + clipboard.setPrimaryClip(ClipData.newPlainText(null, statusUrl)) return@setOnMenuItemClickListener true } R.id.status_open_as -> { diff --git a/app/src/main/java/com/keylesspalace/tusky/di/AppModule.kt b/app/src/main/java/com/keylesspalace/tusky/di/AppModule.kt index 1cbe2190f..bbc870614 100644 --- a/app/src/main/java/com/keylesspalace/tusky/di/AppModule.kt +++ b/app/src/main/java/com/keylesspalace/tusky/di/AppModule.kt @@ -19,8 +19,8 @@ package com.keylesspalace.tusky.di import android.app.Application import android.content.Context import android.content.SharedPreferences -import android.preference.PreferenceManager import androidx.localbroadcastmanager.content.LocalBroadcastManager +import androidx.preference.PreferenceManager import com.keylesspalace.tusky.TuskyApplication import com.keylesspalace.tusky.appstore.EventHub import com.keylesspalace.tusky.appstore.EventHubImpl diff --git a/app/src/main/java/com/keylesspalace/tusky/fragment/NotificationsFragment.java b/app/src/main/java/com/keylesspalace/tusky/fragment/NotificationsFragment.java index b888d8cbf..4150a6ee9 100644 --- a/app/src/main/java/com/keylesspalace/tusky/fragment/NotificationsFragment.java +++ b/app/src/main/java/com/keylesspalace/tusky/fragment/NotificationsFragment.java @@ -20,7 +20,6 @@ import android.content.Context; import android.content.DialogInterface; import android.content.SharedPreferences; import android.os.Bundle; -import android.preference.PreferenceManager; import android.util.Log; import android.util.SparseBooleanArray; import android.view.LayoutInflater; @@ -39,6 +38,7 @@ import androidx.arch.core.util.Function; import androidx.coordinatorlayout.widget.CoordinatorLayout; import androidx.core.util.Pair; import androidx.lifecycle.Lifecycle; +import androidx.preference.PreferenceManager; import androidx.recyclerview.widget.AsyncDifferConfig; import androidx.recyclerview.widget.AsyncListDiffer; import androidx.recyclerview.widget.DiffUtil; 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 44937d150..2431bc920 100644 --- a/app/src/main/java/com/keylesspalace/tusky/fragment/TimelineFragment.java +++ b/app/src/main/java/com/keylesspalace/tusky/fragment/TimelineFragment.java @@ -19,13 +19,29 @@ import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; -import android.preference.PreferenceManager; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ProgressBar; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.arch.core.util.Function; +import androidx.core.util.Pair; +import androidx.core.widget.ContentLoadingProgressBar; +import androidx.lifecycle.Lifecycle; +import androidx.preference.PreferenceManager; +import androidx.recyclerview.widget.AsyncDifferConfig; +import androidx.recyclerview.widget.AsyncListDiffer; +import androidx.recyclerview.widget.DiffUtil; +import androidx.recyclerview.widget.DividerItemDecoration; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.ListUpdateCallback; +import androidx.recyclerview.widget.RecyclerView; +import androidx.recyclerview.widget.SimpleItemAnimator; +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; + import com.google.android.material.floatingactionbutton.FloatingActionButton; import com.keylesspalace.tusky.AccountListActivity; import com.keylesspalace.tusky.BaseActivity; @@ -77,22 +93,6 @@ import java.util.concurrent.TimeUnit; import javax.inject.Inject; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.arch.core.util.Function; -import androidx.core.util.Pair; -import androidx.core.widget.ContentLoadingProgressBar; -import androidx.lifecycle.Lifecycle; -import androidx.recyclerview.widget.AsyncDifferConfig; -import androidx.recyclerview.widget.AsyncListDiffer; -import androidx.recyclerview.widget.DiffUtil; -import androidx.recyclerview.widget.DividerItemDecoration; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.ListUpdateCallback; -import androidx.recyclerview.widget.RecyclerView; -import androidx.recyclerview.widget.SimpleItemAnimator; -import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; - import at.connyduck.sparkbutton.helpers.Utils; import io.reactivex.Observable; import io.reactivex.android.schedulers.AndroidSchedulers; @@ -307,7 +307,7 @@ public class TimelineFragment extends SFragment implements Iterator> iterator = this.statuses.iterator(); while (iterator.hasNext()) { Either item = iterator.next(); - if(item.isRight()) { + if (item.isRight()) { Status status = item.asRight(); if (status.getId().length() < topId.length() || status.getId().compareTo(topId) < 0) { diff --git a/app/src/main/java/com/keylesspalace/tusky/fragment/ViewThreadFragment.java b/app/src/main/java/com/keylesspalace/tusky/fragment/ViewThreadFragment.java index 825cd23ce..b047064c5 100644 --- a/app/src/main/java/com/keylesspalace/tusky/fragment/ViewThreadFragment.java +++ b/app/src/main/java/com/keylesspalace/tusky/fragment/ViewThreadFragment.java @@ -19,7 +19,6 @@ import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; -import android.preference.PreferenceManager; import android.text.TextUtils; import android.util.Log; import android.view.LayoutInflater; @@ -31,6 +30,7 @@ import androidx.annotation.Nullable; import androidx.arch.core.util.Function; import androidx.core.util.Pair; import androidx.lifecycle.Lifecycle; +import androidx.preference.PreferenceManager; import androidx.recyclerview.widget.DividerItemDecoration; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; diff --git a/app/src/main/java/com/keylesspalace/tusky/service/AccountChooserService.kt b/app/src/main/java/com/keylesspalace/tusky/service/AccountChooserService.kt deleted file mode 100644 index b97ca3ee3..000000000 --- a/app/src/main/java/com/keylesspalace/tusky/service/AccountChooserService.kt +++ /dev/null @@ -1,65 +0,0 @@ -/* Copyright 2019 Levi Bard - * - * 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.service - -import android.annotation.TargetApi -import android.content.ComponentName -import android.content.IntentFilter -import android.graphics.drawable.Icon -import android.os.Bundle -import android.service.chooser.ChooserTarget -import android.service.chooser.ChooserTargetService -import android.text.TextUtils -import com.bumptech.glide.Glide -import com.keylesspalace.tusky.R -import com.keylesspalace.tusky.TuskyApplication -import com.keylesspalace.tusky.db.AccountManager -import com.keylesspalace.tusky.di.Injectable -import com.keylesspalace.tusky.util.NotificationHelper - - -@TargetApi(23) -class AccountChooserService : ChooserTargetService(), Injectable { - - // cannot inject here, it crashes on APIs < 23 - lateinit var accountManager: AccountManager - - override fun onCreate() { - super.onCreate() - accountManager = (application as TuskyApplication).serviceLocator.get(AccountManager::class.java) - } - - override fun onGetChooserTargets(targetActivityName: ComponentName?, intentFilter: IntentFilter?): MutableList { - val targets = mutableListOf() - for (account in accountManager.getAllAccountsOrderedByActive()) { - val icon: Icon = if (TextUtils.isEmpty(account.profilePictureUrl)) { - Icon.createWithResource(applicationContext, R.drawable.avatar_default) - } else { - val bmp = Glide.with(this) - .asBitmap() - .load(account.profilePictureUrl) - .error(R.drawable.avatar_default) - .placeholder(R.drawable.avatar_default) - .submit() - Icon.createWithBitmap(bmp.get()) - } - val bundle = Bundle() - bundle.putLong(NotificationHelper.ACCOUNT_ID, account.id) - targets.add(ChooserTarget(account.displayName, icon, 1.0f, targetActivityName, bundle)) - } - return targets - } -} diff --git a/app/src/main/java/com/keylesspalace/tusky/service/TuskyTileService.java b/app/src/main/java/com/keylesspalace/tusky/service/TuskyTileService.kt similarity index 50% rename from app/src/main/java/com/keylesspalace/tusky/service/TuskyTileService.java rename to app/src/main/java/com/keylesspalace/tusky/service/TuskyTileService.kt index 6aad5d228..f064089da 100644 --- a/app/src/main/java/com/keylesspalace/tusky/service/TuskyTileService.java +++ b/app/src/main/java/com/keylesspalace/tusky/service/TuskyTileService.kt @@ -1,4 +1,4 @@ -/* Copyright 2017 Andrew Dawson +/* Copyright 2019 Tusky Contributors * * This file is a part of Tusky. * @@ -13,29 +13,28 @@ * You should have received a copy of the GNU General Public License along with Tusky; if not, * see . */ -package com.keylesspalace.tusky.service; +package com.keylesspalace.tusky.service -import android.annotation.TargetApi; -import android.content.Intent; -import android.service.quicksettings.TileService; +import android.annotation.TargetApi +import android.content.Intent +import android.service.quicksettings.TileService -import com.keylesspalace.tusky.ComposeActivity; +import com.keylesspalace.tusky.MainActivity /** - * Small Addition that adds in a QuickSettings tile that opens the Compose activity when clicked - * Created by ztepps on 4/3/17. + * Small Addition that adds in a QuickSettings tile + * opens the Compose activity or shows an account selector when multiple accounts are present */ @TargetApi(24) -public class TuskyTileService extends TileService { - public TuskyTileService() { - super(); - } +class TuskyTileService : TileService() { - @Override - public void onClick() { - Intent intent = new Intent(this, ComposeActivity.class); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - startActivityAndCollapse(intent); + override fun onClick() { + val intent = Intent(this, MainActivity::class.java).apply { + addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + action = Intent.ACTION_SEND + type = "text/plain" + } + startActivityAndCollapse(intent) } } diff --git a/app/src/main/java/com/keylesspalace/tusky/util/LinkHelper.java b/app/src/main/java/com/keylesspalace/tusky/util/LinkHelper.java index 2505649db..606a36a9b 100644 --- a/app/src/main/java/com/keylesspalace/tusky/util/LinkHelper.java +++ b/app/src/main/java/com/keylesspalace/tusky/util/LinkHelper.java @@ -19,11 +19,6 @@ import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Intent; import android.net.Uri; -import android.preference.PreferenceManager; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.browser.customtabs.CustomTabsIntent; import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.method.LinkMovementMethod; @@ -33,11 +28,15 @@ import android.util.Log; import android.view.View; import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.browser.customtabs.CustomTabsIntent; +import androidx.preference.PreferenceManager; + import com.keylesspalace.tusky.R; import com.keylesspalace.tusky.entity.Status; import com.keylesspalace.tusky.interfaces.LinkListener; -import java.lang.CharSequence; import java.net.URI; import java.net.URISyntaxException; diff --git a/app/src/main/java/com/keylesspalace/tusky/util/LocaleManager.kt b/app/src/main/java/com/keylesspalace/tusky/util/LocaleManager.kt index 3cb34e856..4a80bca20 100644 --- a/app/src/main/java/com/keylesspalace/tusky/util/LocaleManager.kt +++ b/app/src/main/java/com/keylesspalace/tusky/util/LocaleManager.kt @@ -18,9 +18,8 @@ package com.keylesspalace.tusky.util import android.content.Context import android.content.SharedPreferences import android.content.res.Configuration -import android.preference.PreferenceManager - -import java.util.Locale +import androidx.preference.PreferenceManager +import java.util.* class LocaleManager(context: Context) { diff --git a/app/src/main/java/com/keylesspalace/tusky/util/NotificationHelper.java b/app/src/main/java/com/keylesspalace/tusky/util/NotificationHelper.java index 39f19c30a..4e0d298d7 100644 --- a/app/src/main/java/com/keylesspalace/tusky/util/NotificationHelper.java +++ b/app/src/main/java/com/keylesspalace/tusky/util/NotificationHelper.java @@ -295,6 +295,7 @@ public class NotificationHelper { .setColor(BuildConfig.DEBUG ? Color.parseColor("#19A341") : ContextCompat.getColor(context, R.color.tusky_blue)) .setGroup(account.getAccountId()) .setAutoCancel(true) + .setShortcutId(Long.toString(account.getId())) .setDefaults(0); // So it doesn't ring twice, notify only in Target callback setupPreferences(account, builder); diff --git a/app/src/main/java/com/keylesspalace/tusky/util/OkHttpUtils.java b/app/src/main/java/com/keylesspalace/tusky/util/OkHttpUtils.java index 7647c2c84..22e13e5ec 100644 --- a/app/src/main/java/com/keylesspalace/tusky/util/OkHttpUtils.java +++ b/app/src/main/java/com/keylesspalace/tusky/util/OkHttpUtils.java @@ -18,7 +18,9 @@ package com.keylesspalace.tusky.util; import android.content.Context; import android.content.SharedPreferences; import android.os.Build; -import android.preference.PreferenceManager; + +import androidx.annotation.NonNull; +import androidx.preference.PreferenceManager; import com.keylesspalace.tusky.BuildConfig; @@ -26,7 +28,6 @@ import java.net.InetSocketAddress; import java.net.Proxy; import java.util.concurrent.TimeUnit; -import androidx.annotation.NonNull; import okhttp3.Cache; import okhttp3.Interceptor; import okhttp3.OkHttpClient; diff --git a/app/src/main/java/com/keylesspalace/tusky/util/ShareShortcutHelper.kt b/app/src/main/java/com/keylesspalace/tusky/util/ShareShortcutHelper.kt new file mode 100644 index 000000000..9c0cd0c74 --- /dev/null +++ b/app/src/main/java/com/keylesspalace/tusky/util/ShareShortcutHelper.kt @@ -0,0 +1,101 @@ +/* Copyright 2019 Tusky Contributors + * + * 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 . */ + +@file:JvmName("ShareShortcutHelper") + +package com.keylesspalace.tusky.util + +import android.content.Context +import android.content.Intent +import android.graphics.Bitmap +import android.graphics.Canvas +import android.text.TextUtils +import androidx.core.app.Person +import androidx.core.content.pm.ShortcutInfoCompat +import androidx.core.content.pm.ShortcutManagerCompat +import androidx.core.graphics.drawable.IconCompat +import com.bumptech.glide.Glide +import com.keylesspalace.tusky.MainActivity +import com.keylesspalace.tusky.R +import com.keylesspalace.tusky.db.AccountEntity +import io.reactivex.Single +import io.reactivex.schedulers.Schedulers + +fun updateShortcut(context: Context, account: AccountEntity) { + + Single.fromCallable { + + val innerSize = context.resources.getDimensionPixelSize(R.dimen.adaptive_bitmap_inner_size) + val outerSize = context.resources.getDimensionPixelSize(R.dimen.adaptive_bitmap_outer_size) + + val bmp = if (TextUtils.isEmpty(account.profilePictureUrl)) { + Glide.with(context) + .asBitmap() + .load(R.drawable.avatar_default) + .submit(innerSize, innerSize) + .get() + } else { + Glide.with(context) + .asBitmap() + .load(account.profilePictureUrl) + .error(R.drawable.avatar_default) + .submit(innerSize, innerSize) + .get() + } + + // inset the loaded bitmap inside a 108dp transparent canvas so it looks good as adaptive icon + val outBmp = Bitmap.createBitmap(outerSize, outerSize, Bitmap.Config.ARGB_8888) + + val canvas = Canvas(outBmp) + canvas.drawBitmap(bmp, (outerSize - innerSize).toFloat() / 2f, (outerSize - innerSize).toFloat() / 2f, null) + + val icon = IconCompat.createWithAdaptiveBitmap(outBmp) + + val person = Person.Builder() + .setIcon(icon) + .setName(account.displayName) + .setKey(account.identifier) + .build() + + // This intent will be sent when the user clicks on one of the launcher shortcuts. Intent from share sheet will be different + val intent = Intent(context, MainActivity::class.java).apply { + action = Intent.ACTION_SEND + type = "text/plain" + putExtra(NotificationHelper.ACCOUNT_ID, account.id) + } + + val shortcutInfo = ShortcutInfoCompat.Builder(context, account.id.toString()) + .setIntent(intent) + .setCategories(setOf("com.keylesspalace.tusky.Share")) + .setShortLabel(account.displayName) + .setPerson(person) + .setLongLived(true) + .setIcon(icon) + .build() + + ShortcutManagerCompat.addDynamicShortcuts(context, listOf(shortcutInfo)) + + } + .subscribeOn(Schedulers.io()) + .subscribe() + + +} + +fun removeShortcut(context: Context, account: AccountEntity) { + + ShortcutManagerCompat.removeDynamicShortcuts(context, listOf(account.id.toString())) + +} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_about.xml b/app/src/main/res/layout/activity_about.xml index 4ebaf3945..9bc43d641 100644 --- a/app/src/main/res/layout/activity_about.xml +++ b/app/src/main/res/layout/activity_about.xml @@ -16,8 +16,8 @@ + android:layout_gravity="center" + android:textDirection="anyRtl"> diff --git a/app/src/main/res/layout/fragment_view_image.xml b/app/src/main/res/layout/fragment_view_image.xml index 39bbd9fb6..faf1f806f 100644 --- a/app/src/main/res/layout/fragment_view_image.xml +++ b/app/src/main/res/layout/fragment_view_image.xml @@ -1,7 +1,7 @@ + android:layout_gravity="center" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintRight_toRightOf="parent" + app:layout_constraintTop_toTopOf="parent" /> \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_view_video.xml b/app/src/main/res/layout/fragment_view_video.xml index 0247a9cb3..083bdb20f 100644 --- a/app/src/main/res/layout/fragment_view_video.xml +++ b/app/src/main/res/layout/fragment_view_video.xml @@ -2,9 +2,9 @@ @@ -14,6 +14,7 @@ android:layout_height="wrap_content" android:layout_marginTop="?attr/actionBarSize" android:background="#60000000" + android:hyphenationFrequency="full" android:lineSpacingMultiplier="1.1" android:padding="8dp" android:textAlignment="center" diff --git a/app/src/main/res/layout/item_status.xml b/app/src/main/res/layout/item_status.xml index a0e2b8515..167579dfb 100644 --- a/app/src/main/res/layout/item_status.xml +++ b/app/src/main/res/layout/item_status.xml @@ -105,6 +105,7 @@ android:id="@+id/status_content_warning_description" android:layout_width="0dp" android:layout_height="wrap_content" + android:hyphenationFrequency="full" android:importantForAccessibility="no" android:lineSpacingMultiplier="1.1" android:textColor="?android:textColorPrimary" @@ -145,6 +146,7 @@ android:layout_height="wrap_content" android:layout_marginTop="8dp" android:focusable="true" + android:hyphenationFrequency="full" android:importantForAccessibility="no" android:lineSpacingMultiplier="1.1" android:textColor="?android:textColorPrimary" diff --git a/app/src/main/res/layout/item_status_detailed.xml b/app/src/main/res/layout/item_status_detailed.xml index 8db4d0d9e..6cdc1a40f 100644 --- a/app/src/main/res/layout/item_status_detailed.xml +++ b/app/src/main/res/layout/item_status_detailed.xml @@ -84,6 +84,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="8dp" + android:hyphenationFrequency="full" android:importantForAccessibility="no" android:lineSpacingMultiplier="1.1" android:textColor="?android:textColorPrimary" @@ -120,6 +121,7 @@ android:layout_marginTop="4dp" android:layout_marginBottom="4dp" android:focusable="true" + android:hyphenationFrequency="full" android:importantForAccessibility="no" android:lineSpacingMultiplier="1.1" android:textColor="?android:textColorPrimary" diff --git a/app/src/main/res/layout/item_status_notification.xml b/app/src/main/res/layout/item_status_notification.xml index f9f0a4b6a..94f40c454 100644 --- a/app/src/main/res/layout/item_status_notification.xml +++ b/app/src/main/res/layout/item_status_notification.xml @@ -13,8 +13,8 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" - android:layout_marginBottom="6dp" android:layout_marginTop="8dp" + android:layout_marginBottom="6dp" android:drawablePadding="10dp" android:ellipsize="end" android:gravity="center_vertical" @@ -39,8 +39,8 @@ android:layout_alignParentStart="true" android:ellipsize="end" android:maxLines="1" - android:paddingEnd="@dimen/status_display_name_padding_end" android:paddingStart="0dp" + android:paddingEnd="@dimen/status_display_name_padding_end" android:textAppearance="@android:style/TextAppearance.DeviceDefault.Small" android:textColor="?android:textColorTertiary" android:textSize="?attr/status_text_medium" @@ -51,8 +51,8 @@ android:id="@+id/status_username" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_toEndOf="@id/status_display_name" android:layout_toStartOf="@+id/status_timestamp_info" + android:layout_toEndOf="@id/status_display_name" android:ellipsize="end" android:maxLines="1" android:textColor="?android:textColorTertiary" @@ -77,27 +77,27 @@ android:layout_height="wrap_content" android:layout_below="@id/status_name_bar" android:layout_toEndOf="@id/notification_status_avatar" + android:hyphenationFrequency="full" android:lineSpacingMultiplier="1.1" android:textColor="?android:textColorTertiary" android:textSize="?attr/status_text_medium" tools:text="Example CW text" /> - + android:id="@+id/button_toggle_notification_content" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@id/notification_content" + android:layout_marginTop="4dp" + android:layout_marginBottom="4dp" + android:layout_toEndOf="@id/notification_status_avatar" + android:background="?attr/content_warning_button" + android:minWidth="150dp" + android:minHeight="0dp" + android:paddingLeft="16dp" + android:paddingTop="4dp" + android:paddingRight="16dp" + android:paddingBottom="4dp" + android:textAllCaps="true" + android:textOff="@string/status_content_show_less" + android:textOn="@string/status_content_show_more" + android:textSize="?attr/status_text_medium" + android:visibility="gone" /> @@ -157,7 +158,7 @@ android:id="@+id/notification_notification_avatar" android:layout_width="24dp" android:layout_height="24dp" - android:layout_alignBottom="@+id/notification_status_avatar" - android:layout_alignEnd="@id/notification_status_avatar" /> + android:layout_alignEnd="@id/notification_status_avatar" + android:layout_alignBottom="@+id/notification_status_avatar" /> diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index c2f1bdd91..f8bbe3d48 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -46,4 +46,7 @@ 5dp 12dp + + 72dp + 108dp diff --git a/app/src/main/res/xml/share_shortcuts.xml b/app/src/main/res/xml/share_shortcuts.xml new file mode 100644 index 000000000..54ecd5db1 --- /dev/null +++ b/app/src/main/res/xml/share_shortcuts.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/test/java/com/keylesspalace/tusky/ComposeActivityTest.kt b/app/src/test/java/com/keylesspalace/tusky/ComposeActivityTest.kt index bb924ee4b..c8a06252f 100644 --- a/app/src/test/java/com/keylesspalace/tusky/ComposeActivityTest.kt +++ b/app/src/test/java/com/keylesspalace/tusky/ComposeActivityTest.kt @@ -49,7 +49,7 @@ import retrofit2.Response * Created by charlag on 3/7/18. */ -@Config(application = FakeTuskyApplication::class) +@Config(application = FakeTuskyApplication::class, sdk = [28]) @RunWith(AndroidJUnit4::class) class ComposeActivityTest { diff --git a/app/src/test/java/com/keylesspalace/tusky/FilterTest.kt b/app/src/test/java/com/keylesspalace/tusky/FilterTest.kt index 2e627d965..b7e95dc16 100644 --- a/app/src/test/java/com/keylesspalace/tusky/FilterTest.kt +++ b/app/src/test/java/com/keylesspalace/tusky/FilterTest.kt @@ -24,7 +24,7 @@ import retrofit2.Callback import retrofit2.Response import java.util.* -@Config(application = FakeTuskyApplication::class) +@Config(application = FakeTuskyApplication::class, sdk = [28]) @RunWith(AndroidJUnit4::class) class FilterTest { diff --git a/app/src/test/java/com/keylesspalace/tusky/SpanUtilsTest.kt b/app/src/test/java/com/keylesspalace/tusky/SpanUtilsTest.kt index f90a95e7e..66bf73e80 100644 --- a/app/src/test/java/com/keylesspalace/tusky/SpanUtilsTest.kt +++ b/app/src/test/java/com/keylesspalace/tusky/SpanUtilsTest.kt @@ -100,15 +100,10 @@ class SpanUtilsTest { spans.add(BoundedSpan(what, start, end)) } - override fun getSpans(start: Int, end: Int, type: Class?): Array { - val matching = if (type == null) { - ArrayList() - } else { - spans.filter { it.start >= start && it.end <= end && type.isAssignableFrom(it.span?.javaClass) } + override fun getSpans(start: Int, end: Int, type: Class): Array { + return spans.filter { it.start >= start && it.end <= end && type.isInstance(it)} .map { it.span } - .let { ArrayList(it) } - } - return matching.toArray() as Array + .toTypedArray() as Array } override fun removeSpan(what: Any?) { diff --git a/app/src/test/java/com/keylesspalace/tusky/util/RickRollTest.kt b/app/src/test/java/com/keylesspalace/tusky/util/RickRollTest.kt index 6a6a5d53a..c307e5524 100644 --- a/app/src/test/java/com/keylesspalace/tusky/util/RickRollTest.kt +++ b/app/src/test/java/com/keylesspalace/tusky/util/RickRollTest.kt @@ -11,7 +11,7 @@ import org.junit.runner.RunWith import org.robolectric.Robolectric import org.robolectric.annotation.Config -@Config(application = FakeTuskyApplication::class) +@Config(application = FakeTuskyApplication::class, sdk = [28]) @RunWith(AndroidJUnit4::class) class RickRollTest { private lateinit var activity: Activity diff --git a/app/src/test/java/com/keylesspalace/tusky/util/SmartLengthInputFilterTest.kt b/app/src/test/java/com/keylesspalace/tusky/util/SmartLengthInputFilterTest.kt index f11658b00..acb6cf881 100644 --- a/app/src/test/java/com/keylesspalace/tusky/util/SmartLengthInputFilterTest.kt +++ b/app/src/test/java/com/keylesspalace/tusky/util/SmartLengthInputFilterTest.kt @@ -9,7 +9,7 @@ import org.junit.Test import org.junit.runner.RunWith import org.robolectric.annotation.Config -@Config(application = FakeTuskyApplication::class) +@Config(application = FakeTuskyApplication::class, sdk = [28]) @RunWith(AndroidJUnit4::class) class SmartLengthInputFilterTest {