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
This commit is contained in:
Konrad Pozniak 2019-10-22 21:18:20 +02:00 committed by GitHub
parent 0466b260fc
commit 78b5aa8baf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
46 changed files with 283 additions and 265 deletions

View File

@ -13,11 +13,11 @@ def getGitSha = { ->
} }
android { android {
compileSdkVersion 28 compileSdkVersion 29
defaultConfig { defaultConfig {
applicationId "com.keylesspalace.tusky" applicationId "com.keylesspalace.tusky"
minSdkVersion 21 minSdkVersion 21
targetSdkVersion 28 targetSdkVersion 29
versionCode 68 versionCode 68
versionName "9.1" versionName "9.1"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
@ -105,6 +105,7 @@ dependencies {
implementation 'androidx.exifinterface:exifinterface:1.0.0' implementation 'androidx.exifinterface:exifinterface:1.0.0'
implementation 'androidx.cardview:cardview:1.0.0' implementation 'androidx.cardview:cardview:1.0.0'
implementation 'androidx.preference:preference:1.1.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:retrofit:$retrofitVersion"
implementation "com.squareup.retrofit2:converter-gson:$retrofitVersion" implementation "com.squareup.retrofit2:converter-gson:$retrofitVersion"
implementation "com.squareup.retrofit2:adapter-rxjava2:$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:$daggerVersion"
implementation "com.google.dagger:dagger-android-support:$daggerVersion" implementation "com.google.dagger:dagger-android-support:$daggerVersion"
kapt "com.google.dagger:dagger-android-processor:$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 'org.mockito:mockito-inline:3.1.0'
testImplementation 'com.nhaarman.mockitokotlin2:mockito-kotlin:2.2.0' testImplementation 'com.nhaarman.mockitokotlin2:mockito-kotlin:2.2.0'
androidTestImplementation('androidx.test.espresso:espresso-core:3.1.1', { androidTestImplementation('androidx.test.espresso:espresso-core:3.1.1', {

View File

@ -1,20 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shortcuts xmlns:android="http://schemas.android.com/apk/res/android">
<shortcut
android:icon="@mipmap/ic_shortcut_compose"
android:shortcutId="com.keylesspalace.tusky.Compose"
android:shortcutLongLabel="@string/compose_shortcut_long_label"
android:shortcutShortLabel="@string/compose_shortcut_short_label">
<intent
android:action="android.intent.action.VIEW"
android:targetClass="com.keylesspalace.tusky.SplashActivity"
android:targetPackage="com.keylesspalace.tusky"/>
<intent
android:action="com.keylesspalace.tusky.Compose"
android:targetClass="com.keylesspalace.tusky.ComposeActivity"
android:targetPackage="com.keylesspalace.tusky"/>
</shortcut>
</shortcuts>

View File

@ -1,20 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shortcuts xmlns:android="http://schemas.android.com/apk/res/android">
<shortcut
android:icon="@mipmap/ic_shortcut_compose"
android:shortcutId="com.keylesspalace.tusky.Compose"
android:shortcutLongLabel="@string/compose_shortcut_long_label"
android:shortcutShortLabel="@string/compose_shortcut_short_label">
<intent
android:action="android.intent.action.VIEW"
android:targetClass="com.keylesspalace.tusky.SplashActivity"
android:targetPackage="com.keylesspalace.tusky.test"/>
<intent
android:action="com.keylesspalace.tusky.Compose"
android:targetClass="com.keylesspalace.tusky.ComposeActivity"
android:targetPackage="com.keylesspalace.tusky.test"/>
</shortcut>
</shortcuts>

View File

@ -31,7 +31,8 @@
<meta-data <meta-data
android:name="android.app.shortcuts" android:name="android.app.shortcuts"
android:resource="@xml/shortcuts" /> android:resource="@xml/share_shortcuts" />
</activity> </activity>
<activity <activity
android:name=".SavedTootActivity" android:name=".SavedTootActivity"
@ -52,7 +53,7 @@
</activity> </activity>
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
android:configChanges="orientation|screenSize|keyboardHidden"> android:configChanges="orientation|screenSize|keyboardHidden|screenLayout|smallestScreenSize">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.SEND" /> <action android:name="android.intent.action.SEND" />
@ -91,7 +92,8 @@
<meta-data <meta-data
android:name="android.service.chooser.chooser_target_service" android:name="android.service.chooser.chooser_target_service"
android:value="com.keylesspalace.tusky.service.AccountChooserService" /> android:value="androidx.sharetarget.ChooserTargetServiceCompat" />
</activity> </activity>
<activity <activity
android:name=".ComposeActivity" android:name=".ComposeActivity"
@ -106,7 +108,7 @@
android:theme="@style/TuskyBaseTheme" /> android:theme="@style/TuskyBaseTheme" />
<activity <activity
android:name=".AccountActivity" android:name=".AccountActivity"
android:configChanges="orientation|screenSize|keyboardHidden" /> android:configChanges="orientation|screenSize|keyboardHidden|screenLayout|smallestScreenSize" />
<activity android:name=".EditProfileActivity" /> <activity android:name=".EditProfileActivity" />
<activity android:name=".PreferencesActivity" /> <activity android:name=".PreferencesActivity" />
<activity android:name=".FavouritesActivity" /> <activity android:name=".FavouritesActivity" />
@ -153,16 +155,8 @@
<action android:name="android.service.quicksettings.action.QS_TILE" /> <action android:name="android.service.quicksettings.action.QS_TILE" />
</intent-filter> </intent-filter>
</service> </service>
<service android:name=".service.SendTootService" /> <service android:name=".service.SendTootService" />
<service
android:name=".service.AccountChooserService"
android:label="@string/app_name"
android:permission="android.permission.BIND_CHOOSER_TARGET_SERVICE"
tools:targetApi="23">
<intent-filter>
<action android:name="android.service.chooser.ChooserTargetService" />
</intent-filter>
</service>
<provider <provider
android:name="androidx.core.content.FileProvider" android:name="androidx.core.content.FileProvider"

View File

@ -22,7 +22,6 @@ import android.content.res.ColorStateList
import android.graphics.Color import android.graphics.Color
import android.graphics.PorterDuff import android.graphics.PorterDuff
import android.os.Bundle import android.os.Bundle
import android.preference.PreferenceManager
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
@ -36,6 +35,7 @@ import androidx.core.content.ContextCompat
import androidx.emoji.text.EmojiCompat import androidx.emoji.text.EmojiCompat
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProviders import androidx.lifecycle.ViewModelProviders
import androidx.preference.PreferenceManager
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.google.android.material.appbar.AppBarLayout import com.google.android.material.appbar.AppBarLayout

View File

@ -17,13 +17,13 @@
package com.keylesspalace.tusky package com.keylesspalace.tusky
import android.os.Bundle import android.os.Bundle
import android.preference.PreferenceManager
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.LinearLayout import android.widget.LinearLayout
import androidx.appcompat.widget.SearchView import androidx.appcompat.widget.SearchView
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
import androidx.preference.PreferenceManager
import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.ListAdapter
@ -35,7 +35,6 @@ import com.keylesspalace.tusky.util.*
import com.keylesspalace.tusky.viewmodel.AccountsInListViewModel import com.keylesspalace.tusky.viewmodel.AccountsInListViewModel
import com.keylesspalace.tusky.viewmodel.State import com.keylesspalace.tusky.viewmodel.State
import com.uber.autodispose.android.lifecycle.AndroidLifecycleScopeProvider.from import com.uber.autodispose.android.lifecycle.AndroidLifecycleScopeProvider.from
import com.uber.autodispose.autoDisposable
import com.uber.autodispose.autoDispose import com.uber.autodispose.autoDispose
import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.android.schedulers.AndroidSchedulers
import kotlinx.android.extensions.LayoutContainer import kotlinx.android.extensions.LayoutContainer

View File

@ -23,7 +23,6 @@ import android.content.pm.PackageManager;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.BitmapFactory; import android.graphics.BitmapFactory;
import android.os.Bundle; import android.os.Bundle;
import android.preference.PreferenceManager;
import android.util.Log; import android.util.Log;
import android.view.View; import android.view.View;
@ -34,6 +33,7 @@ import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat; import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
import androidx.preference.PreferenceManager;
import com.google.android.material.snackbar.Snackbar; import com.google.android.material.snackbar.Snackbar;
import com.keylesspalace.tusky.adapter.AccountSelectionAdapter; import com.keylesspalace.tusky.adapter.AccountSelectionAdapter;

View File

@ -51,7 +51,7 @@ abstract class BottomSheetActivity : BaseActivity() {
val bottomSheetLayout: LinearLayout = findViewById(R.id.item_status_bottom_sheet) val bottomSheetLayout: LinearLayout = findViewById(R.id.item_status_bottom_sheet)
bottomSheet = BottomSheetBehavior.from(bottomSheetLayout) bottomSheet = BottomSheetBehavior.from(bottomSheetLayout)
bottomSheet.state = BottomSheetBehavior.STATE_HIDDEN bottomSheet.state = BottomSheetBehavior.STATE_HIDDEN
bottomSheet.setBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() { bottomSheet.addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() {
override fun onStateChanged(bottomSheet: View, newState: Int) { override fun onStateChanged(bottomSheet: View, newState: Int) {
if (newState == BottomSheetBehavior.STATE_HIDDEN) { if (newState == BottomSheetBehavior.STATE_HIDDEN) {
cancelActiveSearch() cancelActiveSearch()

View File

@ -21,7 +21,6 @@ import android.graphics.drawable.Drawable;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.preference.PreferenceManager;
import android.util.Log; import android.util.Log;
import android.view.KeyEvent; import android.view.KeyEvent;
import android.widget.ImageView; import android.widget.ImageView;
@ -29,9 +28,11 @@ import android.widget.ImageView;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AlertDialog;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
import androidx.core.content.pm.ShortcutManagerCompat;
import androidx.emoji.text.EmojiCompat; import androidx.emoji.text.EmojiCompat;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import androidx.lifecycle.Lifecycle; import androidx.lifecycle.Lifecycle;
import androidx.preference.PreferenceManager;
import androidx.viewpager.widget.ViewPager; import androidx.viewpager.widget.ViewPager;
import com.bumptech.glide.Glide; import com.bumptech.glide.Glide;
@ -51,6 +52,7 @@ import com.keylesspalace.tusky.interfaces.ReselectableFragment;
import com.keylesspalace.tusky.pager.MainPagerAdapter; import com.keylesspalace.tusky.pager.MainPagerAdapter;
import com.keylesspalace.tusky.util.CustomEmojiHelper; import com.keylesspalace.tusky.util.CustomEmojiHelper;
import com.keylesspalace.tusky.util.NotificationHelper; import com.keylesspalace.tusky.util.NotificationHelper;
import com.keylesspalace.tusky.util.ShareShortcutHelper;
import com.keylesspalace.tusky.util.ThemeUtils; import com.keylesspalace.tusky.util.ThemeUtils;
import com.mikepenz.google_material_typeface_library.GoogleMaterial; import com.mikepenz.google_material_typeface_library.GoogleMaterial;
import com.mikepenz.materialdrawer.AccountHeader; import com.mikepenz.materialdrawer.AccountHeader;
@ -139,7 +141,18 @@ public final class MainActivity extends BottomSheetActivity implements ActionBut
boolean showNotificationTab = false; boolean showNotificationTab = false;
if (intent != null) { if (intent != null) {
/** there are two possibilities the accountId can be passed to MainActivity:
- from our code as long 'account_id'
- from share shortcuts as String 'android.intent.extra.shortcut.ID'
*/
long accountId = intent.getLongExtra(NotificationHelper.ACCOUNT_ID, -1); long accountId = intent.getLongExtra(NotificationHelper.ACCOUNT_ID, -1);
if(accountId == -1) {
String accountIdString = intent.getStringExtra(ShortcutManagerCompat.EXTRA_SHORTCUT_ID);
if(accountIdString != null) {
accountId = Long.parseLong(accountIdString);
}
}
boolean accountRequested = (accountId != -1); boolean accountRequested = (accountId != -1);
if (accountRequested) { if (accountRequested) {
@ -528,6 +541,7 @@ public final class MainActivity extends BottomSheetActivity implements ActionBut
NotificationHelper.deleteNotificationChannelsForAccount(accountManager.getActiveAccount(), MainActivity.this); NotificationHelper.deleteNotificationChannelsForAccount(accountManager.getActiveAccount(), MainActivity.this);
cacheUpdater.clearForUser(activeAccount.getId()); cacheUpdater.clearForUser(activeAccount.getId());
conversationRepository.deleteCacheForAccount(activeAccount.getId()); conversationRepository.deleteCacheForAccount(activeAccount.getId());
ShareShortcutHelper.removeShortcut(this, activeAccount);
AccountEntity newAccount = accountManager.logActiveAccountOut(); AccountEntity newAccount = accountManager.logActiveAccountOut();
@ -585,6 +599,8 @@ public final class MainActivity extends BottomSheetActivity implements ActionBut
updateProfiles(); updateProfiles();
ShareShortcutHelper.updateShortcut(this, accountManager.getActiveAccount());
} }
private void updateProfiles() { private void updateProfiles() {

View File

@ -19,20 +19,19 @@ import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.SharedPreferences import android.content.SharedPreferences
import android.os.Bundle import android.os.Bundle
import android.preference.PreferenceManager
import androidx.fragment.app.Fragment
import android.util.Log import android.util.Log
import android.view.MenuItem import android.view.MenuItem
import androidx.fragment.app.Fragment
import androidx.preference.PreferenceManager
import com.keylesspalace.tusky.appstore.EventHub import com.keylesspalace.tusky.appstore.EventHub
import com.keylesspalace.tusky.appstore.PreferenceChangedEvent import com.keylesspalace.tusky.appstore.PreferenceChangedEvent
import com.keylesspalace.tusky.fragment.preference.* import com.keylesspalace.tusky.fragment.preference.*
import com.keylesspalace.tusky.util.ThemeUtils import com.keylesspalace.tusky.util.ThemeUtils
import com.keylesspalace.tusky.util.getNonNullString import com.keylesspalace.tusky.util.getNonNullString
import dagger.android.DispatchingAndroidInjector import dagger.android.DispatchingAndroidInjector
import kotlinx.android.synthetic.main.toolbar_basic.*
import java.lang.IllegalArgumentException
import javax.inject.Inject
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import kotlinx.android.synthetic.main.toolbar_basic.*
import javax.inject.Inject
class PreferencesActivity : BaseActivity(), SharedPreferences.OnSharedPreferenceChangeListener, class PreferencesActivity : BaseActivity(), SharedPreferences.OnSharedPreferenceChangeListener,
HasAndroidInjector { HasAndroidInjector {

View File

@ -19,9 +19,9 @@ import android.app.Application;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.preference.PreferenceManager;
import androidx.emoji.text.EmojiCompat; import androidx.emoji.text.EmojiCompat;
import androidx.preference.PreferenceManager;
import androidx.room.Room; import androidx.room.Room;
import com.evernote.android.job.JobManager; import com.evernote.android.job.JobManager;

View File

@ -227,7 +227,7 @@ class ViewMediaActivity : BaseActivity(), ViewImageFragment.PhotoActionsListener
private fun copyLink() { private fun copyLink() {
val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
clipboard.primaryClip = ClipData.newPlainText(null, attachments!![viewPager.currentItem].attachment.url) clipboard.setPrimaryClip(ClipData.newPlainText(null, attachments!![viewPager.currentItem].attachment.url))
} }
private fun shareMedia() { private fun shareMedia() {

View File

@ -16,16 +16,15 @@
package com.keylesspalace.tusky.adapter package com.keylesspalace.tusky.adapter
import android.content.Context import android.content.Context
import android.preference.PreferenceManager
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.ArrayAdapter import android.widget.ArrayAdapter
import androidx.preference.PreferenceManager
import com.keylesspalace.tusky.R import com.keylesspalace.tusky.R
import com.keylesspalace.tusky.db.AccountEntity import com.keylesspalace.tusky.db.AccountEntity
import com.keylesspalace.tusky.util.CustomEmojiHelper import com.keylesspalace.tusky.util.CustomEmojiHelper
import com.keylesspalace.tusky.util.loadAvatar import com.keylesspalace.tusky.util.loadAvatar
import kotlinx.android.synthetic.main.item_autocomplete_account.view.* import kotlinx.android.synthetic.main.item_autocomplete_account.view.*
class AccountSelectionAdapter(context: Context) : ArrayAdapter<AccountEntity>(context, R.layout.item_autocomplete_account) { class AccountSelectionAdapter(context: Context) : ArrayAdapter<AccountEntity>(context, R.layout.item_autocomplete_account) {

View File

@ -1,13 +1,13 @@
package com.keylesspalace.tusky.adapter; package com.keylesspalace.tusky.adapter;
import androidx.recyclerview.widget.RecyclerView;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.view.View; import android.view.View;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import androidx.preference.PreferenceManager;
import androidx.recyclerview.widget.RecyclerView;
import com.keylesspalace.tusky.R; import com.keylesspalace.tusky.R;
import com.keylesspalace.tusky.entity.Account; import com.keylesspalace.tusky.entity.Account;
import com.keylesspalace.tusky.interfaces.AccountActionListener; import com.keylesspalace.tusky.interfaces.AccountActionListener;

View File

@ -15,10 +15,6 @@
package com.keylesspalace.tusky.adapter; 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.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
@ -26,6 +22,10 @@ import android.widget.ImageButton;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; 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.R;
import com.keylesspalace.tusky.entity.Account; import com.keylesspalace.tusky.entity.Account;
import com.keylesspalace.tusky.interfaces.AccountActionListener; import com.keylesspalace.tusky.interfaces.AccountActionListener;

View File

@ -15,10 +15,6 @@
package com.keylesspalace.tusky.adapter; 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.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
@ -26,6 +22,10 @@ import android.widget.ImageButton;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; 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.R;
import com.keylesspalace.tusky.entity.Account; import com.keylesspalace.tusky.entity.Account;
import com.keylesspalace.tusky.interfaces.AccountActionListener; import com.keylesspalace.tusky.interfaces.AccountActionListener;

View File

@ -1,9 +1,5 @@
package com.keylesspalace.tusky.adapter; 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.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
@ -11,6 +7,10 @@ import android.widget.ImageButton;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; 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.R;
import com.keylesspalace.tusky.entity.Account; import com.keylesspalace.tusky.entity.Account;
import com.keylesspalace.tusky.interfaces.AccountActionListener; import com.keylesspalace.tusky.interfaces.AccountActionListener;

View File

@ -16,7 +16,6 @@
package com.keylesspalace.tusky.components.conversation; package com.keylesspalace.tusky.components.conversation;
import android.content.Context; import android.content.Context;
import android.preference.PreferenceManager;
import android.text.InputFilter; import android.text.InputFilter;
import android.text.TextUtils; import android.text.TextUtils;
import android.view.View; import android.view.View;
@ -24,6 +23,7 @@ import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import android.widget.ToggleButton; import android.widget.ToggleButton;
import androidx.preference.PreferenceManager;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import com.keylesspalace.tusky.R; import com.keylesspalace.tusky.R;

View File

@ -17,13 +17,13 @@ package com.keylesspalace.tusky.components.conversation
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.preference.PreferenceManager
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProviders import androidx.lifecycle.ViewModelProviders
import androidx.paging.PagedList import androidx.paging.PagedList
import androidx.preference.PreferenceManager
import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.SimpleItemAnimator import androidx.recyclerview.widget.SimpleItemAnimator

View File

@ -16,7 +16,6 @@
package com.keylesspalace.tusky.components.report.fragments package com.keylesspalace.tusky.components.report.fragments
import android.os.Bundle import android.os.Bundle
import android.preference.PreferenceManager
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
@ -26,6 +25,7 @@ import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProviders import androidx.lifecycle.ViewModelProviders
import androidx.paging.PagedList import androidx.paging.PagedList
import androidx.preference.PreferenceManager
import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.SimpleItemAnimator import androidx.recyclerview.widget.SimpleItemAnimator

View File

@ -24,7 +24,6 @@ import android.content.Intent
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.net.Uri import android.net.Uri
import android.os.Environment import android.os.Environment
import android.preference.PreferenceManager
import android.util.Log import android.util.Log
import android.view.View import android.view.View
import android.widget.Toast import android.widget.Toast
@ -36,6 +35,7 @@ import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.paging.PagedList import androidx.paging.PagedList
import androidx.paging.PagedListAdapter import androidx.paging.PagedListAdapter
import androidx.preference.PreferenceManager
import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import com.keylesspalace.tusky.* import com.keylesspalace.tusky.*
@ -277,8 +277,7 @@ class SearchStatusesFragment : SearchFragment<Pair<Status, StatusViewData.Concre
} }
R.id.status_copy_link -> { R.id.status_copy_link -> {
val clipboard = activity!!.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager val clipboard = activity!!.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val clip = ClipData.newPlainText(null, statusUrl) clipboard.setPrimaryClip(ClipData.newPlainText(null, statusUrl))
clipboard.primaryClip = clip
return@setOnMenuItemClickListener true return@setOnMenuItemClickListener true
} }
R.id.status_open_as -> { R.id.status_open_as -> {

View File

@ -19,8 +19,8 @@ package com.keylesspalace.tusky.di
import android.app.Application import android.app.Application
import android.content.Context import android.content.Context
import android.content.SharedPreferences import android.content.SharedPreferences
import android.preference.PreferenceManager
import androidx.localbroadcastmanager.content.LocalBroadcastManager import androidx.localbroadcastmanager.content.LocalBroadcastManager
import androidx.preference.PreferenceManager
import com.keylesspalace.tusky.TuskyApplication import com.keylesspalace.tusky.TuskyApplication
import com.keylesspalace.tusky.appstore.EventHub import com.keylesspalace.tusky.appstore.EventHub
import com.keylesspalace.tusky.appstore.EventHubImpl import com.keylesspalace.tusky.appstore.EventHubImpl

View File

@ -20,7 +20,6 @@ import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.os.Bundle; import android.os.Bundle;
import android.preference.PreferenceManager;
import android.util.Log; import android.util.Log;
import android.util.SparseBooleanArray; import android.util.SparseBooleanArray;
import android.view.LayoutInflater; import android.view.LayoutInflater;
@ -39,6 +38,7 @@ import androidx.arch.core.util.Function;
import androidx.coordinatorlayout.widget.CoordinatorLayout; import androidx.coordinatorlayout.widget.CoordinatorLayout;
import androidx.core.util.Pair; import androidx.core.util.Pair;
import androidx.lifecycle.Lifecycle; import androidx.lifecycle.Lifecycle;
import androidx.preference.PreferenceManager;
import androidx.recyclerview.widget.AsyncDifferConfig; import androidx.recyclerview.widget.AsyncDifferConfig;
import androidx.recyclerview.widget.AsyncListDiffer; import androidx.recyclerview.widget.AsyncListDiffer;
import androidx.recyclerview.widget.DiffUtil; import androidx.recyclerview.widget.DiffUtil;

View File

@ -19,13 +19,29 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.os.Bundle; import android.os.Bundle;
import android.preference.PreferenceManager;
import android.util.Log; import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ProgressBar; 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.google.android.material.floatingactionbutton.FloatingActionButton;
import com.keylesspalace.tusky.AccountListActivity; import com.keylesspalace.tusky.AccountListActivity;
import com.keylesspalace.tusky.BaseActivity; import com.keylesspalace.tusky.BaseActivity;
@ -77,22 +93,6 @@ import java.util.concurrent.TimeUnit;
import javax.inject.Inject; 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 at.connyduck.sparkbutton.helpers.Utils;
import io.reactivex.Observable; import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.android.schedulers.AndroidSchedulers;
@ -307,7 +307,7 @@ public class TimelineFragment extends SFragment implements
Iterator<Either<Placeholder, Status>> iterator = this.statuses.iterator(); Iterator<Either<Placeholder, Status>> iterator = this.statuses.iterator();
while (iterator.hasNext()) { while (iterator.hasNext()) {
Either<Placeholder, Status> item = iterator.next(); Either<Placeholder, Status> item = iterator.next();
if(item.isRight()) { if (item.isRight()) {
Status status = item.asRight(); Status status = item.asRight();
if (status.getId().length() < topId.length() || status.getId().compareTo(topId) < 0) { if (status.getId().length() < topId.length() || status.getId().compareTo(topId) < 0) {

View File

@ -19,7 +19,6 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.os.Bundle; import android.os.Bundle;
import android.preference.PreferenceManager;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
@ -31,6 +30,7 @@ import androidx.annotation.Nullable;
import androidx.arch.core.util.Function; import androidx.arch.core.util.Function;
import androidx.core.util.Pair; import androidx.core.util.Pair;
import androidx.lifecycle.Lifecycle; import androidx.lifecycle.Lifecycle;
import androidx.preference.PreferenceManager;
import androidx.recyclerview.widget.DividerItemDecoration; import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;

View File

@ -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 <http://www.gnu.org/licenses>. */
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<ChooserTarget> {
val targets = mutableListOf<ChooserTarget>()
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
}
}

View File

@ -1,4 +1,4 @@
/* Copyright 2017 Andrew Dawson /* Copyright 2019 Tusky Contributors
* *
* This file is a part of Tusky. * 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, * You should have received a copy of the GNU General Public License along with Tusky; if not,
* see <http://www.gnu.org/licenses>. */ * see <http://www.gnu.org/licenses>. */
package com.keylesspalace.tusky.service; package com.keylesspalace.tusky.service
import android.annotation.TargetApi; import android.annotation.TargetApi
import android.content.Intent; import android.content.Intent
import android.service.quicksettings.TileService; 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 * Small Addition that adds in a QuickSettings tile
* Created by ztepps on 4/3/17. * opens the Compose activity or shows an account selector when multiple accounts are present
*/ */
@TargetApi(24) @TargetApi(24)
public class TuskyTileService extends TileService { class TuskyTileService : TileService() {
public TuskyTileService() {
super();
}
@Override override fun onClick() {
public void onClick() { val intent = Intent(this, MainActivity::class.java).apply {
Intent intent = new Intent(this, ComposeActivity.class); addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); action = Intent.ACTION_SEND
startActivityAndCollapse(intent); type = "text/plain"
}
startActivityAndCollapse(intent)
} }
} }

View File

@ -19,11 +19,6 @@ import android.content.ActivityNotFoundException;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.net.Uri; 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.SpannableStringBuilder;
import android.text.Spanned; import android.text.Spanned;
import android.text.method.LinkMovementMethod; import android.text.method.LinkMovementMethod;
@ -33,11 +28,15 @@ import android.util.Log;
import android.view.View; import android.view.View;
import android.widget.TextView; 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.R;
import com.keylesspalace.tusky.entity.Status; import com.keylesspalace.tusky.entity.Status;
import com.keylesspalace.tusky.interfaces.LinkListener; import com.keylesspalace.tusky.interfaces.LinkListener;
import java.lang.CharSequence;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;

View File

@ -18,9 +18,8 @@ package com.keylesspalace.tusky.util
import android.content.Context import android.content.Context
import android.content.SharedPreferences import android.content.SharedPreferences
import android.content.res.Configuration import android.content.res.Configuration
import android.preference.PreferenceManager import androidx.preference.PreferenceManager
import java.util.*
import java.util.Locale
class LocaleManager(context: Context) { class LocaleManager(context: Context) {

View File

@ -295,6 +295,7 @@ public class NotificationHelper {
.setColor(BuildConfig.DEBUG ? Color.parseColor("#19A341") : ContextCompat.getColor(context, R.color.tusky_blue)) .setColor(BuildConfig.DEBUG ? Color.parseColor("#19A341") : ContextCompat.getColor(context, R.color.tusky_blue))
.setGroup(account.getAccountId()) .setGroup(account.getAccountId())
.setAutoCancel(true) .setAutoCancel(true)
.setShortcutId(Long.toString(account.getId()))
.setDefaults(0); // So it doesn't ring twice, notify only in Target callback .setDefaults(0); // So it doesn't ring twice, notify only in Target callback
setupPreferences(account, builder); setupPreferences(account, builder);

View File

@ -18,7 +18,9 @@ package com.keylesspalace.tusky.util;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.os.Build; import android.os.Build;
import android.preference.PreferenceManager;
import androidx.annotation.NonNull;
import androidx.preference.PreferenceManager;
import com.keylesspalace.tusky.BuildConfig; import com.keylesspalace.tusky.BuildConfig;
@ -26,7 +28,6 @@ import java.net.InetSocketAddress;
import java.net.Proxy; import java.net.Proxy;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import androidx.annotation.NonNull;
import okhttp3.Cache; import okhttp3.Cache;
import okhttp3.Interceptor; import okhttp3.Interceptor;
import okhttp3.OkHttpClient; import okhttp3.OkHttpClient;

View File

@ -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 <http://www.gnu.org/licenses>. */
@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()))
}

View File

@ -16,8 +16,8 @@
<androidx.core.widget.NestedScrollView <androidx.core.widget.NestedScrollView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:textDirection="anyRtl" android:layout_gravity="center"
android:layout_gravity="center"> android:textDirection="anyRtl">
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
@ -46,6 +46,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="24dp" android:layout_marginTop="24dp"
android:hyphenationFrequency="full"
android:lineSpacingMultiplier="1.2" android:lineSpacingMultiplier="1.2"
android:paddingStart="@dimen/text_content_margin" android:paddingStart="@dimen/text_content_margin"
android:paddingEnd="@dimen/text_content_margin" android:paddingEnd="@dimen/text_content_margin"

View File

@ -172,6 +172,7 @@
android:id="@+id/accountNoteTextView" android:id="@+id/accountNoteTextView"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:hyphenationFrequency="full"
android:lineSpacingMultiplier="1.1" android:lineSpacingMultiplier="1.1"
android:paddingTop="10dp" android:paddingTop="10dp"
android:textColor="?android:textColorTertiary" android:textColor="?android:textColorTertiary"
@ -193,6 +194,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
android:layout_marginBottom="8dp" android:layout_marginBottom="8dp"
android:hyphenationFrequency="full"
android:lineSpacingMultiplier="1.1" android:lineSpacingMultiplier="1.1"
android:text="@string/label_remote_account" android:text="@string/label_remote_account"
android:visibility="gone" android:visibility="gone"
@ -313,8 +315,8 @@
android:layout_height="?attr/actionBarSize" android:layout_height="?attr/actionBarSize"
android:layout_gravity="top" android:layout_gravity="top"
android:background="@android:color/transparent" android:background="@android:color/transparent"
app:layout_collapseMode="pin"
app:contentInsetStartWithNavigation="0dp" app:contentInsetStartWithNavigation="0dp"
app:layout_collapseMode="pin"
app:layout_scrollFlags="scroll|enterAlways" /> app:layout_scrollFlags="scroll|enterAlways" />
</com.google.android.material.appbar.CollapsingToolbarLayout> </com.google.android.material.appbar.CollapsingToolbarLayout>

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_gravity="center" android:layout_gravity="center"
@ -17,25 +17,26 @@
android:id="@+id/progressBar" android:id="@+id/progressBar"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_centerHorizontal="true" android:layout_centerHorizontal="true"
android:layout_centerVertical="true" android:layout_centerVertical="true"
android:layout_gravity="center" /> android:layout_gravity="center"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView <TextView
android:id="@+id/mediaDescription" android:id="@+id/mediaDescription"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
android:background="#60000000" android:background="#60000000"
android:hyphenationFrequency="full"
android:lineSpacingMultiplier="1.1" android:lineSpacingMultiplier="1.1"
android:padding="8dp" android:padding="8dp"
android:textAlignment="center" android:textAlignment="center"
android:textColor="#eee" android:textColor="#eee"
android:textSize="?attr/status_text_medium" android:textSize="?attr/status_text_medium"
app:layout_constraintBottom_toBottomOf="parent"
tools:text="Some media description" /> tools:text="Some media description" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -2,9 +2,9 @@
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/videoContainer"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:id="@+id/videoContainer"
android:clickable="true" android:clickable="true"
android:focusable="true"> android:focusable="true">
@ -14,6 +14,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="?attr/actionBarSize" android:layout_marginTop="?attr/actionBarSize"
android:background="#60000000" android:background="#60000000"
android:hyphenationFrequency="full"
android:lineSpacingMultiplier="1.1" android:lineSpacingMultiplier="1.1"
android:padding="8dp" android:padding="8dp"
android:textAlignment="center" android:textAlignment="center"

View File

@ -105,6 +105,7 @@
android:id="@+id/status_content_warning_description" android:id="@+id/status_content_warning_description"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:hyphenationFrequency="full"
android:importantForAccessibility="no" android:importantForAccessibility="no"
android:lineSpacingMultiplier="1.1" android:lineSpacingMultiplier="1.1"
android:textColor="?android:textColorPrimary" android:textColor="?android:textColorPrimary"
@ -145,6 +146,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
android:focusable="true" android:focusable="true"
android:hyphenationFrequency="full"
android:importantForAccessibility="no" android:importantForAccessibility="no"
android:lineSpacingMultiplier="1.1" android:lineSpacingMultiplier="1.1"
android:textColor="?android:textColorPrimary" android:textColor="?android:textColorPrimary"

View File

@ -84,6 +84,7 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
android:hyphenationFrequency="full"
android:importantForAccessibility="no" android:importantForAccessibility="no"
android:lineSpacingMultiplier="1.1" android:lineSpacingMultiplier="1.1"
android:textColor="?android:textColorPrimary" android:textColor="?android:textColorPrimary"
@ -120,6 +121,7 @@
android:layout_marginTop="4dp" android:layout_marginTop="4dp"
android:layout_marginBottom="4dp" android:layout_marginBottom="4dp"
android:focusable="true" android:focusable="true"
android:hyphenationFrequency="full"
android:importantForAccessibility="no" android:importantForAccessibility="no"
android:lineSpacingMultiplier="1.1" android:lineSpacingMultiplier="1.1"
android:textColor="?android:textColorPrimary" android:textColor="?android:textColorPrimary"

View File

@ -13,8 +13,8 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_alignParentTop="true" android:layout_alignParentTop="true"
android:layout_marginBottom="6dp"
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
android:layout_marginBottom="6dp"
android:drawablePadding="10dp" android:drawablePadding="10dp"
android:ellipsize="end" android:ellipsize="end"
android:gravity="center_vertical" android:gravity="center_vertical"
@ -39,8 +39,8 @@
android:layout_alignParentStart="true" android:layout_alignParentStart="true"
android:ellipsize="end" android:ellipsize="end"
android:maxLines="1" android:maxLines="1"
android:paddingEnd="@dimen/status_display_name_padding_end"
android:paddingStart="0dp" android:paddingStart="0dp"
android:paddingEnd="@dimen/status_display_name_padding_end"
android:textAppearance="@android:style/TextAppearance.DeviceDefault.Small" android:textAppearance="@android:style/TextAppearance.DeviceDefault.Small"
android:textColor="?android:textColorTertiary" android:textColor="?android:textColorTertiary"
android:textSize="?attr/status_text_medium" android:textSize="?attr/status_text_medium"
@ -51,8 +51,8 @@
android:id="@+id/status_username" android:id="@+id/status_username"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_toEndOf="@id/status_display_name"
android:layout_toStartOf="@+id/status_timestamp_info" android:layout_toStartOf="@+id/status_timestamp_info"
android:layout_toEndOf="@id/status_display_name"
android:ellipsize="end" android:ellipsize="end"
android:maxLines="1" android:maxLines="1"
android:textColor="?android:textColorTertiary" android:textColor="?android:textColorTertiary"
@ -77,27 +77,27 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_below="@id/status_name_bar" android:layout_below="@id/status_name_bar"
android:layout_toEndOf="@id/notification_status_avatar" android:layout_toEndOf="@id/notification_status_avatar"
android:hyphenationFrequency="full"
android:lineSpacingMultiplier="1.1" android:lineSpacingMultiplier="1.1"
android:textColor="?android:textColorTertiary" android:textColor="?android:textColorTertiary"
android:textSize="?attr/status_text_medium" android:textSize="?attr/status_text_medium"
tools:text="Example CW text" /> tools:text="Example CW text" />
<ToggleButton <ToggleButton
android:id="@+id/notification_content_warning_button" android:id="@+id/notification_content_warning_button"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_below="@+id/notification_content_warning_description" android:layout_below="@+id/notification_content_warning_description"
android:layout_toEndOf="@id/notification_status_avatar"
android:background="?attr/content_warning_button"
android:minHeight="0dp"
android:minWidth="150dp"
android:paddingBottom="4dp"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingTop="4dp"
android:layout_marginTop="4dp" android:layout_marginTop="4dp"
android:layout_marginBottom="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:textAllCaps="true"
android:textOff="@string/status_content_warning_show_more" android:textOff="@string/status_content_warning_show_more"
android:textOn="@string/status_content_warning_show_less" android:textOn="@string/status_content_warning_show_less"
@ -109,6 +109,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_below="@id/notification_content_warning_button" android:layout_below="@id/notification_content_warning_button"
android:layout_toEndOf="@+id/notification_status_avatar" android:layout_toEndOf="@+id/notification_status_avatar"
android:hyphenationFrequency="full"
android:lineSpacingMultiplier="1.1" android:lineSpacingMultiplier="1.1"
android:paddingBottom="10dp" android:paddingBottom="10dp"
android:textColor="?android:textColorTertiary" android:textColor="?android:textColorTertiary"
@ -117,38 +118,38 @@
<ToggleButton <ToggleButton
android:id="@+id/button_toggle_notification_content" android:id="@+id/button_toggle_notification_content"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_toEndOf="@id/notification_status_avatar" android:layout_below="@id/notification_content"
android:layout_below="@id/notification_content" android:layout_marginTop="4dp"
android:textOff="@string/status_content_show_less" android:layout_marginBottom="4dp"
android:textOn="@string/status_content_show_more" android:layout_toEndOf="@id/notification_status_avatar"
android:background="?attr/content_warning_button" android:background="?attr/content_warning_button"
android:minHeight="0dp" android:minWidth="150dp"
android:minWidth="150dp" android:minHeight="0dp"
android:paddingBottom="4dp" android:paddingLeft="16dp"
android:paddingLeft="16dp" android:paddingTop="4dp"
android:paddingRight="16dp" android:paddingRight="16dp"
android:paddingTop="4dp" android:paddingBottom="4dp"
android:layout_marginTop="4dp" android:textAllCaps="true"
android:layout_marginBottom="4dp" android:textOff="@string/status_content_show_less"
android:textAllCaps="true" android:textOn="@string/status_content_show_more"
android:textSize="?attr/status_text_medium" android:textSize="?attr/status_text_medium"
android:visibility="gone" /> android:visibility="gone" />
<ImageView <ImageView
android:id="@+id/notification_status_avatar" android:id="@+id/notification_status_avatar"
android:layout_width="48dp" android:layout_width="48dp"
android:layout_height="48dp" android:layout_height="48dp"
android:layout_below="@id/notification_top_text" android:layout_below="@id/notification_top_text"
android:layout_marginBottom="14dp" android:layout_marginTop="10dp"
android:layout_marginEnd="14dp" android:layout_marginEnd="14dp"
android:layout_marginRight="14dp" android:layout_marginRight="14dp"
android:layout_marginTop="10dp" android:layout_marginBottom="14dp"
android:contentDescription="@string/action_view_profile" android:contentDescription="@string/action_view_profile"
android:paddingBottom="12dp"
android:paddingRight="12dp" android:paddingRight="12dp"
android:paddingBottom="12dp"
android:scaleType="centerCrop" android:scaleType="centerCrop"
tools:ignore="RtlHardcoded,RtlSymmetry" tools:ignore="RtlHardcoded,RtlSymmetry"
tools:src="@drawable/avatar_default" /> tools:src="@drawable/avatar_default" />
@ -157,7 +158,7 @@
android:id="@+id/notification_notification_avatar" android:id="@+id/notification_notification_avatar"
android:layout_width="24dp" android:layout_width="24dp"
android:layout_height="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" />
</RelativeLayout> </RelativeLayout>

View File

@ -46,4 +46,7 @@
<dimen name="card_radius">5dp</dimen> <dimen name="card_radius">5dp</dimen>
<dimen name="poll_preview_padding">12dp</dimen> <dimen name="poll_preview_padding">12dp</dimen>
<dimen name="adaptive_bitmap_inner_size">72dp</dimen>
<dimen name="adaptive_bitmap_outer_size">108dp</dimen>
</resources> </resources>

View File

@ -0,0 +1,8 @@
<shortcuts xmlns:android="http://schemas.android.com/apk/res/android">
<share-target android:targetClass="com.keylesspalace.tusky.MainActivity">
<data android:mimeType="text/plain" />
<category android:name="com.keylesspalace.tusky.Share" />
</share-target>
</shortcuts>

View File

@ -49,7 +49,7 @@ import retrofit2.Response
* Created by charlag on 3/7/18. * Created by charlag on 3/7/18.
*/ */
@Config(application = FakeTuskyApplication::class) @Config(application = FakeTuskyApplication::class, sdk = [28])
@RunWith(AndroidJUnit4::class) @RunWith(AndroidJUnit4::class)
class ComposeActivityTest { class ComposeActivityTest {

View File

@ -24,7 +24,7 @@ import retrofit2.Callback
import retrofit2.Response import retrofit2.Response
import java.util.* import java.util.*
@Config(application = FakeTuskyApplication::class) @Config(application = FakeTuskyApplication::class, sdk = [28])
@RunWith(AndroidJUnit4::class) @RunWith(AndroidJUnit4::class)
class FilterTest { class FilterTest {

View File

@ -100,15 +100,10 @@ class SpanUtilsTest {
spans.add(BoundedSpan(what, start, end)) spans.add(BoundedSpan(what, start, end))
} }
override fun <T : Any?> getSpans(start: Int, end: Int, type: Class<T>?): Array<T> { override fun <T : Any> getSpans(start: Int, end: Int, type: Class<T>): Array<T> {
val matching = if (type == null) { return spans.filter { it.start >= start && it.end <= end && type.isInstance(it)}
ArrayList<T>()
} else {
spans.filter { it.start >= start && it.end <= end && type.isAssignableFrom(it.span?.javaClass) }
.map { it.span } .map { it.span }
.let { ArrayList(it) } .toTypedArray() as Array<T>
}
return matching.toArray() as Array<T>
} }
override fun removeSpan(what: Any?) { override fun removeSpan(what: Any?) {

View File

@ -11,7 +11,7 @@ import org.junit.runner.RunWith
import org.robolectric.Robolectric import org.robolectric.Robolectric
import org.robolectric.annotation.Config import org.robolectric.annotation.Config
@Config(application = FakeTuskyApplication::class) @Config(application = FakeTuskyApplication::class, sdk = [28])
@RunWith(AndroidJUnit4::class) @RunWith(AndroidJUnit4::class)
class RickRollTest { class RickRollTest {
private lateinit var activity: Activity private lateinit var activity: Activity

View File

@ -9,7 +9,7 @@ import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.robolectric.annotation.Config import org.robolectric.annotation.Config
@Config(application = FakeTuskyApplication::class) @Config(application = FakeTuskyApplication::class, sdk = [28])
@RunWith(AndroidJUnit4::class) @RunWith(AndroidJUnit4::class)
class SmartLengthInputFilterTest { class SmartLengthInputFilterTest {