mirror of
https://github.com/nextcloud/talk-android.git
synced 2024-11-21 20:45:29 +03:00
bump minSdkVersion to 26 and remove old checks
Signed-off-by: sowjanyakch <sowjanya.kch@gmail.com>
This commit is contained in:
parent
b6d28dfbbb
commit
fc2ff534e9
25 changed files with 50 additions and 211 deletions
|
@ -34,7 +34,7 @@ android {
|
||||||
namespace 'com.nextcloud.talk'
|
namespace 'com.nextcloud.talk'
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion 24
|
minSdkVersion 26
|
||||||
targetSdkVersion 34
|
targetSdkVersion 34
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
package com.nextcloud.talk.utils
|
package com.nextcloud.talk.utils
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.Build
|
|
||||||
import android.os.VibrationEffect
|
import android.os.VibrationEffect
|
||||||
import android.os.Vibrator
|
import android.os.Vibrator
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
|
@ -34,8 +33,6 @@ class VibrationUtilsTest {
|
||||||
@Test
|
@Test
|
||||||
fun testVibrateShort() {
|
fun testVibrateShort() {
|
||||||
VibrationUtils.vibrateShort(mockContext)
|
VibrationUtils.vibrateShort(mockContext)
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
||||||
Mockito.verify(mockVibrator)
|
Mockito.verify(mockVibrator)
|
||||||
.vibrate(
|
.vibrate(
|
||||||
VibrationEffect
|
VibrationEffect
|
||||||
|
@ -44,8 +41,5 @@ class VibrationUtilsTest {
|
||||||
VibrationEffect.DEFAULT_AMPLITUDE
|
VibrationEffect.DEFAULT_AMPLITUDE
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
} else {
|
|
||||||
Mockito.verify(mockVibrator).vibrate(VibrationUtils.SHORT_VIBRATE)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,6 @@ package com.nextcloud.talk.activities
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Build
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.text.TextUtils
|
import android.text.TextUtils
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
@ -21,7 +20,6 @@ import android.view.WindowManager
|
||||||
import android.view.inputmethod.EditorInfo
|
import android.view.inputmethod.EditorInfo
|
||||||
import android.webkit.SslErrorHandler
|
import android.webkit.SslErrorHandler
|
||||||
import android.widget.EditText
|
import android.widget.EditText
|
||||||
import androidx.annotation.RequiresApi
|
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.core.content.res.ResourcesCompat
|
import androidx.core.content.res.ResourcesCompat
|
||||||
|
@ -96,7 +94,7 @@ open class BaseActivity : AppCompatActivity() {
|
||||||
public override fun onResume() {
|
public override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && appPreferences.isKeyboardIncognito) {
|
if (appPreferences.isKeyboardIncognito) {
|
||||||
val viewGroup = (findViewById<View>(android.R.id.content) as ViewGroup).getChildAt(0) as ViewGroup
|
val viewGroup = (findViewById<View>(android.R.id.content) as ViewGroup).getChildAt(0) as ViewGroup
|
||||||
disableKeyboardPersonalisedLearning(viewGroup)
|
disableKeyboardPersonalisedLearning(viewGroup)
|
||||||
}
|
}
|
||||||
|
@ -137,7 +135,6 @@ open class BaseActivity : AppCompatActivity() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
|
||||||
private fun disableKeyboardPersonalisedLearning(viewGroup: ViewGroup) {
|
private fun disableKeyboardPersonalisedLearning(viewGroup: ViewGroup) {
|
||||||
var view: View?
|
var view: View?
|
||||||
var editText: EditText
|
var editText: EditText
|
||||||
|
|
|
@ -47,7 +47,6 @@ import android.widget.FrameLayout
|
||||||
import android.widget.RelativeLayout
|
import android.widget.RelativeLayout
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.annotation.DrawableRes
|
import androidx.annotation.DrawableRes
|
||||||
import androidx.annotation.RequiresApi
|
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.core.graphics.drawable.DrawableCompat
|
import androidx.core.graphics.drawable.DrawableCompat
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
@ -3054,7 +3053,6 @@ class CallActivity : CallBaseActivity() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
|
||||||
override fun onPictureInPictureModeChanged(isInPictureInPictureMode: Boolean, newConfig: Configuration) {
|
override fun onPictureInPictureModeChanged(isInPictureInPictureMode: Boolean, newConfig: Configuration) {
|
||||||
super.onPictureInPictureModeChanged(isInPictureInPictureMode, newConfig)
|
super.onPictureInPictureModeChanged(isInPictureInPictureMode, newConfig)
|
||||||
Log.d(TAG, "onPictureInPictureModeChanged")
|
Log.d(TAG, "onPictureInPictureModeChanged")
|
||||||
|
@ -3087,7 +3085,7 @@ class CallActivity : CallBaseActivity() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updatePictureInPictureActions(@DrawableRes iconId: Int, title: String?, requestCode: Int) {
|
private fun updatePictureInPictureActions(@DrawableRes iconId: Int, title: String?, requestCode: Int) {
|
||||||
if (isGreaterEqualOreo && isPipModePossible) {
|
if (isPipModePossible) {
|
||||||
val actions = ArrayList<RemoteAction>()
|
val actions = ArrayList<RemoteAction>()
|
||||||
val icon = Icon.createWithResource(this, iconId)
|
val icon = Icon.createWithResource(this, iconId)
|
||||||
val intentFlag: Int = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
val intentFlag: Int = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||||
|
|
|
@ -54,7 +54,7 @@ public abstract class CallBaseActivity extends BaseActivity {
|
||||||
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
||||||
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
||||||
|
|
||||||
if (isGreaterEqualOreo() && isPipModePossible()) {
|
if (isPipModePossible()) {
|
||||||
mPictureInPictureParamsBuilder = new PictureInPictureParams.Builder();
|
mPictureInPictureParamsBuilder = new PictureInPictureParams.Builder();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,7 +118,7 @@ public abstract class CallBaseActivity extends BaseActivity {
|
||||||
|
|
||||||
void enterPipMode() {
|
void enterPipMode() {
|
||||||
enableKeyguard();
|
enableKeyguard();
|
||||||
if (isGreaterEqualOreo() && isPipModePossible()) {
|
if (isPipModePossible()) {
|
||||||
Rational pipRatio = new Rational(300, 500);
|
Rational pipRatio = new Rational(300, 500);
|
||||||
mPictureInPictureParamsBuilder.setAspectRatio(pipRatio);
|
mPictureInPictureParamsBuilder.setAspectRatio(pipRatio);
|
||||||
enterPictureInPictureMode(mPictureInPictureParamsBuilder.build());
|
enterPictureInPictureMode(mPictureInPictureParamsBuilder.build());
|
||||||
|
@ -131,7 +131,6 @@ public abstract class CallBaseActivity extends BaseActivity {
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isPipModePossible() {
|
boolean isPipModePossible() {
|
||||||
if (isGreaterEqualOreo()) {
|
|
||||||
boolean deviceHasPipFeature = getPackageManager().hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE);
|
boolean deviceHasPipFeature = getPackageManager().hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE);
|
||||||
|
|
||||||
AppOpsManager appOpsManager = (AppOpsManager) getSystemService(Context.APP_OPS_SERVICE);
|
AppOpsManager appOpsManager = (AppOpsManager) getSystemService(Context.APP_OPS_SERVICE);
|
||||||
|
@ -140,12 +139,6 @@ public abstract class CallBaseActivity extends BaseActivity {
|
||||||
android.os.Process.myUid(),
|
android.os.Process.myUid(),
|
||||||
BuildConfig.APPLICATION_ID) == AppOpsManager.MODE_ALLOWED;
|
BuildConfig.APPLICATION_ID) == AppOpsManager.MODE_ALLOWED;
|
||||||
return deviceHasPipFeature && isPipFeatureGranted;
|
return deviceHasPipFeature && isPipFeatureGranted;
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean isGreaterEqualOreo(){
|
|
||||||
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.O;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract void updateUiForPipMode();
|
public abstract void updateUiForPipMode();
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
*/
|
*/
|
||||||
package com.nextcloud.talk.adapters.items
|
package com.nextcloud.talk.adapters.items
|
||||||
|
|
||||||
import android.os.Build
|
|
||||||
import android.text.TextUtils
|
import android.text.TextUtils
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.core.content.res.ResourcesCompat
|
import androidx.core.content.res.ResourcesCompat
|
||||||
|
@ -136,9 +135,9 @@ class ContactItem(
|
||||||
if (model.calculatedActorType == Participant.ActorType.GROUPS ||
|
if (model.calculatedActorType == Participant.ActorType.GROUPS ||
|
||||||
model.calculatedActorType == Participant.ActorType.CIRCLES
|
model.calculatedActorType == Participant.ActorType.CIRCLES
|
||||||
) {
|
) {
|
||||||
setGenericAvatar(holder!!, R.drawable.ic_avatar_group, R.drawable.ic_circular_group)
|
setGenericAvatar(holder!!, R.drawable.ic_avatar_group)
|
||||||
} else if (model.calculatedActorType == Participant.ActorType.EMAILS) {
|
} else if (model.calculatedActorType == Participant.ActorType.EMAILS) {
|
||||||
setGenericAvatar(holder!!, R.drawable.ic_avatar_mail, R.drawable.ic_circular_mail)
|
setGenericAvatar(holder!!, R.drawable.ic_avatar_mail)
|
||||||
} else if (model.calculatedActorType == Participant.ActorType.GUESTS ||
|
} else if (model.calculatedActorType == Participant.ActorType.GUESTS ||
|
||||||
model.type == Participant.ParticipantType.GUEST || model.type == Participant.ParticipantType.GUEST_MODERATOR
|
model.type == Participant.ParticipantType.GUEST || model.type == Participant.ParticipantType.GUEST_MODERATOR
|
||||||
) {
|
) {
|
||||||
|
@ -169,17 +168,13 @@ class ContactItem(
|
||||||
|
|
||||||
private fun setGenericAvatar(
|
private fun setGenericAvatar(
|
||||||
holder: ContactItemViewHolder,
|
holder: ContactItemViewHolder,
|
||||||
roundPlaceholderDrawable: Int,
|
roundPlaceholderDrawable: Int
|
||||||
fallbackImageResource: Int
|
|
||||||
) {
|
) {
|
||||||
val avatar = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
val avatar =
|
||||||
viewThemeUtils.talk.themePlaceholderAvatar(
|
viewThemeUtils.talk.themePlaceholderAvatar(
|
||||||
holder.binding.avatarView,
|
holder.binding.avatarView,
|
||||||
roundPlaceholderDrawable
|
roundPlaceholderDrawable
|
||||||
)
|
)
|
||||||
} else {
|
|
||||||
fallbackImageResource
|
|
||||||
}
|
|
||||||
|
|
||||||
holder.binding.avatarView.loadUserAvatar(avatar)
|
holder.binding.avatarView.loadUserAvatar(avatar)
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,6 @@ import android.annotation.SuppressLint
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.res.ColorStateList
|
import android.content.res.ColorStateList
|
||||||
import android.graphics.Typeface
|
import android.graphics.Typeface
|
||||||
import android.os.Build
|
|
||||||
import android.text.TextUtils
|
import android.text.TextUtils
|
||||||
import android.text.format.DateUtils
|
import android.text.format.DateUtils
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
@ -195,18 +194,13 @@ class ConversationItem(
|
||||||
}
|
}
|
||||||
|
|
||||||
ConversationEnums.ObjectType.FILE -> {
|
ConversationEnums.ObjectType.FILE -> {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
||||||
holder.binding.dialogAvatar.loadUserAvatar(
|
holder.binding.dialogAvatar.loadUserAvatar(
|
||||||
viewThemeUtils.talk.themePlaceholderAvatar(
|
viewThemeUtils.talk.themePlaceholderAvatar(
|
||||||
holder.binding.dialogAvatar,
|
holder.binding.dialogAvatar,
|
||||||
R.drawable.ic_avatar_document
|
R.drawable.ic_avatar_document
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
} else {
|
|
||||||
holder.binding.dialogAvatar.loadUserAvatar(
|
|
||||||
R.drawable.ic_circular_document
|
|
||||||
)
|
|
||||||
}
|
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,6 @@ package com.nextcloud.talk.adapters.items
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.Build
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.constraintlayout.widget.ConstraintLayout
|
import androidx.constraintlayout.widget.ConstraintLayout
|
||||||
import androidx.core.content.res.ResourcesCompat
|
import androidx.core.content.res.ResourcesCompat
|
||||||
|
@ -117,30 +116,22 @@ class MentionAutocompleteItem(
|
||||||
SOURCE_CALLS -> {
|
SOURCE_CALLS -> {
|
||||||
run {}
|
run {}
|
||||||
run {
|
run {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
||||||
holder.binding.avatarView.loadUserAvatar(
|
holder.binding.avatarView.loadUserAvatar(
|
||||||
viewThemeUtils.talk.themePlaceholderAvatar(
|
viewThemeUtils.talk.themePlaceholderAvatar(
|
||||||
holder.binding.avatarView,
|
holder.binding.avatarView,
|
||||||
R.drawable.ic_avatar_group
|
R.drawable.ic_avatar_group
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
} else {
|
|
||||||
holder.binding.avatarView.loadUserAvatar(R.drawable.ic_circular_group)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SOURCE_GROUPS -> {
|
SOURCE_GROUPS -> {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
||||||
holder.binding.avatarView.loadUserAvatar(
|
holder.binding.avatarView.loadUserAvatar(
|
||||||
viewThemeUtils.talk.themePlaceholderAvatar(
|
viewThemeUtils.talk.themePlaceholderAvatar(
|
||||||
holder.binding.avatarView,
|
holder.binding.avatarView,
|
||||||
R.drawable.ic_avatar_group
|
R.drawable.ic_avatar_group
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
} else {
|
|
||||||
holder.binding.avatarView.loadUserAvatar(R.drawable.ic_circular_group)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SOURCE_FEDERATION -> {
|
SOURCE_FEDERATION -> {
|
||||||
|
|
|
@ -10,13 +10,11 @@ package com.nextcloud.talk.callnotification
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import android.os.Build
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.annotation.RequiresApi
|
|
||||||
import androidx.core.app.NotificationManagerCompat
|
import androidx.core.app.NotificationManagerCompat
|
||||||
import autodagger.AutoInjector
|
import autodagger.AutoInjector
|
||||||
import com.nextcloud.talk.R
|
import com.nextcloud.talk.R
|
||||||
|
@ -215,7 +213,6 @@ class CallNotificationActivity : CallBaseActivity() {
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
|
||||||
override fun onPictureInPictureModeChanged(isInPictureInPictureMode: Boolean, newConfig: Configuration) {
|
override fun onPictureInPictureModeChanged(isInPictureInPictureMode: Boolean, newConfig: Configuration) {
|
||||||
super.onPictureInPictureModeChanged(isInPictureInPictureMode, newConfig)
|
super.onPictureInPictureModeChanged(isInPictureInPictureMode, newConfig)
|
||||||
isInPipMode = isInPictureInPictureMode
|
isInPipMode = isInPictureInPictureMode
|
||||||
|
|
|
@ -13,8 +13,6 @@ import android.content.Intent
|
||||||
import android.content.IntentFilter
|
import android.content.IntentFilter
|
||||||
import android.media.AudioFocusRequest
|
import android.media.AudioFocusRequest
|
||||||
import android.media.AudioManager
|
import android.media.AudioManager
|
||||||
import android.os.Build
|
|
||||||
import androidx.annotation.RequiresApi
|
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
|
||||||
|
@ -61,7 +59,6 @@ class AudioFocusRequestManager(private val context: Context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.O)
|
|
||||||
private val focusRequest = AudioFocusRequest.Builder(duration)
|
private val focusRequest = AudioFocusRequest.Builder(duration)
|
||||||
.setOnAudioFocusChangeListener(audioFocusChangeListener)
|
.setOnAudioFocusChangeListener(audioFocusChangeListener)
|
||||||
.build()
|
.build()
|
||||||
|
@ -75,19 +72,13 @@ class AudioFocusRequestManager(private val context: Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val isGranted: Int = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
val isGranted: Int =
|
||||||
if (shouldRequestFocus) {
|
if (shouldRequestFocus) {
|
||||||
audioManager.requestAudioFocus(focusRequest)
|
audioManager.requestAudioFocus(focusRequest)
|
||||||
} else {
|
} else {
|
||||||
audioManager.abandonAudioFocusRequest(focusRequest)
|
audioManager.abandonAudioFocusRequest(focusRequest)
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
if (shouldRequestFocus) {
|
|
||||||
audioManager.requestAudioFocus(audioFocusChangeListener, AudioManager.STREAM_MUSIC, duration)
|
|
||||||
} else {
|
|
||||||
audioManager.abandonAudioFocus(audioFocusChangeListener)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (isGranted == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
|
if (isGranted == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
|
||||||
onGranted()
|
onGranted()
|
||||||
handleBecomingNoisyBroadcast(shouldRequestFocus)
|
handleBecomingNoisyBroadcast(shouldRequestFocus)
|
||||||
|
|
|
@ -13,7 +13,6 @@ import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.graphics.PorterDuff
|
import android.graphics.PorterDuff
|
||||||
import android.graphics.drawable.ColorDrawable
|
import android.graphics.drawable.ColorDrawable
|
||||||
import android.os.Build
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.text.InputType
|
import android.text.InputType
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
@ -414,9 +413,7 @@ class ContactsActivity :
|
||||||
searchView!!.maxWidth = Int.MAX_VALUE
|
searchView!!.maxWidth = Int.MAX_VALUE
|
||||||
searchView!!.inputType = InputType.TYPE_TEXT_VARIATION_FILTER
|
searchView!!.inputType = InputType.TYPE_TEXT_VARIATION_FILTER
|
||||||
var imeOptions: Int = EditorInfo.IME_ACTION_DONE or EditorInfo.IME_FLAG_NO_FULLSCREEN
|
var imeOptions: Int = EditorInfo.IME_ACTION_DONE or EditorInfo.IME_FLAG_NO_FULLSCREEN
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O &&
|
if (appPreferences.isKeyboardIncognito == true) {
|
||||||
appPreferences.isKeyboardIncognito == true
|
|
||||||
) {
|
|
||||||
imeOptions = imeOptions or EditorInfo.IME_FLAG_NO_PERSONALIZED_LEARNING
|
imeOptions = imeOptions or EditorInfo.IME_FLAG_NO_PERSONALIZED_LEARNING
|
||||||
}
|
}
|
||||||
searchView!!.imeOptions = imeOptions
|
searchView!!.imeOptions = imeOptions
|
||||||
|
|
|
@ -550,7 +550,7 @@ class ConversationsListActivity :
|
||||||
searchView!!.maxWidth = Int.MAX_VALUE
|
searchView!!.maxWidth = Int.MAX_VALUE
|
||||||
searchView!!.inputType = InputType.TYPE_TEXT_VARIATION_FILTER
|
searchView!!.inputType = InputType.TYPE_TEXT_VARIATION_FILTER
|
||||||
var imeOptions = EditorInfo.IME_ACTION_DONE or EditorInfo.IME_FLAG_NO_FULLSCREEN
|
var imeOptions = EditorInfo.IME_ACTION_DONE or EditorInfo.IME_FLAG_NO_FULLSCREEN
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && appPreferences.isKeyboardIncognito) {
|
if (appPreferences.isKeyboardIncognito) {
|
||||||
imeOptions = imeOptions or EditorInfo.IME_FLAG_NO_PERSONALIZED_LEARNING
|
imeOptions = imeOptions or EditorInfo.IME_FLAG_NO_PERSONALIZED_LEARNING
|
||||||
}
|
}
|
||||||
searchView!!.imeOptions = imeOptions
|
searchView!!.imeOptions = imeOptions
|
||||||
|
|
|
@ -13,7 +13,6 @@ package com.nextcloud.talk.extensions
|
||||||
import android.graphics.drawable.ColorDrawable
|
import android.graphics.drawable.ColorDrawable
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
import android.graphics.drawable.LayerDrawable
|
import android.graphics.drawable.LayerDrawable
|
||||||
import android.os.Build
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
|
@ -27,9 +26,9 @@ import coil.result
|
||||||
import coil.transform.CircleCropTransformation
|
import coil.transform.CircleCropTransformation
|
||||||
import coil.transform.RoundedCornersTransformation
|
import coil.transform.RoundedCornersTransformation
|
||||||
import com.nextcloud.talk.R
|
import com.nextcloud.talk.R
|
||||||
|
import com.nextcloud.talk.chat.data.model.ChatMessage
|
||||||
import com.nextcloud.talk.data.user.model.User
|
import com.nextcloud.talk.data.user.model.User
|
||||||
import com.nextcloud.talk.models.domain.ConversationModel
|
import com.nextcloud.talk.models.domain.ConversationModel
|
||||||
import com.nextcloud.talk.chat.data.model.ChatMessage
|
|
||||||
import com.nextcloud.talk.models.json.conversations.Conversation
|
import com.nextcloud.talk.models.json.conversations.Conversation
|
||||||
import com.nextcloud.talk.models.json.conversations.ConversationEnums
|
import com.nextcloud.talk.models.json.conversations.ConversationEnums
|
||||||
import com.nextcloud.talk.ui.theme.ViewThemeUtils
|
import com.nextcloud.talk.ui.theme.ViewThemeUtils
|
||||||
|
@ -207,14 +206,11 @@ fun ImageView.loadThumbnail(url: String, user: User): io.reactivex.disposables.D
|
||||||
.target(this)
|
.target(this)
|
||||||
.transformations(CircleCropTransformation())
|
.transformations(CircleCropTransformation())
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
||||||
val layers = arrayOfNulls<Drawable>(2)
|
val layers = arrayOfNulls<Drawable>(2)
|
||||||
layers[0] = ContextCompat.getDrawable(context, R.drawable.ic_launcher_background)
|
layers[0] = ContextCompat.getDrawable(context, R.drawable.ic_launcher_background)
|
||||||
layers[1] = ContextCompat.getDrawable(context, R.drawable.ic_launcher_foreground)
|
layers[1] = ContextCompat.getDrawable(context, R.drawable.ic_launcher_foreground)
|
||||||
requestBuilder.placeholder(LayerDrawable(layers))
|
requestBuilder.placeholder(LayerDrawable(layers))
|
||||||
} else {
|
|
||||||
requestBuilder.placeholder(R.mipmap.ic_launcher)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (url.startsWith(user.baseUrl!!) &&
|
if (url.startsWith(user.baseUrl!!) &&
|
||||||
(url.contains("index.php/core/preview") || url.contains("/avatar/"))
|
(url.contains("index.php/core/preview") || url.contains("/avatar/"))
|
||||||
|
@ -275,15 +271,12 @@ fun ImageView.loadUserAvatar(any: Any?): io.reactivex.disposables.Disposable {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun ImageView.loadSystemAvatar(): io.reactivex.disposables.Disposable {
|
fun ImageView.loadSystemAvatar(): io.reactivex.disposables.Disposable {
|
||||||
val data: Any = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
||||||
val layers = arrayOfNulls<Drawable>(2)
|
val layers = arrayOfNulls<Drawable>(2)
|
||||||
layers[0] = ContextCompat.getDrawable(context, R.drawable.ic_launcher_background)
|
layers[0] = ContextCompat.getDrawable(context, R.drawable.ic_launcher_background)
|
||||||
layers[1] = ContextCompat.getDrawable(context, R.drawable.ic_launcher_foreground)
|
layers[1] = ContextCompat.getDrawable(context, R.drawable.ic_launcher_foreground)
|
||||||
val layerDrawable = LayerDrawable(layers)
|
val layerDrawable = LayerDrawable(layers)
|
||||||
layerDrawable
|
val data: Any = layerDrawable
|
||||||
} else {
|
|
||||||
R.mipmap.ic_launcher
|
|
||||||
}
|
|
||||||
|
|
||||||
return DisposableWrapper(
|
return DisposableWrapper(
|
||||||
load(data) {
|
load(data) {
|
||||||
|
@ -293,15 +286,13 @@ fun ImageView.loadSystemAvatar(): io.reactivex.disposables.Disposable {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun ImageView.loadNoteToSelfAvatar(): io.reactivex.disposables.Disposable {
|
fun ImageView.loadNoteToSelfAvatar(): io.reactivex.disposables.Disposable {
|
||||||
val data: Any = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
||||||
val layers = arrayOfNulls<Drawable>(2)
|
val layers = arrayOfNulls<Drawable>(2)
|
||||||
layers[0] = ContextCompat.getDrawable(context, R.drawable.ic_launcher_background)
|
layers[0] = ContextCompat.getDrawable(context, R.drawable.ic_launcher_background)
|
||||||
layers[1] = ContextCompat.getDrawable(context, R.drawable.ic_note_to_self)
|
layers[1] = ContextCompat.getDrawable(context, R.drawable.ic_note_to_self)
|
||||||
val layerDrawable = LayerDrawable(layers)
|
val layerDrawable = LayerDrawable(layers)
|
||||||
layerDrawable
|
val data: Any = layerDrawable
|
||||||
} else {
|
|
||||||
R.mipmap.ic_launcher
|
|
||||||
}
|
|
||||||
|
|
||||||
return DisposableWrapper(
|
return DisposableWrapper(
|
||||||
load(data) {
|
load(data) {
|
||||||
|
@ -315,15 +306,12 @@ fun ImageView.loadChangelogBotAvatar(): io.reactivex.disposables.Disposable {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun ImageView.loadBotsAvatar(): io.reactivex.disposables.Disposable {
|
fun ImageView.loadBotsAvatar(): io.reactivex.disposables.Disposable {
|
||||||
val data: Any = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
||||||
val layers = arrayOfNulls<Drawable>(2)
|
val layers = arrayOfNulls<Drawable>(2)
|
||||||
layers[0] = ColorDrawable(context.getColor(R.color.black))
|
layers[0] = ColorDrawable(context.getColor(R.color.black))
|
||||||
layers[1] = TextDrawable(context, ">")
|
layers[1] = TextDrawable(context, ">")
|
||||||
val layerDrawable = LayerDrawable(layers)
|
val layerDrawable = LayerDrawable(layers)
|
||||||
layerDrawable
|
val data: Any = layerDrawable
|
||||||
} else {
|
|
||||||
R.mipmap.ic_launcher
|
|
||||||
}
|
|
||||||
|
|
||||||
return DisposableWrapper(
|
return DisposableWrapper(
|
||||||
load(data) {
|
load(data) {
|
||||||
|
@ -333,29 +321,17 @@ fun ImageView.loadBotsAvatar(): io.reactivex.disposables.Disposable {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun ImageView.loadDefaultGroupCallAvatar(viewThemeUtils: ViewThemeUtils): io.reactivex.disposables.Disposable {
|
fun ImageView.loadDefaultGroupCallAvatar(viewThemeUtils: ViewThemeUtils): io.reactivex.disposables.Disposable {
|
||||||
val data: Any = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
val data: Any = viewThemeUtils.talk.themePlaceholderAvatar(this, R.drawable.ic_avatar_group) as Any
|
||||||
viewThemeUtils.talk.themePlaceholderAvatar(this, R.drawable.ic_avatar_group) as Any
|
|
||||||
} else {
|
|
||||||
R.drawable.ic_circular_group
|
|
||||||
}
|
|
||||||
return loadUserAvatar(data)
|
return loadUserAvatar(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun ImageView.loadDefaultPublicCallAvatar(viewThemeUtils: ViewThemeUtils): io.reactivex.disposables.Disposable {
|
fun ImageView.loadDefaultPublicCallAvatar(viewThemeUtils: ViewThemeUtils): io.reactivex.disposables.Disposable {
|
||||||
val data: Any = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
val data: Any = viewThemeUtils.talk.themePlaceholderAvatar(this, R.drawable.ic_avatar_link) as Any
|
||||||
viewThemeUtils.talk.themePlaceholderAvatar(this, R.drawable.ic_avatar_link) as Any
|
|
||||||
} else {
|
|
||||||
R.drawable.ic_circular_link
|
|
||||||
}
|
|
||||||
return loadUserAvatar(data)
|
return loadUserAvatar(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun ImageView.loadMailAvatar(viewThemeUtils: ViewThemeUtils): io.reactivex.disposables.Disposable {
|
fun ImageView.loadMailAvatar(viewThemeUtils: ViewThemeUtils): io.reactivex.disposables.Disposable {
|
||||||
val data: Any = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
val data: Any = viewThemeUtils.talk.themePlaceholderAvatar(this, R.drawable.ic_avatar_mail) as Any
|
||||||
viewThemeUtils.talk.themePlaceholderAvatar(this, R.drawable.ic_avatar_mail) as Any
|
|
||||||
} else {
|
|
||||||
R.drawable.ic_circular_mail
|
|
||||||
}
|
|
||||||
return loadUserAvatar(data)
|
return loadUserAvatar(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,9 +9,7 @@ package com.nextcloud.talk.jobs;
|
||||||
|
|
||||||
import android.app.NotificationManager;
|
import android.app.NotificationManager;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Build;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import com.nextcloud.talk.R;
|
import com.nextcloud.talk.R;
|
||||||
import com.nextcloud.talk.api.NcApi;
|
import com.nextcloud.talk.api.NcApi;
|
||||||
import com.nextcloud.talk.application.NextcloudTalkApplication;
|
import com.nextcloud.talk.application.NextcloudTalkApplication;
|
||||||
|
@ -146,7 +144,6 @@ public class AccountRemovalWorker extends Worker {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onNext(Void aVoid) {
|
public void onNext(Void aVoid) {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
||||||
String groupName = String.format(
|
String groupName = String.format(
|
||||||
getApplicationContext()
|
getApplicationContext()
|
||||||
.getResources()
|
.getResources()
|
||||||
|
@ -161,7 +158,6 @@ public class AccountRemovalWorker extends Worker {
|
||||||
notificationManager.deleteNotificationChannelGroup(
|
notificationManager.deleteNotificationChannelGroup(
|
||||||
Long.toString(crc32.getValue()));
|
Long.toString(crc32.getValue()));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
initiateUserDeletion(user);
|
initiateUserDeletion(user);
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,8 +15,6 @@ import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
import android.media.AudioAttributes
|
|
||||||
import android.media.MediaPlayer
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
@ -66,13 +64,11 @@ import com.nextcloud.talk.receivers.ShareRecordingToChatReceiver
|
||||||
import com.nextcloud.talk.users.UserManager
|
import com.nextcloud.talk.users.UserManager
|
||||||
import com.nextcloud.talk.utils.ApiUtils
|
import com.nextcloud.talk.utils.ApiUtils
|
||||||
import com.nextcloud.talk.utils.ConversationUtils
|
import com.nextcloud.talk.utils.ConversationUtils
|
||||||
import com.nextcloud.talk.utils.DoNotDisturbUtils.shouldPlaySound
|
|
||||||
import com.nextcloud.talk.utils.NotificationUtils
|
import com.nextcloud.talk.utils.NotificationUtils
|
||||||
import com.nextcloud.talk.utils.NotificationUtils.cancelAllNotificationsForAccount
|
import com.nextcloud.talk.utils.NotificationUtils.cancelAllNotificationsForAccount
|
||||||
import com.nextcloud.talk.utils.NotificationUtils.cancelNotification
|
import com.nextcloud.talk.utils.NotificationUtils.cancelNotification
|
||||||
import com.nextcloud.talk.utils.NotificationUtils.findNotificationForRoom
|
import com.nextcloud.talk.utils.NotificationUtils.findNotificationForRoom
|
||||||
import com.nextcloud.talk.utils.NotificationUtils.getCallRingtoneUri
|
import com.nextcloud.talk.utils.NotificationUtils.getCallRingtoneUri
|
||||||
import com.nextcloud.talk.utils.NotificationUtils.getMessageRingtoneUri
|
|
||||||
import com.nextcloud.talk.utils.NotificationUtils.loadAvatarSync
|
import com.nextcloud.talk.utils.NotificationUtils.loadAvatarSync
|
||||||
import com.nextcloud.talk.utils.ParticipantPermissions
|
import com.nextcloud.talk.utils.ParticipantPermissions
|
||||||
import com.nextcloud.talk.utils.PushUtils
|
import com.nextcloud.talk.utils.PushUtils
|
||||||
|
@ -90,7 +86,6 @@ import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_TOKEN
|
||||||
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_SHARE_RECORDING_TO_CHAT_URL
|
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_SHARE_RECORDING_TO_CHAT_URL
|
||||||
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_SYSTEM_NOTIFICATION_ID
|
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_SYSTEM_NOTIFICATION_ID
|
||||||
import com.nextcloud.talk.utils.preferences.AppPreferences
|
import com.nextcloud.talk.utils.preferences.AppPreferences
|
||||||
import com.nextcloud.talk.utils.singletons.ApplicationWideCurrentRoomHolder
|
|
||||||
import io.reactivex.Observable
|
import io.reactivex.Observable
|
||||||
import io.reactivex.Observer
|
import io.reactivex.Observer
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||||
|
@ -99,7 +94,6 @@ import io.reactivex.schedulers.Schedulers
|
||||||
import okhttp3.JavaNetCookieJar
|
import okhttp3.JavaNetCookieJar
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import retrofit2.Retrofit
|
import retrofit2.Retrofit
|
||||||
import java.io.IOException
|
|
||||||
import java.net.CookieManager
|
import java.net.CookieManager
|
||||||
import java.security.InvalidKeyException
|
import java.security.InvalidKeyException
|
||||||
import java.security.NoSuchAlgorithmException
|
import java.security.NoSuchAlgorithmException
|
||||||
|
@ -541,7 +535,6 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor
|
||||||
|
|
||||||
notificationBuilder.setExtras(notificationInfoBundle)
|
notificationBuilder.setExtras(notificationInfoBundle)
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
||||||
when (pushMessage.type) {
|
when (pushMessage.type) {
|
||||||
TYPE_CHAT,
|
TYPE_CHAT,
|
||||||
TYPE_ROOM,
|
TYPE_ROOM,
|
||||||
|
@ -554,10 +547,6 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// red color for the lights
|
|
||||||
notificationBuilder.setLights(-0x10000, 200, 200)
|
|
||||||
}
|
|
||||||
|
|
||||||
notificationBuilder.setContentIntent(pendingIntent)
|
notificationBuilder.setContentIntent(pendingIntent)
|
||||||
val groupName = signatureVerification.user!!.id.toString() + "@" + pushMessage.id
|
val groupName = signatureVerification.user!!.id.toString() + "@" + pushMessage.id
|
||||||
|
@ -847,35 +836,9 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor
|
||||||
}
|
}
|
||||||
notificationManager.notify(notificationId, notification)
|
notificationManager.notify(notificationId, notification)
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
// On devices with Android 8.0 (Oreo) or later, notification sound will be handled by the system
|
||||||
// On devices with Android 8.0 (Oreo) or later, notification sound will be handled by the system
|
// if notifications have not been disabled by the user.
|
||||||
// if notifications have not been disabled by the user.
|
return
|
||||||
return
|
|
||||||
}
|
|
||||||
if (Notification.CATEGORY_CALL != notification.category || !muteCall) {
|
|
||||||
val soundUri = getMessageRingtoneUri(context!!, appPreferences)
|
|
||||||
if (soundUri != null && !ApplicationWideCurrentRoomHolder.getInstance().isInCall &&
|
|
||||||
(shouldPlaySound() || importantConversation)
|
|
||||||
) {
|
|
||||||
val audioAttributesBuilder =
|
|
||||||
AudioAttributes.Builder().setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
|
|
||||||
if (TYPE_CHAT == pushMessage.type || TYPE_ROOM == pushMessage.type) {
|
|
||||||
audioAttributesBuilder.setUsage(AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_INSTANT)
|
|
||||||
} else {
|
|
||||||
audioAttributesBuilder.setUsage(AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST)
|
|
||||||
}
|
|
||||||
val mediaPlayer = MediaPlayer()
|
|
||||||
try {
|
|
||||||
mediaPlayer.setDataSource(context!!, soundUri)
|
|
||||||
mediaPlayer.setAudioAttributes(audioAttributesBuilder.build())
|
|
||||||
mediaPlayer.setOnPreparedListener { mediaPlayer.start() }
|
|
||||||
mediaPlayer.setOnCompletionListener { obj: MediaPlayer -> obj.release() }
|
|
||||||
mediaPlayer.prepareAsync()
|
|
||||||
} catch (e: IOException) {
|
|
||||||
Log.e(TAG, "Failed to set data source")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun removeNotification(notificationId: Int) {
|
private fun removeNotification(notificationId: Int) {
|
||||||
|
@ -1049,6 +1012,5 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor
|
||||||
private const val TIMER_START = 1
|
private const val TIMER_START = 1
|
||||||
private const val TIMER_COUNT = 12
|
private const val TIMER_COUNT = 12
|
||||||
private const val TIMER_DELAY: Long = 5
|
private const val TIMER_DELAY: Long = 5
|
||||||
private const val GET_ROOM_RETRY_COUNT: Long = 3
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,6 @@ import android.app.SearchManager
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.graphics.drawable.ColorDrawable
|
import android.graphics.drawable.ColorDrawable
|
||||||
import android.os.Build
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.text.InputType
|
import android.text.InputType
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
@ -174,7 +173,7 @@ class GeocodingActivity :
|
||||||
searchView?.maxWidth = Int.MAX_VALUE
|
searchView?.maxWidth = Int.MAX_VALUE
|
||||||
searchView?.inputType = InputType.TYPE_TEXT_VARIATION_FILTER
|
searchView?.inputType = InputType.TYPE_TEXT_VARIATION_FILTER
|
||||||
var imeOptions = EditorInfo.IME_ACTION_DONE or EditorInfo.IME_FLAG_NO_FULLSCREEN
|
var imeOptions = EditorInfo.IME_ACTION_DONE or EditorInfo.IME_FLAG_NO_FULLSCREEN
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && appPreferences.isKeyboardIncognito) {
|
if (appPreferences.isKeyboardIncognito) {
|
||||||
imeOptions = imeOptions or EditorInfo.IME_FLAG_NO_PERSONALIZED_LEARNING
|
imeOptions = imeOptions or EditorInfo.IME_FLAG_NO_PERSONALIZED_LEARNING
|
||||||
}
|
}
|
||||||
searchView?.imeOptions = imeOptions
|
searchView?.imeOptions = imeOptions
|
||||||
|
|
|
@ -17,7 +17,6 @@ import android.graphics.drawable.ColorDrawable
|
||||||
import android.location.Location
|
import android.location.Location
|
||||||
import android.location.LocationListener
|
import android.location.LocationListener
|
||||||
import android.location.LocationManager
|
import android.location.LocationManager
|
||||||
import android.os.Build
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.text.InputType
|
import android.text.InputType
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
@ -217,7 +216,7 @@ class LocationPickerActivity :
|
||||||
searchView?.maxWidth = Int.MAX_VALUE
|
searchView?.maxWidth = Int.MAX_VALUE
|
||||||
searchView?.inputType = InputType.TYPE_TEXT_VARIATION_FILTER
|
searchView?.inputType = InputType.TYPE_TEXT_VARIATION_FILTER
|
||||||
var imeOptions = EditorInfo.IME_ACTION_DONE or EditorInfo.IME_FLAG_NO_FULLSCREEN
|
var imeOptions = EditorInfo.IME_ACTION_DONE or EditorInfo.IME_FLAG_NO_FULLSCREEN
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && appPreferences!!.isKeyboardIncognito) {
|
if (appPreferences!!.isKeyboardIncognito) {
|
||||||
imeOptions = imeOptions or EditorInfo.IME_FLAG_NO_PERSONALIZED_LEARNING
|
imeOptions = imeOptions or EditorInfo.IME_FLAG_NO_PERSONALIZED_LEARNING
|
||||||
}
|
}
|
||||||
searchView?.imeOptions = imeOptions
|
searchView?.imeOptions = imeOptions
|
||||||
|
|
|
@ -146,10 +146,6 @@ class SettingsActivity : BaseActivity(), SetPhoneNumberDialogFragment.SetPhoneNu
|
||||||
|
|
||||||
setupLicenceSetting()
|
setupLicenceSetting()
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
|
|
||||||
binding.settingsIncognitoKeyboard.visibility = View.GONE
|
|
||||||
}
|
|
||||||
|
|
||||||
binding.settingsScreenLockSummary.text = String.format(
|
binding.settingsScreenLockSummary.text = String.format(
|
||||||
Locale.getDefault(),
|
Locale.getDefault(),
|
||||||
resources!!.getString(R.string.nc_settings_screen_lock_desc),
|
resources!!.getString(R.string.nc_settings_screen_lock_desc),
|
||||||
|
@ -259,11 +255,9 @@ class SettingsActivity : BaseActivity(), SetPhoneNumberDialogFragment.SetPhoneNu
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupNotificationSettings() {
|
private fun setupNotificationSettings() {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
binding.settingsNotificationsTitle.text = resources!!.getString(
|
||||||
binding.settingsNotificationsTitle.text = resources!!.getString(
|
|
||||||
R.string.nc_settings_notification_sounds_post_oreo
|
R.string.nc_settings_notification_sounds_post_oreo
|
||||||
)
|
)
|
||||||
}
|
|
||||||
setupNotificationSoundsSettings()
|
setupNotificationSoundsSettings()
|
||||||
setupNotificationPermissionSettings()
|
setupNotificationPermissionSettings()
|
||||||
}
|
}
|
||||||
|
@ -365,7 +359,6 @@ class SettingsActivity : BaseActivity(), SetPhoneNumberDialogFragment.SetPhoneNu
|
||||||
binding.messagesRingtone.text = resources!!.getString(R.string.nc_common_disabled)
|
binding.messagesRingtone.text = resources!!.getString(R.string.nc_common_disabled)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
||||||
binding.settingsCallSound.setOnClickListener {
|
binding.settingsCallSound.setOnClickListener {
|
||||||
val intent = Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS)
|
val intent = Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS)
|
||||||
intent.putExtra(Settings.EXTRA_APP_PACKAGE, BuildConfig.APPLICATION_ID)
|
intent.putExtra(Settings.EXTRA_APP_PACKAGE, BuildConfig.APPLICATION_ID)
|
||||||
|
@ -385,9 +378,7 @@ class SettingsActivity : BaseActivity(), SetPhoneNumberDialogFragment.SetPhoneNu
|
||||||
)
|
)
|
||||||
startActivity(intent)
|
startActivity(intent)
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
Log.w(TAG, "setupSoundSettings currently not supported for versions < Build.VERSION_CODES.O")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setTroubleshootingClickListenersIfNecessary() {
|
private fun setTroubleshootingClickListenersIfNecessary() {
|
||||||
|
@ -869,11 +860,9 @@ class SettingsActivity : BaseActivity(), SetPhoneNumberDialogFragment.SetPhoneNu
|
||||||
private fun setupCheckables() {
|
private fun setupCheckables() {
|
||||||
binding.settingsScreenSecuritySwitch.isChecked = appPreferences.isScreenSecured
|
binding.settingsScreenSecuritySwitch.isChecked = appPreferences.isScreenSecured
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
||||||
binding.settingsIncognitoKeyboardSwitch.isChecked = appPreferences.isKeyboardIncognito
|
binding.settingsIncognitoKeyboardSwitch.isChecked = appPreferences.isKeyboardIncognito
|
||||||
} else {
|
|
||||||
binding.settingsIncognitoKeyboardSwitch.visibility = View.GONE
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CapabilitiesUtil.isReadStatusAvailable(currentUser!!.capabilities!!.spreedCapability!!)) {
|
if (CapabilitiesUtil.isReadStatusAvailable(currentUser!!.capabilities!!.spreedCapability!!)) {
|
||||||
binding.settingsReadPrivacySwitch.isChecked = !CapabilitiesUtil.isReadStatusPrivate(currentUser!!)
|
binding.settingsReadPrivacySwitch.isChecked = !CapabilitiesUtil.isReadStatusPrivate(currentUser!!)
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
package com.nextcloud.talk.ui.theme
|
package com.nextcloud.talk.ui.theme
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.annotation.TargetApi
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.res.ColorStateList
|
import android.content.res.ColorStateList
|
||||||
import android.graphics.PorterDuff
|
import android.graphics.PorterDuff
|
||||||
|
@ -16,7 +15,6 @@ import android.graphics.PorterDuffColorFilter
|
||||||
import android.graphics.Typeface
|
import android.graphics.Typeface
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
import android.graphics.drawable.LayerDrawable
|
import android.graphics.drawable.LayerDrawable
|
||||||
import android.os.Build
|
|
||||||
import android.text.Spannable
|
import android.text.Spannable
|
||||||
import android.text.Spanned
|
import android.text.Spanned
|
||||||
import android.text.style.ForegroundColorSpan
|
import android.text.style.ForegroundColorSpan
|
||||||
|
@ -203,7 +201,6 @@ class TalkSpecificViewThemeUtils @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@TargetApi(Build.VERSION_CODES.O)
|
|
||||||
fun themePlaceholderAvatar(avatar: View, @DrawableRes foreground: Int): Drawable? {
|
fun themePlaceholderAvatar(avatar: View, @DrawableRes foreground: Int): Drawable? {
|
||||||
var drawable: LayerDrawable? = null
|
var drawable: LayerDrawable? = null
|
||||||
withScheme(avatar) { scheme ->
|
withScheme(avatar) { scheme ->
|
||||||
|
|
|
@ -263,7 +263,6 @@ class ChunkedFileUploader(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// @RequiresApi(Build.VERSION_CODES.O)
|
|
||||||
private fun initHttpClient(okHttpClient: OkHttpClient, currentUser: User) {
|
private fun initHttpClient(okHttpClient: OkHttpClient, currentUser: User) {
|
||||||
val okHttpClientBuilder: OkHttpClient.Builder = okHttpClient.newBuilder()
|
val okHttpClientBuilder: OkHttpClient.Builder = okHttpClient.newBuilder()
|
||||||
okHttpClientBuilder.followRedirects(false)
|
okHttpClientBuilder.followRedirects(false)
|
||||||
|
|
|
@ -21,7 +21,6 @@ import android.graphics.Color
|
||||||
import android.graphics.Typeface
|
import android.graphics.Typeface
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build
|
|
||||||
import android.text.Spannable
|
import android.text.Spannable
|
||||||
import android.text.SpannableString
|
import android.text.SpannableString
|
||||||
import android.text.Spanned
|
import android.text.Spanned
|
||||||
|
@ -346,12 +345,10 @@ object DisplayUtils {
|
||||||
if (window != null) {
|
if (window != null) {
|
||||||
val decor = window.decorView
|
val decor = window.decorView
|
||||||
if (isLightTheme) {
|
if (isLightTheme) {
|
||||||
val systemUiFlagLightStatusBar: Int = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
val systemUiFlagLightStatusBar: Int =
|
||||||
View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR or
|
View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR or
|
||||||
View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR
|
View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR
|
||||||
} else {
|
|
||||||
View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
|
|
||||||
}
|
|
||||||
decor.systemUiVisibility = systemUiFlagLightStatusBar
|
decor.systemUiVisibility = systemUiFlagLightStatusBar
|
||||||
} else {
|
} else {
|
||||||
decor.systemUiVisibility = 0
|
decor.systemUiVisibility = 0
|
||||||
|
|
|
@ -13,7 +13,6 @@ import android.content.ContentResolver
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.database.Cursor
|
import android.database.Cursor
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build
|
|
||||||
import android.provider.OpenableColumns
|
import android.provider.OpenableColumns
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
@ -100,14 +99,10 @@ object FileUtils {
|
||||||
val cachedFile = File(context.cacheDir, filename)
|
val cachedFile = File(context.cacheDir, filename)
|
||||||
|
|
||||||
val aboveOrEqualAPI26Check =
|
val aboveOrEqualAPI26Check =
|
||||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.O &&
|
|
||||||
!cachedFile.toPath().normalize().startsWith(context.cacheDir.toPath())
|
!cachedFile.toPath().normalize().startsWith(context.cacheDir.toPath())
|
||||||
|
|
||||||
val belowAPI26Check =
|
|
||||||
Build.VERSION.SDK_INT < Build.VERSION_CODES.O &&
|
|
||||||
!cachedFile.canonicalPath.startsWith(context.cacheDir.canonicalPath, true)
|
|
||||||
|
|
||||||
val isOutsideCacheDir = aboveOrEqualAPI26Check || belowAPI26Check
|
val isOutsideCacheDir = aboveOrEqualAPI26Check
|
||||||
|
|
||||||
if (isOutsideCacheDir) {
|
if (isOutsideCacheDir) {
|
||||||
Log.w(TAG, "cachedFile was not created in cacheDir. Aborting for security reasons.")
|
Log.w(TAG, "cachedFile was not created in cacheDir. Aborting for security reasons.")
|
||||||
|
|
|
@ -8,7 +8,6 @@ package com.nextcloud.talk.utils
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build
|
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import android.view.inputmethod.EditorInfo
|
import android.view.inputmethod.EditorInfo
|
||||||
import android.view.inputmethod.InputConnection
|
import android.view.inputmethod.InputConnection
|
||||||
|
@ -42,7 +41,7 @@ class ImageEmojiEditText : EmojiEditText {
|
||||||
InputConnectionCompat.OnCommitContentListener { inputContentInfo, flags, _ ->
|
InputConnectionCompat.OnCommitContentListener { inputContentInfo, flags, _ ->
|
||||||
|
|
||||||
val lacksPermission = (flags and InputConnectionCompat.INPUT_CONTENT_GRANT_READ_URI_PERMISSION) != 0
|
val lacksPermission = (flags and InputConnectionCompat.INPUT_CONTENT_GRANT_READ_URI_PERMISSION) != 0
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1 && lacksPermission) {
|
if (lacksPermission) {
|
||||||
try {
|
try {
|
||||||
inputContentInfo.requestPermission()
|
inputContentInfo.requestPermission()
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
*/
|
*/
|
||||||
package com.nextcloud.talk.utils
|
package com.nextcloud.talk.utils
|
||||||
|
|
||||||
import android.annotation.TargetApi
|
|
||||||
import android.app.Notification
|
import android.app.Notification
|
||||||
import android.app.NotificationChannel
|
import android.app.NotificationChannel
|
||||||
import android.app.NotificationManager
|
import android.app.NotificationManager
|
||||||
|
@ -15,11 +14,9 @@ import android.content.Context
|
||||||
import android.graphics.drawable.BitmapDrawable
|
import android.graphics.drawable.BitmapDrawable
|
||||||
import android.media.AudioAttributes
|
import android.media.AudioAttributes
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build
|
|
||||||
import android.service.notification.StatusBarNotification
|
import android.service.notification.StatusBarNotification
|
||||||
import android.text.TextUtils
|
import android.text.TextUtils
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.core.app.NotificationManagerCompat
|
|
||||||
import androidx.core.graphics.drawable.IconCompat
|
import androidx.core.graphics.drawable.IconCompat
|
||||||
import coil.executeBlocking
|
import coil.executeBlocking
|
||||||
import coil.imageLoader
|
import coil.imageLoader
|
||||||
|
@ -57,7 +54,7 @@ object NotificationUtils {
|
||||||
const val KEY_UPLOAD_GROUP = "com.nextcloud.talk.utils.KEY_UPLOAD_GROUP"
|
const val KEY_UPLOAD_GROUP = "com.nextcloud.talk.utils.KEY_UPLOAD_GROUP"
|
||||||
const val GROUP_SUMMARY_NOTIFICATION_ID = -1
|
const val GROUP_SUMMARY_NOTIFICATION_ID = -1
|
||||||
|
|
||||||
@TargetApi(Build.VERSION_CODES.O)
|
|
||||||
private fun createNotificationChannel(
|
private fun createNotificationChannel(
|
||||||
context: Context,
|
context: Context,
|
||||||
notificationChannel: Channel,
|
notificationChannel: Channel,
|
||||||
|
@ -67,7 +64,6 @@ object NotificationUtils {
|
||||||
val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||||
|
|
||||||
if (
|
if (
|
||||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.O &&
|
|
||||||
notificationManager.getNotificationChannel(notificationChannel.id) == null
|
notificationManager.getNotificationChannel(notificationChannel.id) == null
|
||||||
) {
|
) {
|
||||||
val importance = if (notificationChannel.isImportant) {
|
val importance = if (notificationChannel.isImportant) {
|
||||||
|
@ -154,9 +150,8 @@ object NotificationUtils {
|
||||||
createUploadsNotificationChannel(context)
|
createUploadsNotificationChannel(context)
|
||||||
}
|
}
|
||||||
|
|
||||||
@TargetApi(Build.VERSION_CODES.O)
|
|
||||||
fun removeOldNotificationChannels(context: Context) {
|
fun removeOldNotificationChannels(context: Context) {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
||||||
val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||||
|
|
||||||
// Current version does not use notification channel groups - delete all groups
|
// Current version does not use notification channel groups - delete all groups
|
||||||
|
@ -172,16 +167,13 @@ object NotificationUtils {
|
||||||
notificationManager.deleteNotificationChannel(channel.id)
|
notificationManager.deleteNotificationChannel(channel.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@TargetApi(Build.VERSION_CODES.O)
|
|
||||||
private fun getNotificationChannel(context: Context, channelId: String): NotificationChannel? {
|
private fun getNotificationChannel(context: Context, channelId: String): NotificationChannel? {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
||||||
val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||||
return notificationManager.getNotificationChannel(channelId)
|
return notificationManager.getNotificationChannel(channelId)
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private inline fun scanNotifications(
|
private inline fun scanNotifications(
|
||||||
|
@ -268,7 +260,7 @@ object NotificationUtils {
|
||||||
fun isCallsNotificationChannelEnabled(context: Context): Boolean {
|
fun isCallsNotificationChannelEnabled(context: Context): Boolean {
|
||||||
val channel = getNotificationChannel(context, NotificationChannels.NOTIFICATION_CHANNEL_CALLS_V4.name)
|
val channel = getNotificationChannel(context, NotificationChannels.NOTIFICATION_CHANNEL_CALLS_V4.name)
|
||||||
if (channel != null) {
|
if (channel != null) {
|
||||||
return isNotificationChannelEnabled(context, channel)
|
return isNotificationChannelEnabled(channel)
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -276,17 +268,13 @@ object NotificationUtils {
|
||||||
fun isMessagesNotificationChannelEnabled(context: Context): Boolean {
|
fun isMessagesNotificationChannelEnabled(context: Context): Boolean {
|
||||||
val channel = getNotificationChannel(context, NotificationChannels.NOTIFICATION_CHANNEL_MESSAGES_V4.name)
|
val channel = getNotificationChannel(context, NotificationChannels.NOTIFICATION_CHANNEL_MESSAGES_V4.name)
|
||||||
if (channel != null) {
|
if (channel != null) {
|
||||||
return isNotificationChannelEnabled(context, channel)
|
return isNotificationChannelEnabled(channel)
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isNotificationChannelEnabled(context: Context, channel: NotificationChannel): Boolean {
|
private fun isNotificationChannelEnabled(channel: NotificationChannel): Boolean {
|
||||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
return channel.importance != NotificationManager.IMPORTANCE_NONE
|
||||||
channel.importance != NotificationManager.IMPORTANCE_NONE
|
|
||||||
} else {
|
|
||||||
NotificationManagerCompat.from(context).areNotificationsEnabled()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getRingtoneUri(
|
private fun getRingtoneUri(
|
||||||
|
@ -295,14 +283,14 @@ object NotificationUtils {
|
||||||
defaultRingtoneUri: String,
|
defaultRingtoneUri: String,
|
||||||
channelId: String
|
channelId: String
|
||||||
): Uri? {
|
): Uri? {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
||||||
val channel = getNotificationChannel(context, channelId)
|
val channel = getNotificationChannel(context, channelId)
|
||||||
if (channel != null) {
|
if (channel != null) {
|
||||||
return channel.sound
|
return channel.sound
|
||||||
}
|
}
|
||||||
// Notification channel will not be available when starting the application for the first time.
|
// Notification channel will not be available when starting the application for the first time.
|
||||||
// Ringtone uris are required to register the notification channels -> get uri from preferences.
|
// Ringtone uris are required to register the notification channels -> get uri from preferences.
|
||||||
}
|
|
||||||
return if (TextUtils.isEmpty(ringtonePreferencesString)) {
|
return if (TextUtils.isEmpty(ringtonePreferencesString)) {
|
||||||
Uri.parse(defaultRingtoneUri)
|
Uri.parse(defaultRingtoneUri)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -16,10 +16,6 @@ object VibrationUtils {
|
||||||
|
|
||||||
fun vibrateShort(context: Context) {
|
fun vibrateShort(context: Context) {
|
||||||
val vibrator = context.getSystemService(Context.VIBRATOR_SERVICE) as Vibrator
|
val vibrator = context.getSystemService(Context.VIBRATOR_SERVICE) as Vibrator
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
vibrator.vibrate(VibrationEffect.createOneShot(SHORT_VIBRATE, VibrationEffect.DEFAULT_AMPLITUDE))
|
||||||
vibrator.vibrate(VibrationEffect.createOneShot(SHORT_VIBRATE, VibrationEffect.DEFAULT_AMPLITUDE))
|
|
||||||
} else {
|
|
||||||
vibrator.vibrate(SHORT_VIBRATE)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue