mirror of
https://github.com/nextcloud/talk-android
synced 2025-07-09 22:04:24 +01:00
reformat kotlin code to comply with ktlint
Signed-off-by: Andy Scherzinger <info@andy-scherzinger.de>
This commit is contained in:
parent
0b1ca971dd
commit
e82808080d
@ -104,7 +104,6 @@ class MagicFirebaseMessagingService : FirebaseMessagingService() {
|
||||
@Inject
|
||||
var eventBus: EventBus? = null
|
||||
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
sharedApplication!!.componentApplication.inject(this)
|
||||
@ -148,18 +147,26 @@ class MagicFirebaseMessagingService : FirebaseMessagingService() {
|
||||
val pushUtils = PushUtils()
|
||||
val privateKey = pushUtils.readKeyFromFile(false) as PrivateKey
|
||||
try {
|
||||
signatureVerification = pushUtils.verifySignature(base64DecodedSignature,
|
||||
base64DecodedSubject)
|
||||
signatureVerification = pushUtils.verifySignature(
|
||||
base64DecodedSignature,
|
||||
base64DecodedSubject
|
||||
)
|
||||
if (signatureVerification!!.signatureValid) {
|
||||
val cipher = Cipher.getInstance("RSA/None/PKCS1Padding")
|
||||
cipher.init(Cipher.DECRYPT_MODE, privateKey)
|
||||
val decryptedSubject = cipher.doFinal(base64DecodedSubject)
|
||||
decryptedPushMessage = LoganSquare.parse(String(decryptedSubject),
|
||||
DecryptedPushMessage::class.java)
|
||||
decryptedPushMessage = LoganSquare.parse(
|
||||
String(decryptedSubject),
|
||||
DecryptedPushMessage::class.java
|
||||
)
|
||||
decryptedPushMessage?.apply {
|
||||
timestamp = System.currentTimeMillis()
|
||||
if (delete) {
|
||||
cancelExistingNotificationWithId(applicationContext, signatureVerification!!.userEntity, notificationId)
|
||||
cancelExistingNotificationWithId(
|
||||
applicationContext,
|
||||
signatureVerification!!.userEntity,
|
||||
notificationId
|
||||
)
|
||||
} else if (deleteAll) {
|
||||
cancelAllNotificationsForAccount(applicationContext, signatureVerification!!.userEntity)
|
||||
} else if (type == "call") {
|
||||
@ -171,39 +178,66 @@ class MagicFirebaseMessagingService : FirebaseMessagingService() {
|
||||
fullScreenIntent.putExtras(bundle)
|
||||
|
||||
fullScreenIntent.flags = Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
val fullScreenPendingIntent = PendingIntent.getActivity(this@MagicFirebaseMessagingService, 0, fullScreenIntent, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
val fullScreenPendingIntent = PendingIntent.getActivity(
|
||||
this@MagicFirebaseMessagingService,
|
||||
0,
|
||||
fullScreenIntent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT
|
||||
)
|
||||
|
||||
val audioAttributesBuilder = AudioAttributes.Builder().setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
|
||||
val audioAttributesBuilder =
|
||||
AudioAttributes.Builder().setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
|
||||
audioAttributesBuilder.setUsage(AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST)
|
||||
|
||||
val ringtonePreferencesString: String? = appPreferences!!.callRingtoneUri
|
||||
val soundUri = if (TextUtils.isEmpty(ringtonePreferencesString)) {
|
||||
Uri.parse("android.resource://" + applicationContext.packageName +
|
||||
"/raw/librem_by_feandesign_call")
|
||||
Uri.parse(
|
||||
"android.resource://" + applicationContext.packageName +
|
||||
"/raw/librem_by_feandesign_call"
|
||||
)
|
||||
} else {
|
||||
try {
|
||||
val ringtoneSettings = LoganSquare.parse(ringtonePreferencesString, RingtoneSettings::class.java)
|
||||
val ringtoneSettings =
|
||||
LoganSquare.parse(ringtonePreferencesString, RingtoneSettings::class.java)
|
||||
ringtoneSettings.ringtoneUri
|
||||
} catch (exception: IOException) {
|
||||
Uri.parse("android.resource://" + applicationContext.packageName + "/raw/librem_by_feandesign_call")
|
||||
}
|
||||
}
|
||||
|
||||
val notificationChannelId = NotificationUtils.getNotificationChannelId(applicationContext.resources
|
||||
.getString(R.string.nc_notification_channel_calls), applicationContext.resources
|
||||
.getString(R.string.nc_notification_channel_calls_description), true,
|
||||
NotificationManagerCompat.IMPORTANCE_HIGH, soundUri!!, audioAttributesBuilder.build(), null, false)
|
||||
val notificationChannelId = NotificationUtils.getNotificationChannelId(
|
||||
applicationContext.resources
|
||||
.getString(R.string.nc_notification_channel_calls),
|
||||
applicationContext.resources
|
||||
.getString(R.string.nc_notification_channel_calls_description),
|
||||
true,
|
||||
NotificationManagerCompat.IMPORTANCE_HIGH,
|
||||
soundUri!!,
|
||||
audioAttributesBuilder.build(),
|
||||
null,
|
||||
false
|
||||
)
|
||||
|
||||
createNotificationChannel(applicationContext!!,
|
||||
notificationChannelId, applicationContext.resources
|
||||
.getString(R.string.nc_notification_channel_calls), applicationContext.resources
|
||||
.getString(R.string.nc_notification_channel_calls_description), true,
|
||||
NotificationManagerCompat.IMPORTANCE_HIGH, soundUri, audioAttributesBuilder.build(), null, false)
|
||||
createNotificationChannel(
|
||||
applicationContext!!,
|
||||
notificationChannelId,
|
||||
applicationContext.resources
|
||||
.getString(R.string.nc_notification_channel_calls),
|
||||
applicationContext.resources
|
||||
.getString(R.string.nc_notification_channel_calls_description),
|
||||
true,
|
||||
NotificationManagerCompat.IMPORTANCE_HIGH,
|
||||
soundUri,
|
||||
audioAttributesBuilder.build(),
|
||||
null,
|
||||
false
|
||||
)
|
||||
|
||||
val uri = Uri.parse(signatureVerification!!.userEntity.baseUrl)
|
||||
val baseUrl = uri.host
|
||||
|
||||
val notification = NotificationCompat.Builder(this@MagicFirebaseMessagingService, notificationChannelId)
|
||||
val notification =
|
||||
NotificationCompat.Builder(this@MagicFirebaseMessagingService, notificationChannelId)
|
||||
.setPriority(NotificationCompat.PRIORITY_HIGH)
|
||||
.setCategory(NotificationCompat.CATEGORY_CALL)
|
||||
.setSmallIcon(R.drawable.ic_call_black_24dp)
|
||||
@ -213,7 +247,7 @@ class MagicFirebaseMessagingService : FirebaseMessagingService() {
|
||||
.setContentTitle(EmojiCompat.get().process(decryptedPushMessage!!.subject))
|
||||
.setAutoCancel(true)
|
||||
.setOngoing(true)
|
||||
//.setTimeoutAfter(45000L)
|
||||
// .setTimeoutAfter(45000L)
|
||||
.setContentIntent(fullScreenPendingIntent)
|
||||
.setFullScreenIntent(fullScreenPendingIntent, true)
|
||||
.setSound(soundUri)
|
||||
@ -224,10 +258,12 @@ class MagicFirebaseMessagingService : FirebaseMessagingService() {
|
||||
startForeground(decryptedPushMessage!!.timestamp.toInt(), notification)
|
||||
} else {
|
||||
val messageData = Data.Builder()
|
||||
.putString(BundleKeys.KEY_NOTIFICATION_SUBJECT, subject)
|
||||
.putString(BundleKeys.KEY_NOTIFICATION_SIGNATURE, signature)
|
||||
.putString(BundleKeys.KEY_NOTIFICATION_SUBJECT, subject)
|
||||
.putString(BundleKeys.KEY_NOTIFICATION_SIGNATURE, signature)
|
||||
.build()
|
||||
val pushNotificationWork =
|
||||
OneTimeWorkRequest.Builder(NotificationWorker::class.java).setInputData(messageData)
|
||||
.build()
|
||||
val pushNotificationWork = OneTimeWorkRequest.Builder(NotificationWorker::class.java).setInputData(messageData).build()
|
||||
WorkManager.getInstance().enqueue(pushNotificationWork)
|
||||
}
|
||||
}
|
||||
@ -244,47 +280,59 @@ class MagicFirebaseMessagingService : FirebaseMessagingService() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkIfCallIsActive(signatureVerification: SignatureVerification, decryptedPushMessage: DecryptedPushMessage) {
|
||||
val ncApi = retrofit!!.newBuilder().client(okHttpClient!!.newBuilder().cookieJar(JavaNetCookieJar(CookieManager())).build()).build().create(NcApi::class.java)
|
||||
private fun checkIfCallIsActive(
|
||||
signatureVerification: SignatureVerification,
|
||||
decryptedPushMessage: DecryptedPushMessage
|
||||
) {
|
||||
val ncApi = retrofit!!.newBuilder()
|
||||
.client(okHttpClient!!.newBuilder().cookieJar(JavaNetCookieJar(CookieManager())).build()).build()
|
||||
.create(NcApi::class.java)
|
||||
var hasParticipantsInCall = false
|
||||
var inCallOnDifferentDevice = false
|
||||
|
||||
ncApi.getPeersForCall(ApiUtils.getCredentials(signatureVerification.userEntity.username, signatureVerification.userEntity.token),
|
||||
ApiUtils.getUrlForCall(signatureVerification.userEntity.baseUrl,
|
||||
decryptedPushMessage.id))
|
||||
.takeWhile {
|
||||
isServiceInForeground
|
||||
ncApi.getPeersForCall(
|
||||
ApiUtils.getCredentials(signatureVerification.userEntity.username, signatureVerification.userEntity.token),
|
||||
ApiUtils.getUrlForCall(
|
||||
signatureVerification.userEntity.baseUrl,
|
||||
decryptedPushMessage.id
|
||||
)
|
||||
)
|
||||
.takeWhile {
|
||||
isServiceInForeground
|
||||
}
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe(object : Observer<ParticipantsOverall> {
|
||||
override fun onSubscribe(d: Disposable) {
|
||||
}
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe(object : Observer<ParticipantsOverall> {
|
||||
override fun onSubscribe(d: Disposable) {
|
||||
}
|
||||
|
||||
override fun onNext(participantsOverall: ParticipantsOverall) {
|
||||
val participantList: List<Participant> = participantsOverall.ocs.data
|
||||
hasParticipantsInCall = participantList.isNotEmpty()
|
||||
if (!hasParticipantsInCall) {
|
||||
for (participant in participantList) {
|
||||
if (participant.userId == signatureVerification.userEntity.userId) {
|
||||
inCallOnDifferentDevice = true
|
||||
break
|
||||
}
|
||||
override fun onNext(participantsOverall: ParticipantsOverall) {
|
||||
val participantList: List<Participant> = participantsOverall.ocs.data
|
||||
hasParticipantsInCall = participantList.isNotEmpty()
|
||||
if (!hasParticipantsInCall) {
|
||||
for (participant in participantList) {
|
||||
if (participant.userId == signatureVerification.userEntity.userId) {
|
||||
inCallOnDifferentDevice = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasParticipantsInCall || inCallOnDifferentDevice) {
|
||||
stopForeground(true)
|
||||
handler.removeCallbacksAndMessages(null)
|
||||
} else if (isServiceInForeground) {
|
||||
handler.postDelayed({
|
||||
if (!hasParticipantsInCall || inCallOnDifferentDevice) {
|
||||
stopForeground(true)
|
||||
handler.removeCallbacksAndMessages(null)
|
||||
} else if (isServiceInForeground) {
|
||||
handler.postDelayed(
|
||||
{
|
||||
checkIfCallIsActive(signatureVerification, decryptedPushMessage)
|
||||
}, 5000)
|
||||
}
|
||||
},
|
||||
5000
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onError(e: Throwable) {}
|
||||
override fun onComplete() {
|
||||
}
|
||||
})
|
||||
override fun onError(e: Throwable) {}
|
||||
override fun onComplete() {
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -76,8 +76,11 @@ open class BaseActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
fun showCertificateDialog(cert: X509Certificate, magicTrustManager: MagicTrustManager,
|
||||
sslErrorHandler: SslErrorHandler?) {
|
||||
fun showCertificateDialog(
|
||||
cert: X509Certificate,
|
||||
magicTrustManager: MagicTrustManager,
|
||||
sslErrorHandler: SslErrorHandler?
|
||||
) {
|
||||
val formatter = DateFormat.getDateInstance(DateFormat.LONG)
|
||||
val validFrom = formatter.format(cert.notBefore)
|
||||
val validUntil = formatter.format(cert.notAfter)
|
||||
@ -101,30 +104,30 @@ open class BaseActivity : AppCompatActivity() {
|
||||
issuedFor = cert.subjectDN.name
|
||||
}
|
||||
|
||||
@SuppressLint("StringFormatMatches") val dialogText = String.format(resources
|
||||
@SuppressLint("StringFormatMatches") val dialogText = String.format(
|
||||
resources
|
||||
.getString(R.string.nc_certificate_dialog_text),
|
||||
issuedBy, issuedFor, validFrom, validUntil)
|
||||
issuedBy, issuedFor, validFrom, validUntil
|
||||
)
|
||||
|
||||
LovelyStandardDialog(this)
|
||||
.setTopColorRes(R.color.nc_darkRed)
|
||||
.setNegativeButtonColorRes(R.color.nc_darkRed)
|
||||
.setPositiveButtonColorRes(R.color.colorPrimary)
|
||||
.setIcon(R.drawable.ic_security_white_24dp)
|
||||
.setTitle(R.string.nc_certificate_dialog_title)
|
||||
.setMessage(dialogText)
|
||||
.setPositiveButton(R.string.nc_yes) { v ->
|
||||
magicTrustManager.addCertInTrustStore(cert)
|
||||
sslErrorHandler?.proceed()
|
||||
}
|
||||
.setNegativeButton(R.string.nc_no) { view1 ->
|
||||
sslErrorHandler?.cancel()
|
||||
}
|
||||
.show()
|
||||
|
||||
.setTopColorRes(R.color.nc_darkRed)
|
||||
.setNegativeButtonColorRes(R.color.nc_darkRed)
|
||||
.setPositiveButtonColorRes(R.color.colorPrimary)
|
||||
.setIcon(R.drawable.ic_security_white_24dp)
|
||||
.setTitle(R.string.nc_certificate_dialog_title)
|
||||
.setMessage(dialogText)
|
||||
.setPositiveButton(R.string.nc_yes) { v ->
|
||||
magicTrustManager.addCertInTrustStore(cert)
|
||||
sslErrorHandler?.proceed()
|
||||
}
|
||||
.setNegativeButton(R.string.nc_no) { view1 ->
|
||||
sslErrorHandler?.cancel()
|
||||
}
|
||||
.show()
|
||||
} catch (e: CertificateParsingException) {
|
||||
Log.d(TAG, "Failed to parse the certificate")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
|
@ -38,7 +38,6 @@ import pl.droidsonroids.gif.GifDrawable
|
||||
import pl.droidsonroids.gif.GifImageView
|
||||
import java.io.File
|
||||
|
||||
|
||||
class FullScreenImageActivity : AppCompatActivity() {
|
||||
|
||||
private lateinit var path: String
|
||||
@ -55,9 +54,11 @@ class FullScreenImageActivity : AppCompatActivity() {
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
return if (item.itemId == R.id.share) {
|
||||
val shareUri = FileProvider.getUriForFile(this,
|
||||
BuildConfig.APPLICATION_ID,
|
||||
File(path))
|
||||
val shareUri = FileProvider.getUriForFile(
|
||||
this,
|
||||
BuildConfig.APPLICATION_ID,
|
||||
File(path)
|
||||
)
|
||||
|
||||
val shareIntent: Intent = Intent().apply {
|
||||
action = Intent.ACTION_SEND
|
||||
@ -78,19 +79,19 @@ class FullScreenImageActivity : AppCompatActivity() {
|
||||
|
||||
setContentView(R.layout.activity_full_screen_image)
|
||||
setSupportActionBar(findViewById(R.id.imageview_toolbar))
|
||||
supportActionBar?.setDisplayShowTitleEnabled(false);
|
||||
supportActionBar?.setDisplayShowTitleEnabled(false)
|
||||
|
||||
imageWrapperView = findViewById(R.id.image_wrapper_view)
|
||||
photoView = findViewById(R.id.photo_view)
|
||||
gifView = findViewById(R.id.gif_view)
|
||||
|
||||
photoView.setOnPhotoTapListener{ view, x, y ->
|
||||
photoView.setOnPhotoTapListener { view, x, y ->
|
||||
toggleFullscreen()
|
||||
}
|
||||
photoView.setOnOutsidePhotoTapListener{
|
||||
photoView.setOnOutsidePhotoTapListener {
|
||||
toggleFullscreen()
|
||||
}
|
||||
gifView.setOnClickListener{
|
||||
gifView.setOnClickListener {
|
||||
toggleFullscreen()
|
||||
}
|
||||
|
||||
@ -115,29 +116,33 @@ class FullScreenImageActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun toggleFullscreen(){
|
||||
showFullscreen = !showFullscreen;
|
||||
if (showFullscreen){
|
||||
private fun toggleFullscreen() {
|
||||
showFullscreen = !showFullscreen
|
||||
if (showFullscreen) {
|
||||
hideSystemUI()
|
||||
supportActionBar?.hide()
|
||||
} else{
|
||||
} else {
|
||||
showSystemUI()
|
||||
supportActionBar?.show()
|
||||
}
|
||||
}
|
||||
|
||||
private fun hideSystemUI() {
|
||||
window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_IMMERSIVE
|
||||
window.decorView.systemUiVisibility = (
|
||||
View.SYSTEM_UI_FLAG_IMMERSIVE
|
||||
or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
|
||||
or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
||||
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||
or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
|
||||
or View.SYSTEM_UI_FLAG_FULLSCREEN)
|
||||
or View.SYSTEM_UI_FLAG_FULLSCREEN
|
||||
)
|
||||
}
|
||||
|
||||
private fun showSystemUI() {
|
||||
window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE
|
||||
window.decorView.systemUiVisibility = (
|
||||
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
|
||||
or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
||||
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN)
|
||||
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -22,7 +22,6 @@ package com.nextcloud.talk.activities
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
@ -33,7 +32,6 @@ import autodagger.AutoInjector
|
||||
import com.google.android.exoplayer2.MediaItem
|
||||
import com.google.android.exoplayer2.Player
|
||||
import com.google.android.exoplayer2.SimpleExoPlayer
|
||||
import com.google.android.exoplayer2.ui.PlayerControlView
|
||||
import com.google.android.exoplayer2.ui.StyledPlayerView
|
||||
import com.nextcloud.talk.BuildConfig
|
||||
import com.nextcloud.talk.R
|
||||
@ -54,9 +52,11 @@ class FullScreenMediaActivity : AppCompatActivity(), Player.EventListener {
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
return if (item.itemId == R.id.share) {
|
||||
val shareUri = FileProvider.getUriForFile(this,
|
||||
BuildConfig.APPLICATION_ID,
|
||||
File(path))
|
||||
val shareUri = FileProvider.getUriForFile(
|
||||
this,
|
||||
BuildConfig.APPLICATION_ID,
|
||||
File(path)
|
||||
)
|
||||
|
||||
val shareIntent: Intent = Intent().apply {
|
||||
action = Intent.ACTION_SEND
|
||||
@ -82,11 +82,11 @@ class FullScreenMediaActivity : AppCompatActivity(), Player.EventListener {
|
||||
|
||||
setContentView(R.layout.activity_full_screen_media)
|
||||
setSupportActionBar(findViewById(R.id.mediaview_toolbar))
|
||||
supportActionBar?.setDisplayShowTitleEnabled(false);
|
||||
supportActionBar?.setDisplayShowTitleEnabled(false)
|
||||
|
||||
playerView = findViewById(R.id.player_view)
|
||||
|
||||
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
||||
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
||||
|
||||
playerView.showController()
|
||||
if (isAudioOnly) {
|
||||
@ -121,7 +121,7 @@ class FullScreenMediaActivity : AppCompatActivity(), Player.EventListener {
|
||||
|
||||
private fun initializePlayer() {
|
||||
player = SimpleExoPlayer.Builder(applicationContext).build()
|
||||
playerView.player = player;
|
||||
playerView.player = player
|
||||
player.playWhenReady = true
|
||||
player.addListener(this)
|
||||
}
|
||||
@ -131,17 +131,21 @@ class FullScreenMediaActivity : AppCompatActivity(), Player.EventListener {
|
||||
}
|
||||
|
||||
private fun hideSystemUI() {
|
||||
window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_IMMERSIVE
|
||||
window.decorView.systemUiVisibility = (
|
||||
View.SYSTEM_UI_FLAG_IMMERSIVE
|
||||
or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
|
||||
or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
||||
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||
or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
|
||||
or View.SYSTEM_UI_FLAG_FULLSCREEN)
|
||||
or View.SYSTEM_UI_FLAG_FULLSCREEN
|
||||
)
|
||||
}
|
||||
|
||||
private fun showSystemUI() {
|
||||
window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE
|
||||
window.decorView.systemUiVisibility = (
|
||||
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
|
||||
or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
||||
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN)
|
||||
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -34,7 +34,6 @@ import com.nextcloud.talk.application.NextcloudTalkApplication
|
||||
import io.noties.markwon.Markwon
|
||||
import java.io.File
|
||||
|
||||
|
||||
@AutoInjector(NextcloudTalkApplication::class)
|
||||
class FullScreenTextViewerActivity : AppCompatActivity() {
|
||||
|
||||
@ -48,9 +47,11 @@ class FullScreenTextViewerActivity : AppCompatActivity() {
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
return if (item.itemId == R.id.share) {
|
||||
val shareUri = FileProvider.getUriForFile(this,
|
||||
BuildConfig.APPLICATION_ID,
|
||||
File(path))
|
||||
val shareUri = FileProvider.getUriForFile(
|
||||
this,
|
||||
BuildConfig.APPLICATION_ID,
|
||||
File(path)
|
||||
)
|
||||
|
||||
val shareIntent: Intent = Intent().apply {
|
||||
action = Intent.ACTION_SEND
|
||||
@ -71,8 +72,7 @@ class FullScreenTextViewerActivity : AppCompatActivity() {
|
||||
|
||||
setContentView(R.layout.activity_full_screen_text)
|
||||
setSupportActionBar(findViewById(R.id.textview_toolbar))
|
||||
supportActionBar?.setDisplayShowTitleEnabled(false);
|
||||
|
||||
supportActionBar?.setDisplayShowTitleEnabled(false)
|
||||
textView = findViewById(R.id.text_view)
|
||||
|
||||
val fileName = intent.getStringExtra("FILE_NAME")
|
||||
@ -81,13 +81,12 @@ class FullScreenTextViewerActivity : AppCompatActivity() {
|
||||
var text = readFile(path)
|
||||
|
||||
if (isMarkdown) {
|
||||
val markwon = Markwon.create(applicationContext);
|
||||
markwon.setMarkdown(textView, text);
|
||||
val markwon = Markwon.create(applicationContext)
|
||||
markwon.setMarkdown(textView, text)
|
||||
} else {
|
||||
textView.text = text
|
||||
}
|
||||
}
|
||||
|
||||
private fun readFile(fileName: String) = File(fileName).inputStream().readBytes().toString(Charsets.UTF_8)
|
||||
|
||||
}
|
||||
|
@ -48,7 +48,7 @@ class MagicCallActivity : BaseActivity() {
|
||||
|
||||
@BindView(R.id.controller_container)
|
||||
lateinit var container: ViewGroup
|
||||
|
||||
|
||||
@BindView(R.id.chatControllerView)
|
||||
lateinit var chatContainer: ViewGroup
|
||||
|
||||
@ -60,10 +60,12 @@ class MagicCallActivity : BaseActivity() {
|
||||
NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this)
|
||||
|
||||
requestWindowFeature(Window.FEATURE_NO_TITLE)
|
||||
window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN or
|
||||
window.addFlags(
|
||||
WindowManager.LayoutParams.FLAG_FULLSCREEN or
|
||||
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON or
|
||||
WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD or WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED or
|
||||
WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON)
|
||||
WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
|
||||
)
|
||||
window.decorView.systemUiVisibility = systemUiVisibility
|
||||
|
||||
setContentView(R.layout.activity_magic_call)
|
||||
@ -74,26 +76,32 @@ class MagicCallActivity : BaseActivity() {
|
||||
|
||||
if (!router!!.hasRootController()) {
|
||||
if (intent.getBooleanExtra(BundleKeys.KEY_FROM_NOTIFICATION_START_CALL, false)) {
|
||||
router!!.setRoot(RouterTransaction.with(CallNotificationController(intent.extras))
|
||||
router!!.setRoot(
|
||||
RouterTransaction.with(CallNotificationController(intent.extras))
|
||||
.pushChangeHandler(HorizontalChangeHandler())
|
||||
.popChangeHandler(HorizontalChangeHandler()))
|
||||
.popChangeHandler(HorizontalChangeHandler())
|
||||
)
|
||||
} else {
|
||||
router!!.setRoot(RouterTransaction.with(CallController(intent.extras))
|
||||
router!!.setRoot(
|
||||
RouterTransaction.with(CallController(intent.extras))
|
||||
.pushChangeHandler(HorizontalChangeHandler())
|
||||
.popChangeHandler(HorizontalChangeHandler()))
|
||||
.popChangeHandler(HorizontalChangeHandler())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val extras = intent.extras ?: Bundle()
|
||||
extras.putBoolean("showToggleChat", true)
|
||||
|
||||
|
||||
chatController = ChatController(extras)
|
||||
chatRouter = Conductor.attachRouter(this, chatContainer, savedInstanceState)
|
||||
chatRouter!!.setRoot(RouterTransaction.with(chatController)
|
||||
chatRouter!!.setRoot(
|
||||
RouterTransaction.with(chatController)
|
||||
.pushChangeHandler(HorizontalChangeHandler())
|
||||
.popChangeHandler(HorizontalChangeHandler()))
|
||||
.popChangeHandler(HorizontalChangeHandler())
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
fun showChat() {
|
||||
chatContainer.visibility = View.VISIBLE
|
||||
container.visibility = View.GONE
|
||||
|
@ -79,23 +79,31 @@ class MainActivity : BaseActivity(), ActionBarProvider {
|
||||
|
||||
@BindView(R.id.appBar)
|
||||
lateinit var appBar: AppBarLayout
|
||||
|
||||
@BindView(R.id.toolbar)
|
||||
lateinit var toolbar: MaterialToolbar
|
||||
|
||||
@BindView(R.id.home_toolbar)
|
||||
lateinit var searchCardView: MaterialCardView
|
||||
|
||||
@BindView(R.id.search_text)
|
||||
lateinit var searchInputText: MaterialTextView
|
||||
|
||||
@BindView(R.id.switch_account_button)
|
||||
lateinit var settingsButton: MaterialButton
|
||||
|
||||
@BindView(R.id.controller_container)
|
||||
lateinit var container: ViewGroup
|
||||
|
||||
@Inject
|
||||
lateinit var userUtils: UserUtils
|
||||
|
||||
@Inject
|
||||
lateinit var dataStore: ReactiveEntityStore<Persistable>
|
||||
|
||||
@Inject
|
||||
lateinit var sqlCipherDatabaseSource: SqlCipherDatabaseSource
|
||||
|
||||
@Inject
|
||||
lateinit var ncApi: NcApi
|
||||
|
||||
@ -124,39 +132,53 @@ class MainActivity : BaseActivity(), ActionBarProvider {
|
||||
|
||||
if (intent.hasExtra(BundleKeys.KEY_FROM_NOTIFICATION_START_CALL)) {
|
||||
if (!router!!.hasRootController()) {
|
||||
router!!.setRoot(RouterTransaction.with(ConversationsListController())
|
||||
router!!.setRoot(
|
||||
RouterTransaction.with(ConversationsListController())
|
||||
.pushChangeHandler(HorizontalChangeHandler())
|
||||
.popChangeHandler(HorizontalChangeHandler()))
|
||||
.popChangeHandler(HorizontalChangeHandler())
|
||||
)
|
||||
}
|
||||
onNewIntent(intent)
|
||||
} else if (!router!!.hasRootController()) {
|
||||
if (hasDb) {
|
||||
if (userUtils.anyUserExists()) {
|
||||
router!!.setRoot(RouterTransaction.with(ConversationsListController())
|
||||
router!!.setRoot(
|
||||
RouterTransaction.with(ConversationsListController())
|
||||
.pushChangeHandler(HorizontalChangeHandler())
|
||||
.popChangeHandler(HorizontalChangeHandler()))
|
||||
.popChangeHandler(HorizontalChangeHandler())
|
||||
)
|
||||
} else {
|
||||
if (!TextUtils.isEmpty(resources.getString(R.string.weblogin_url))) {
|
||||
router!!.pushController(RouterTransaction.with(
|
||||
WebViewLoginController(resources.getString(R.string.weblogin_url), false))
|
||||
router!!.pushController(
|
||||
RouterTransaction.with(
|
||||
WebViewLoginController(resources.getString(R.string.weblogin_url), false)
|
||||
)
|
||||
.pushChangeHandler(HorizontalChangeHandler())
|
||||
.popChangeHandler(HorizontalChangeHandler()))
|
||||
.popChangeHandler(HorizontalChangeHandler())
|
||||
)
|
||||
} else {
|
||||
router!!.setRoot(RouterTransaction.with(ServerSelectionController())
|
||||
router!!.setRoot(
|
||||
RouterTransaction.with(ServerSelectionController())
|
||||
.pushChangeHandler(HorizontalChangeHandler())
|
||||
.popChangeHandler(HorizontalChangeHandler()))
|
||||
.popChangeHandler(HorizontalChangeHandler())
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!TextUtils.isEmpty(resources.getString(R.string.weblogin_url))) {
|
||||
router!!.pushController(RouterTransaction.with(
|
||||
WebViewLoginController(resources.getString(R.string.weblogin_url), false))
|
||||
router!!.pushController(
|
||||
RouterTransaction.with(
|
||||
WebViewLoginController(resources.getString(R.string.weblogin_url), false)
|
||||
)
|
||||
.pushChangeHandler(HorizontalChangeHandler())
|
||||
.popChangeHandler(HorizontalChangeHandler()))
|
||||
.popChangeHandler(HorizontalChangeHandler())
|
||||
)
|
||||
} else {
|
||||
router!!.setRoot(RouterTransaction.with(ServerSelectionController())
|
||||
router!!.setRoot(
|
||||
RouterTransaction.with(ServerSelectionController())
|
||||
.pushChangeHandler(HorizontalChangeHandler())
|
||||
.popChangeHandler(HorizontalChangeHandler()))
|
||||
.popChangeHandler(HorizontalChangeHandler())
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -167,7 +189,7 @@ class MainActivity : BaseActivity(), ActionBarProvider {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
checkIfWeAreSecure()
|
||||
}
|
||||
|
||||
|
||||
handleActionFromContact(intent)
|
||||
}
|
||||
|
||||
@ -182,7 +204,7 @@ class MainActivity : BaseActivity(), ActionBarProvider {
|
||||
// userId @ server
|
||||
userId = cursor.getString(cursor.getColumnIndex(ContactsContract.Data.DATA1))
|
||||
}
|
||||
|
||||
|
||||
cursor.close()
|
||||
}
|
||||
|
||||
@ -193,65 +215,82 @@ class MainActivity : BaseActivity(), ActionBarProvider {
|
||||
if (userUtils.currentUser?.baseUrl?.endsWith(baseUrl) == true) {
|
||||
startConversation(user)
|
||||
} else {
|
||||
Snackbar.make(container, R.string.nc_phone_book_integration_account_not_found, Snackbar
|
||||
.LENGTH_LONG).show()
|
||||
Snackbar.make(
|
||||
container, R.string.nc_phone_book_integration_account_not_found,
|
||||
Snackbar.LENGTH_LONG
|
||||
).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun startConversation(userId: String) {
|
||||
val roomType = "1"
|
||||
val currentUser = userUtils.currentUser ?: return
|
||||
|
||||
val credentials = ApiUtils.getCredentials(currentUser.username, currentUser.token)
|
||||
val retrofitBucket = ApiUtils.getRetrofitBucketForCreateRoom(currentUser.baseUrl, roomType,
|
||||
userId, null)
|
||||
ncApi.createRoom(credentials,
|
||||
retrofitBucket.url, retrofitBucket.queryMap)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : Observer<RoomOverall> {
|
||||
override fun onSubscribe(d: Disposable) {}
|
||||
override fun onNext(roomOverall: RoomOverall) {
|
||||
val conversationIntent = Intent(context, MagicCallActivity::class.java)
|
||||
val bundle = Bundle()
|
||||
bundle.putParcelable(KEY_USER_ENTITY, currentUser)
|
||||
bundle.putString(KEY_ROOM_TOKEN, roomOverall.ocs.data.token)
|
||||
bundle.putString(KEY_ROOM_ID, roomOverall.ocs.data.roomId)
|
||||
if (currentUser.hasSpreedFeatureCapability("chat-v2")) {
|
||||
ncApi.getRoom(credentials,
|
||||
ApiUtils.getRoom(currentUser.baseUrl,
|
||||
roomOverall.ocs.data.token))
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : Observer<RoomOverall> {
|
||||
override fun onSubscribe(d: Disposable) {}
|
||||
override fun onNext(roomOverall: RoomOverall) {
|
||||
bundle.putParcelable(KEY_ACTIVE_CONVERSATION,
|
||||
Parcels.wrap(roomOverall.ocs.data))
|
||||
remapChatController(router!!, currentUser.id,
|
||||
roomOverall.ocs.data.token, bundle, true)
|
||||
}
|
||||
val retrofitBucket = ApiUtils.getRetrofitBucketForCreateRoom(
|
||||
currentUser.baseUrl, roomType,
|
||||
userId, null
|
||||
)
|
||||
ncApi.createRoom(
|
||||
credentials,
|
||||
retrofitBucket.url, retrofitBucket.queryMap
|
||||
)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : Observer<RoomOverall> {
|
||||
override fun onSubscribe(d: Disposable) {}
|
||||
override fun onNext(roomOverall: RoomOverall) {
|
||||
val conversationIntent = Intent(context, MagicCallActivity::class.java)
|
||||
val bundle = Bundle()
|
||||
bundle.putParcelable(KEY_USER_ENTITY, currentUser)
|
||||
bundle.putString(KEY_ROOM_TOKEN, roomOverall.ocs.data.token)
|
||||
bundle.putString(KEY_ROOM_ID, roomOverall.ocs.data.roomId)
|
||||
if (currentUser.hasSpreedFeatureCapability("chat-v2")) {
|
||||
ncApi.getRoom(
|
||||
credentials,
|
||||
ApiUtils.getRoom(
|
||||
currentUser.baseUrl,
|
||||
roomOverall.ocs.data.token
|
||||
)
|
||||
)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : Observer<RoomOverall> {
|
||||
override fun onSubscribe(d: Disposable) {}
|
||||
override fun onNext(roomOverall: RoomOverall) {
|
||||
bundle.putParcelable(
|
||||
KEY_ACTIVE_CONVERSATION,
|
||||
Parcels.wrap(roomOverall.ocs.data)
|
||||
)
|
||||
remapChatController(
|
||||
router!!, currentUser.id,
|
||||
roomOverall.ocs.data.token, bundle, true
|
||||
)
|
||||
}
|
||||
|
||||
override fun onError(e: Throwable) {}
|
||||
override fun onComplete() {}
|
||||
})
|
||||
} else {
|
||||
conversationIntent.putExtras(bundle)
|
||||
startActivity(conversationIntent)
|
||||
Handler().postDelayed({
|
||||
override fun onError(e: Throwable) {}
|
||||
override fun onComplete() {}
|
||||
})
|
||||
} else {
|
||||
conversationIntent.putExtras(bundle)
|
||||
startActivity(conversationIntent)
|
||||
Handler().postDelayed(
|
||||
{
|
||||
if (!isDestroyed) {
|
||||
router!!.popCurrentController()
|
||||
}
|
||||
}, 100)
|
||||
}
|
||||
},
|
||||
100
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onError(e: Throwable) {}
|
||||
override fun onComplete() {}
|
||||
})
|
||||
override fun onError(e: Throwable) {}
|
||||
override fun onComplete() {}
|
||||
})
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.M)
|
||||
@ -260,16 +299,17 @@ class MainActivity : BaseActivity(), ActionBarProvider {
|
||||
if (keyguardManager.isKeyguardSecure && appPreferences.isScreenLocked) {
|
||||
if (!SecurityUtils.checkIfWeAreAuthenticated(appPreferences.screenLockTimeout)) {
|
||||
if (router != null && router!!.getControllerWithTag(LockedController.TAG) == null) {
|
||||
router!!.pushController(RouterTransaction.with(LockedController())
|
||||
router!!.pushController(
|
||||
RouterTransaction.with(LockedController())
|
||||
.pushChangeHandler(VerticalChangeHandler())
|
||||
.popChangeHandler(VerticalChangeHandler())
|
||||
.tag(LockedController.TAG))
|
||||
.tag(LockedController.TAG)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun onNewIntent(intent: Intent) {
|
||||
super.onNewIntent(intent)
|
||||
|
||||
@ -277,12 +317,16 @@ class MainActivity : BaseActivity(), ActionBarProvider {
|
||||
|
||||
if (intent.hasExtra(BundleKeys.KEY_FROM_NOTIFICATION_START_CALL)) {
|
||||
if (intent.getBooleanExtra(BundleKeys.KEY_FROM_NOTIFICATION_START_CALL, false)) {
|
||||
router!!.pushController(RouterTransaction.with(CallNotificationController(intent.extras))
|
||||
router!!.pushController(
|
||||
RouterTransaction.with(CallNotificationController(intent.extras))
|
||||
.pushChangeHandler(HorizontalChangeHandler())
|
||||
.popChangeHandler(HorizontalChangeHandler()))
|
||||
.popChangeHandler(HorizontalChangeHandler())
|
||||
)
|
||||
} else {
|
||||
ConductorRemapping.remapChatController(router!!, intent.getLongExtra(BundleKeys.KEY_INTERNAL_USER_ID, -1),
|
||||
intent.getStringExtra(BundleKeys.KEY_ROOM_TOKEN), intent.extras!!, false)
|
||||
ConductorRemapping.remapChatController(
|
||||
router!!, intent.getLongExtra(BundleKeys.KEY_INTERNAL_USER_ID, -1),
|
||||
intent.getStringExtra(BundleKeys.KEY_ROOM_TOKEN), intent.extras!!, false
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -39,7 +39,6 @@ import autodagger.AutoInjector
|
||||
import butterknife.BindView
|
||||
import butterknife.ButterKnife
|
||||
import coil.load
|
||||
import coil.transform.CircleCropTransformation
|
||||
import com.amulyakhare.textdrawable.TextDrawable
|
||||
import com.facebook.drawee.view.SimpleDraweeView
|
||||
import com.nextcloud.talk.R
|
||||
@ -51,7 +50,6 @@ import com.nextcloud.talk.utils.DisplayUtils
|
||||
import com.nextcloud.talk.utils.TextMatchers
|
||||
import com.nextcloud.talk.utils.preferences.AppPreferences
|
||||
import com.stfalcon.chatkit.messages.MessageHolders
|
||||
import com.stfalcon.chatkit.utils.DateFormatter
|
||||
import javax.inject.Inject
|
||||
|
||||
@AutoInjector(NextcloudTalkApplication::class)
|
||||
@ -104,8 +102,8 @@ class MagicIncomingTextMessageViewHolder(incomingView: View) : MessageHolders
|
||||
|
||||
init {
|
||||
ButterKnife.bind(
|
||||
this,
|
||||
itemView
|
||||
this,
|
||||
itemView
|
||||
)
|
||||
}
|
||||
|
||||
@ -131,13 +129,13 @@ class MagicIncomingTextMessageViewHolder(incomingView: View) : MessageHolders
|
||||
messageUserAvatarView?.setImageDrawable(DisplayUtils.getRoundedDrawable(layerDrawable))
|
||||
} else if (message.actorType == "bots") {
|
||||
val drawable = TextDrawable.builder()
|
||||
.beginConfig()
|
||||
.bold()
|
||||
.endConfig()
|
||||
.buildRound(
|
||||
">",
|
||||
context!!.resources.getColor(R.color.black)
|
||||
)
|
||||
.beginConfig()
|
||||
.bold()
|
||||
.endConfig()
|
||||
.buildRound(
|
||||
">",
|
||||
context!!.resources.getColor(R.color.black)
|
||||
)
|
||||
messageUserAvatarView!!.visibility = View.VISIBLE
|
||||
messageUserAvatarView?.setImageDrawable(drawable)
|
||||
}
|
||||
@ -165,9 +163,9 @@ class MagicIncomingTextMessageViewHolder(incomingView: View) : MessageHolders
|
||||
}
|
||||
|
||||
val bubbleDrawable = DisplayUtils.getMessageSelector(
|
||||
bgBubbleColor,
|
||||
resources.getColor(R.color.transparent),
|
||||
bgBubbleColor, bubbleResource
|
||||
bgBubbleColor,
|
||||
resources.getColor(R.color.transparent),
|
||||
bgBubbleColor, bubbleResource
|
||||
)
|
||||
ViewCompat.setBackground(bubble, bubbleDrawable)
|
||||
|
||||
@ -187,23 +185,23 @@ class MagicIncomingTextMessageViewHolder(incomingView: View) : MessageHolders
|
||||
if (individualHashMap["type"] == "user" || individualHashMap["type"] == "guest" || individualHashMap["type"] == "call") {
|
||||
if (individualHashMap["id"] == message.activeUser!!.userId) {
|
||||
messageString = DisplayUtils.searchAndReplaceWithMentionSpan(
|
||||
messageText!!.context,
|
||||
messageString,
|
||||
individualHashMap["id"]!!,
|
||||
individualHashMap["name"]!!,
|
||||
individualHashMap["type"]!!,
|
||||
message.activeUser!!,
|
||||
R.xml.chip_you
|
||||
messageText!!.context,
|
||||
messageString,
|
||||
individualHashMap["id"]!!,
|
||||
individualHashMap["name"]!!,
|
||||
individualHashMap["type"]!!,
|
||||
message.activeUser!!,
|
||||
R.xml.chip_you
|
||||
)
|
||||
} else {
|
||||
messageString = DisplayUtils.searchAndReplaceWithMentionSpan(
|
||||
messageText!!.context,
|
||||
messageString,
|
||||
individualHashMap["id"]!!,
|
||||
individualHashMap["name"]!!,
|
||||
individualHashMap["type"]!!,
|
||||
message.activeUser!!,
|
||||
R.xml.chip_others
|
||||
messageText!!.context,
|
||||
messageString,
|
||||
individualHashMap["id"]!!,
|
||||
individualHashMap["name"]!!,
|
||||
individualHashMap["type"]!!,
|
||||
message.activeUser!!,
|
||||
R.xml.chip_others
|
||||
)
|
||||
}
|
||||
} else if (individualHashMap["type"] == "file") {
|
||||
@ -231,18 +229,21 @@ class MagicIncomingTextMessageViewHolder(incomingView: View) : MessageHolders
|
||||
parentChatMessage.imageUrl?.let {
|
||||
quotedMessagePreview?.visibility = View.VISIBLE
|
||||
quotedMessagePreview?.load(it) {
|
||||
addHeader("Authorization", ApiUtils.getCredentials(message.activeUser.username, message.activeUser.token))
|
||||
addHeader(
|
||||
"Authorization",
|
||||
ApiUtils.getCredentials(message.activeUser.username, message.activeUser.token)
|
||||
)
|
||||
}
|
||||
} ?: run {
|
||||
quotedMessagePreview?.visibility = View.GONE
|
||||
}
|
||||
quotedUserName?.text = parentChatMessage.actorDisplayName
|
||||
?: context!!.getText(R.string.nc_nick_guest)
|
||||
?: context!!.getText(R.string.nc_nick_guest)
|
||||
quotedMessage?.text = parentChatMessage.text
|
||||
|
||||
quotedUserName?.setTextColor(context!!.resources.getColor(R.color.textColorMaxContrast))
|
||||
|
||||
if(parentChatMessage.actorId?.equals(message.activeUser.userId) == true) {
|
||||
if (parentChatMessage.actorId?.equals(message.activeUser.userId) == true) {
|
||||
quoteColoredView?.setBackgroundResource(R.color.colorPrimary)
|
||||
} else {
|
||||
quoteColoredView?.setBackgroundResource(R.color.textColorMaxContrast)
|
||||
|
@ -36,7 +36,6 @@ import autodagger.AutoInjector
|
||||
import butterknife.BindView
|
||||
import butterknife.ButterKnife
|
||||
import coil.load
|
||||
import coil.transform.CircleCropTransformation
|
||||
import com.google.android.flexbox.FlexboxLayout
|
||||
import com.nextcloud.talk.R
|
||||
import com.nextcloud.talk.application.NextcloudTalkApplication
|
||||
@ -48,8 +47,7 @@ import com.nextcloud.talk.utils.DisplayUtils.getMessageSelector
|
||||
import com.nextcloud.talk.utils.DisplayUtils.searchAndReplaceWithMentionSpan
|
||||
import com.nextcloud.talk.utils.TextMatchers
|
||||
import com.stfalcon.chatkit.messages.MessageHolders.OutcomingTextMessageViewHolder
|
||||
import com.stfalcon.chatkit.utils.DateFormatter
|
||||
import java.util.*
|
||||
import java.util.HashMap
|
||||
import javax.inject.Inject
|
||||
|
||||
@AutoInjector(NextcloudTalkApplication::class)
|
||||
@ -57,6 +55,7 @@ class MagicOutcomingTextMessageViewHolder(itemView: View) : OutcomingTextMessage
|
||||
@JvmField
|
||||
@BindView(R.id.messageText)
|
||||
var messageText: EmojiTextView? = null
|
||||
|
||||
@JvmField
|
||||
@BindView(R.id.messageTime)
|
||||
var messageTimeView: TextView? = null
|
||||
@ -104,20 +103,26 @@ class MagicOutcomingTextMessageViewHolder(itemView: View) : OutcomingTextMessage
|
||||
for (key in messageParameters.keys) {
|
||||
val individualHashMap: HashMap<String, String>? = message.messageParameters[key]
|
||||
if (individualHashMap != null) {
|
||||
if (individualHashMap["type"] == "user" || (individualHashMap["type"]
|
||||
== "guest") || individualHashMap["type"] == "call") {
|
||||
messageString = searchAndReplaceWithMentionSpan(messageText!!.context,
|
||||
messageString,
|
||||
individualHashMap["id"]!!,
|
||||
individualHashMap["name"]!!,
|
||||
individualHashMap["type"]!!,
|
||||
message.activeUser,
|
||||
R.xml.chip_others)
|
||||
if (individualHashMap["type"] == "user" || (
|
||||
individualHashMap["type"] == "guest"
|
||||
) || individualHashMap["type"] == "call"
|
||||
) {
|
||||
messageString = searchAndReplaceWithMentionSpan(
|
||||
messageText!!.context,
|
||||
messageString,
|
||||
individualHashMap["id"]!!,
|
||||
individualHashMap["name"]!!,
|
||||
individualHashMap["type"]!!,
|
||||
message.activeUser,
|
||||
R.xml.chip_others
|
||||
)
|
||||
} else if (individualHashMap["type"] == "file") {
|
||||
realView.setOnClickListener(View.OnClickListener { v: View? ->
|
||||
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(individualHashMap["link"]))
|
||||
context!!.startActivity(browserIntent)
|
||||
})
|
||||
realView.setOnClickListener(
|
||||
View.OnClickListener { v: View? ->
|
||||
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(individualHashMap["link"]))
|
||||
context!!.startActivity(browserIntent)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -135,17 +140,19 @@ class MagicOutcomingTextMessageViewHolder(itemView: View) : OutcomingTextMessage
|
||||
}
|
||||
if (message.isGrouped) {
|
||||
val bubbleDrawable = getMessageSelector(
|
||||
bgBubbleColor,
|
||||
resources.getColor(R.color.transparent),
|
||||
bgBubbleColor,
|
||||
R.drawable.shape_grouped_outcoming_message)
|
||||
bgBubbleColor,
|
||||
resources.getColor(R.color.transparent),
|
||||
bgBubbleColor,
|
||||
R.drawable.shape_grouped_outcoming_message
|
||||
)
|
||||
ViewCompat.setBackground(bubble, bubbleDrawable)
|
||||
} else {
|
||||
val bubbleDrawable = getMessageSelector(
|
||||
bgBubbleColor,
|
||||
resources.getColor(R.color.transparent),
|
||||
bgBubbleColor,
|
||||
R.drawable.shape_outcoming_message)
|
||||
bgBubbleColor,
|
||||
resources.getColor(R.color.transparent),
|
||||
bgBubbleColor,
|
||||
R.drawable.shape_outcoming_message
|
||||
)
|
||||
ViewCompat.setBackground(bubble, bubbleDrawable)
|
||||
}
|
||||
messageText!!.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize)
|
||||
@ -160,13 +167,16 @@ class MagicOutcomingTextMessageViewHolder(itemView: View) : OutcomingTextMessage
|
||||
parentChatMessage.imageUrl?.let {
|
||||
quotedMessagePreview?.visibility = View.VISIBLE
|
||||
quotedMessagePreview?.load(it) {
|
||||
addHeader("Authorization", ApiUtils.getCredentials(message.activeUser.username, message.activeUser.token))
|
||||
addHeader(
|
||||
"Authorization",
|
||||
ApiUtils.getCredentials(message.activeUser.username, message.activeUser.token)
|
||||
)
|
||||
}
|
||||
} ?: run {
|
||||
quotedMessagePreview?.visibility = View.GONE
|
||||
}
|
||||
quotedUserName?.text = parentChatMessage.actorDisplayName
|
||||
?: context!!.getText(R.string.nc_nick_guest)
|
||||
?: context!!.getText(R.string.nc_nick_guest)
|
||||
quotedMessage?.text = parentChatMessage.text
|
||||
quotedMessage?.setTextColor(context!!.resources.getColor(R.color.nc_outcoming_text_default))
|
||||
quotedUserName?.setTextColor(context!!.resources.getColor(R.color.nc_grey))
|
||||
|
@ -90,6 +90,7 @@ class NextcloudTalkApplication : MultiDexApplication(), LifecycleObserver {
|
||||
|
||||
@Inject
|
||||
lateinit var appPreferences: AppPreferences
|
||||
|
||||
@Inject
|
||||
lateinit var okHttpClient: OkHttpClient
|
||||
//endregion
|
||||
@ -105,8 +106,10 @@ class NextcloudTalkApplication : MultiDexApplication(), LifecycleObserver {
|
||||
WebRtcAudioManager.setBlacklistDeviceForOpenSLESUsage(true)
|
||||
}
|
||||
|
||||
PeerConnectionFactory.initialize(PeerConnectionFactory.InitializationOptions.builder(this)
|
||||
.createInitializationOptions())
|
||||
PeerConnectionFactory.initialize(
|
||||
PeerConnectionFactory.InitializationOptions.builder(this)
|
||||
.createInitializationOptions()
|
||||
)
|
||||
} catch (e: UnsatisfiedLinkError) {
|
||||
Log.w(TAG, e)
|
||||
}
|
||||
@ -120,8 +123,8 @@ class NextcloudTalkApplication : MultiDexApplication(), LifecycleObserver {
|
||||
|
||||
val securityKeyManager = SecurityKeyManager.getInstance()
|
||||
val securityKeyConfig = SecurityKeyManagerConfig.Builder()
|
||||
.setEnableDebugLogging(BuildConfig.DEBUG)
|
||||
.build()
|
||||
.setEnableDebugLogging(BuildConfig.DEBUG)
|
||||
.build()
|
||||
securityKeyManager.init(this, securityKeyConfig)
|
||||
|
||||
initializeWebRtc()
|
||||
@ -136,13 +139,15 @@ class NextcloudTalkApplication : MultiDexApplication(), LifecycleObserver {
|
||||
super.onCreate()
|
||||
|
||||
val imagePipelineConfig = ImagePipelineConfig.newBuilder(this)
|
||||
.setNetworkFetcher(OkHttpNetworkFetcherWithCache(okHttpClient))
|
||||
.setMainDiskCacheConfig(DiskCacheConfig.newBuilder(this)
|
||||
.setMaxCacheSize(0)
|
||||
.setMaxCacheSizeOnLowDiskSpace(0)
|
||||
.setMaxCacheSizeOnVeryLowDiskSpace(0)
|
||||
.build())
|
||||
.build()
|
||||
.setNetworkFetcher(OkHttpNetworkFetcherWithCache(okHttpClient))
|
||||
.setMainDiskCacheConfig(
|
||||
DiskCacheConfig.newBuilder(this)
|
||||
.setMaxCacheSize(0)
|
||||
.setMaxCacheSizeOnLowDiskSpace(0)
|
||||
.setMaxCacheSizeOnVeryLowDiskSpace(0)
|
||||
.build()
|
||||
)
|
||||
.build()
|
||||
|
||||
Fresco.initialize(this, imagePipelineConfig)
|
||||
Security.insertProviderAt(Conscrypt.newProvider(), 1)
|
||||
@ -152,8 +157,10 @@ class NextcloudTalkApplication : MultiDexApplication(), LifecycleObserver {
|
||||
|
||||
val pushRegistrationWork = OneTimeWorkRequest.Builder(PushRegistrationWorker::class.java).build()
|
||||
val accountRemovalWork = OneTimeWorkRequest.Builder(AccountRemovalWorker::class.java).build()
|
||||
val periodicCapabilitiesUpdateWork = PeriodicWorkRequest.Builder(CapabilitiesWorker::class.java,
|
||||
12, TimeUnit.HOURS).build()
|
||||
val periodicCapabilitiesUpdateWork = PeriodicWorkRequest.Builder(
|
||||
CapabilitiesWorker::class.java,
|
||||
12, TimeUnit.HOURS
|
||||
).build()
|
||||
val capabilitiesUpdateWork = OneTimeWorkRequest.Builder(CapabilitiesWorker::class.java).build()
|
||||
val signalingSettingsWork = OneTimeWorkRequest.Builder(SignalingSettingsWorker::class.java).build()
|
||||
|
||||
@ -161,7 +168,11 @@ class NextcloudTalkApplication : MultiDexApplication(), LifecycleObserver {
|
||||
WorkManager.getInstance().enqueue(accountRemovalWork)
|
||||
WorkManager.getInstance().enqueue(capabilitiesUpdateWork)
|
||||
WorkManager.getInstance().enqueue(signalingSettingsWork)
|
||||
WorkManager.getInstance().enqueueUniquePeriodicWork("DailyCapabilitiesUpdateWork", ExistingPeriodicWorkPolicy.REPLACE, periodicCapabilitiesUpdateWork)
|
||||
WorkManager.getInstance().enqueueUniquePeriodicWork(
|
||||
"DailyCapabilitiesUpdateWork",
|
||||
ExistingPeriodicWorkPolicy.REPLACE,
|
||||
periodicCapabilitiesUpdateWork
|
||||
)
|
||||
|
||||
val config = BundledEmojiCompatConfig(this)
|
||||
config.setReplaceAll(true)
|
||||
@ -176,17 +187,16 @@ class NextcloudTalkApplication : MultiDexApplication(), LifecycleObserver {
|
||||
}
|
||||
//endregion
|
||||
|
||||
|
||||
//region Protected methods
|
||||
protected fun buildComponent() {
|
||||
componentApplication = DaggerNextcloudTalkApplicationComponent.builder()
|
||||
.busModule(BusModule())
|
||||
.contextModule(ContextModule(applicationContext))
|
||||
.databaseModule(DatabaseModule())
|
||||
.restModule(RestModule(applicationContext))
|
||||
.userModule(UserModule())
|
||||
.arbitraryStorageModule(ArbitraryStorageModule())
|
||||
.build()
|
||||
.busModule(BusModule())
|
||||
.contextModule(ContextModule(applicationContext))
|
||||
.databaseModule(DatabaseModule())
|
||||
.restModule(RestModule(applicationContext))
|
||||
.userModule(UserModule())
|
||||
.arbitraryStorageModule(ArbitraryStorageModule())
|
||||
.build()
|
||||
}
|
||||
|
||||
override fun attachBaseContext(base: Context) {
|
||||
@ -196,19 +206,20 @@ class NextcloudTalkApplication : MultiDexApplication(), LifecycleObserver {
|
||||
|
||||
private fun buildDefaultImageLoader(): ImageLoader {
|
||||
return ImageLoader.Builder(applicationContext)
|
||||
.availableMemoryPercentage(0.5) // Use 50% of the application's available memory.
|
||||
.crossfade(true) // Show a short crossfade when loading images from network or disk into an ImageView.
|
||||
.componentRegistry {
|
||||
if (SDK_INT >= P) {
|
||||
add(ImageDecoderDecoder(applicationContext))
|
||||
} else {
|
||||
add(GifDecoder())
|
||||
}
|
||||
add(SvgDecoder(applicationContext))
|
||||
.availableMemoryPercentage(0.5) // Use 50% of the application's available memory.
|
||||
.crossfade(true) // Show a short crossfade when loading images from network or disk into an ImageView.
|
||||
.componentRegistry {
|
||||
if (SDK_INT >= P) {
|
||||
add(ImageDecoderDecoder(applicationContext))
|
||||
} else {
|
||||
add(GifDecoder())
|
||||
}
|
||||
.okHttpClient(okHttpClient)
|
||||
.build()
|
||||
add(SvgDecoder(applicationContext))
|
||||
}
|
||||
.okHttpClient(okHttpClient)
|
||||
.build()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val TAG = NextcloudTalkApplication::class.java.simpleName
|
||||
//region Singleton
|
||||
|
@ -44,10 +44,6 @@ import android.widget.ImageView;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.constraintlayout.widget.ConstraintLayout;
|
||||
|
||||
import com.bluelinelabs.conductor.RouterTransaction;
|
||||
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler;
|
||||
import com.bluelinelabs.logansquare.LoganSquare;
|
||||
@ -71,7 +67,6 @@ import com.nextcloud.talk.models.RingtoneSettings;
|
||||
import com.nextcloud.talk.models.database.UserEntity;
|
||||
import com.nextcloud.talk.models.json.conversations.Conversation;
|
||||
import com.nextcloud.talk.models.json.conversations.RoomOverall;
|
||||
import com.nextcloud.talk.models.json.conversations.RoomsOverall;
|
||||
import com.nextcloud.talk.models.json.participants.Participant;
|
||||
import com.nextcloud.talk.models.json.participants.ParticipantsOverall;
|
||||
import com.nextcloud.talk.utils.ApiUtils;
|
||||
@ -94,6 +89,9 @@ import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.constraintlayout.widget.ConstraintLayout;
|
||||
import autodagger.AutoInjector;
|
||||
import butterknife.BindView;
|
||||
import butterknife.OnClick;
|
||||
@ -206,13 +204,13 @@ public class CallNotificationController extends BaseController {
|
||||
originalBundle.putString(BundleKeys.INSTANCE.getKEY_CONVERSATION_NAME(), currentConversation.getDisplayName());
|
||||
|
||||
getRouter().replaceTopController(RouterTransaction.with(new CallController(originalBundle))
|
||||
.popChangeHandler(new HorizontalChangeHandler())
|
||||
.pushChangeHandler(new HorizontalChangeHandler()));
|
||||
.popChangeHandler(new HorizontalChangeHandler())
|
||||
.pushChangeHandler(new HorizontalChangeHandler()));
|
||||
}
|
||||
|
||||
private void checkIfAnyParticipantsRemainInRoom() {
|
||||
ncApi.getPeersForCall(credentials, ApiUtils.getUrlForCall(userBeingCalled.getBaseUrl(),
|
||||
currentConversation.getToken()))
|
||||
currentConversation.getToken()))
|
||||
.subscribeOn(Schedulers.io())
|
||||
.takeWhile(observable -> !leavingScreen)
|
||||
.subscribe(new Observer<ParticipantsOverall>() {
|
||||
@ -261,7 +259,7 @@ public class CallNotificationController extends BaseController {
|
||||
|
||||
private void handleFromNotification() {
|
||||
boolean isConversationApiV3 = userBeingCalled.hasSpreedFeatureCapability("conversation-v3");
|
||||
if(isConversationApiV3) {
|
||||
if (isConversationApiV3) {
|
||||
ncApi.getRoom(credentials, ApiUtils.getRoomV3(userBeingCalled.getBaseUrl(), roomId))
|
||||
.subscribeOn(Schedulers.io())
|
||||
.retry(3)
|
||||
@ -279,12 +277,12 @@ public class CallNotificationController extends BaseController {
|
||||
|
||||
boolean hasCallFlags = userBeingCalled.hasSpreedFeatureCapability("conversation-call-flags");
|
||||
if (hasCallFlags) {
|
||||
if (isInCallWithVideo(currentConversation.callFlag)){
|
||||
if (isInCallWithVideo(currentConversation.callFlag)) {
|
||||
incomingCallVoiceOrVideoTextView.setText(String.format(getResources().getString(R.string.nc_call_video),
|
||||
getResources().getString(R.string.nc_app_name)));
|
||||
getResources().getString(R.string.nc_app_name)));
|
||||
} else {
|
||||
incomingCallVoiceOrVideoTextView.setText(String.format(getResources().getString(R.string.nc_call_voice),
|
||||
getResources().getString(R.string.nc_app_name)));
|
||||
getResources().getString(R.string.nc_app_name)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -412,7 +410,7 @@ public class CallNotificationController extends BaseController {
|
||||
|
||||
ImageRequest imageRequest =
|
||||
DisplayUtils.getImageRequestForUrl(ApiUtils.getUrlForAvatarWithName(userBeingCalled.getBaseUrl(),
|
||||
currentConversation.getName(), R.dimen.avatar_size_very_big), null);
|
||||
currentConversation.getName(), R.dimen.avatar_size_very_big), null);
|
||||
|
||||
ImagePipeline imagePipeline = Fresco.getImagePipeline();
|
||||
DataSource<CloseableReference<CloseableImage>> dataSource = imagePipeline.fetchDecodedImage(imageRequest, null);
|
||||
@ -422,11 +420,11 @@ public class CallNotificationController extends BaseController {
|
||||
protected void onNewResultImpl(@Nullable Bitmap bitmap) {
|
||||
if (avatarImageView != null) {
|
||||
avatarImageView.getHierarchy().setImage(new BitmapDrawable(bitmap), 100,
|
||||
true);
|
||||
true);
|
||||
|
||||
if (getResources() != null) {
|
||||
incomingTextRelativeLayout.setBackground(getResources().getDrawable(R.drawable
|
||||
.incoming_gradient));
|
||||
.incoming_gradient));
|
||||
}
|
||||
|
||||
if ((AvatarStatusCodeHolder.getInstance().getStatusCode() == 200 || AvatarStatusCodeHolder.getInstance().getStatusCode() == 0) &&
|
||||
@ -512,7 +510,7 @@ public class CallNotificationController extends BaseController {
|
||||
if (TextUtils.isEmpty(callRingtonePreferenceString)) {
|
||||
// play default sound
|
||||
ringtoneUri = Uri.parse("android.resource://" + getApplicationContext().getPackageName() +
|
||||
"/raw/librem_by_feandesign_call");
|
||||
"/raw/librem_by_feandesign_call");
|
||||
} else {
|
||||
try {
|
||||
RingtoneSettings ringtoneSettings = LoganSquare.parse(callRingtonePreferenceString, RingtoneSettings.class);
|
||||
@ -520,7 +518,7 @@ public class CallNotificationController extends BaseController {
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Failed to parse ringtone settings");
|
||||
ringtoneUri = Uri.parse("android.resource://" + getApplicationContext().getPackageName() +
|
||||
"/raw/librem_by_feandesign_call");
|
||||
"/raw/librem_by_feandesign_call");
|
||||
}
|
||||
}
|
||||
|
||||
@ -531,7 +529,7 @@ public class CallNotificationController extends BaseController {
|
||||
|
||||
mediaPlayer.setLooping(true);
|
||||
AudioAttributes audioAttributes = new AudioAttributes.Builder().setContentType(AudioAttributes
|
||||
.CONTENT_TYPE_SONIFICATION).setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE).build();
|
||||
.CONTENT_TYPE_SONIFICATION).setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE).build();
|
||||
mediaPlayer.setAudioAttributes(audioAttributes);
|
||||
|
||||
mediaPlayer.setOnPreparedListener(mp -> mediaPlayer.start());
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -85,50 +85,69 @@ import io.reactivex.schedulers.Schedulers
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
import org.greenrobot.eventbus.ThreadMode
|
||||
import java.util.*
|
||||
import java.util.Calendar
|
||||
import java.util.Collections
|
||||
import java.util.Comparator
|
||||
import java.util.Locale
|
||||
import javax.inject.Inject
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
|
||||
@AutoInjector(NextcloudTalkApplication::class)
|
||||
class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleAdapter.OnItemClickListener {
|
||||
|
||||
@BindView(R.id.notification_settings)
|
||||
lateinit var notificationsPreferenceScreen: MaterialPreferenceScreen
|
||||
|
||||
@BindView(R.id.progressBar)
|
||||
lateinit var progressBar: ProgressBar
|
||||
|
||||
@BindView(R.id.conversation_info_message_notifications)
|
||||
lateinit var messageNotificationLevel: MaterialChoicePreference
|
||||
|
||||
@BindView(R.id.webinar_settings)
|
||||
lateinit var conversationInfoWebinar: MaterialPreferenceScreen
|
||||
|
||||
@BindView(R.id.conversation_info_lobby)
|
||||
lateinit var conversationInfoLobby: MaterialSwitchPreference
|
||||
|
||||
@BindView(R.id.conversation_info_name)
|
||||
lateinit var nameCategoryView: MaterialPreferenceCategory
|
||||
|
||||
@BindView(R.id.start_time_preferences)
|
||||
lateinit var startTimeView: MaterialStandardPreference
|
||||
|
||||
@BindView(R.id.avatar_image)
|
||||
lateinit var conversationAvatarImageView: SimpleDraweeView
|
||||
|
||||
@BindView(R.id.display_name_text)
|
||||
lateinit var conversationDisplayName: EmojiTextView
|
||||
|
||||
@BindView(R.id.participants_list_category)
|
||||
lateinit var participantsListCategory: MaterialPreferenceCategory
|
||||
|
||||
@BindView(R.id.addParticipantsAction)
|
||||
lateinit var addParticipantsAction: MaterialStandardPreference;
|
||||
lateinit var addParticipantsAction: MaterialStandardPreference
|
||||
|
||||
@BindView(R.id.recycler_view)
|
||||
lateinit var recyclerView: RecyclerView
|
||||
|
||||
@BindView(R.id.deleteConversationAction)
|
||||
lateinit var deleteConversationAction: MaterialStandardPreference
|
||||
|
||||
@BindView(R.id.leaveConversationAction)
|
||||
lateinit var leaveConversationAction: MaterialStandardPreference
|
||||
|
||||
@BindView(R.id.ownOptions)
|
||||
lateinit var ownOptionsCategory: MaterialPreferenceCategory
|
||||
|
||||
@BindView(R.id.muteCalls)
|
||||
lateinit var muteCalls: MaterialSwitchPreference
|
||||
|
||||
@set:Inject
|
||||
lateinit var ncApi: NcApi
|
||||
|
||||
@set:Inject
|
||||
lateinit var context: Context
|
||||
|
||||
@set:Inject
|
||||
lateinit var eventBus: EventBus
|
||||
|
||||
@ -164,7 +183,7 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
|
||||
NextcloudTalkApplication.sharedApplication?.componentApplication?.inject(this)
|
||||
conversationUser = args.getParcelable(BundleKeys.KEY_USER_ENTITY)
|
||||
conversationToken = args.getString(BundleKeys.KEY_ROOM_TOKEN)
|
||||
hasAvatarSpacing = args.getBoolean(BundleKeys.KEY_ROOM_ONE_TO_ONE, false);
|
||||
hasAvatarSpacing = args.getBoolean(BundleKeys.KEY_ROOM_ONE_TO_ONE, false)
|
||||
credentials = ApiUtils.getCredentials(conversationUser!!.username, conversationUser.token)
|
||||
}
|
||||
|
||||
@ -207,14 +226,19 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
|
||||
}
|
||||
|
||||
private fun setupWebinaryView() {
|
||||
if (conversationUser!!.hasSpreedFeatureCapability("webinary-lobby") && (conversation!!.type
|
||||
== Conversation.ConversationType.ROOM_GROUP_CALL || conversation!!.type ==
|
||||
Conversation.ConversationType.ROOM_PUBLIC_CALL) && conversation!!.canModerate(conversationUser)) {
|
||||
if (conversationUser!!.hasSpreedFeatureCapability("webinary-lobby") &&
|
||||
(
|
||||
conversation!!.type == Conversation.ConversationType.ROOM_GROUP_CALL ||
|
||||
conversation!!.type == Conversation.ConversationType.ROOM_PUBLIC_CALL
|
||||
) &&
|
||||
conversation!!.canModerate(conversationUser)
|
||||
) {
|
||||
conversationInfoWebinar.visibility = View.VISIBLE
|
||||
|
||||
val isLobbyOpenToModeratorsOnly = conversation!!.lobbyState == Conversation.LobbyState.LOBBY_STATE_MODERATORS_ONLY
|
||||
val isLobbyOpenToModeratorsOnly =
|
||||
conversation!!.lobbyState == Conversation.LobbyState.LOBBY_STATE_MODERATORS_ONLY
|
||||
(conversationInfoLobby.findViewById<View>(R.id.mp_checkable) as SwitchCompat)
|
||||
.isChecked = isLobbyOpenToModeratorsOnly
|
||||
.isChecked = isLobbyOpenToModeratorsOnly
|
||||
|
||||
reconfigureLobbyTimerView()
|
||||
|
||||
@ -225,12 +249,17 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
|
||||
currentTimeCalendar.timeInMillis = conversation!!.lobbyTimer * 1000
|
||||
}
|
||||
|
||||
dateTimePicker(minDateTime = Calendar.getInstance(), requireFutureDateTime =
|
||||
true, currentDateTime = currentTimeCalendar, dateTimeCallback = { _,
|
||||
dateTime ->
|
||||
reconfigureLobbyTimerView(dateTime)
|
||||
submitLobbyChanges()
|
||||
})
|
||||
dateTimePicker(
|
||||
minDateTime = Calendar.getInstance(),
|
||||
requireFutureDateTime =
|
||||
true,
|
||||
currentDateTime = currentTimeCalendar,
|
||||
dateTimeCallback = { _,
|
||||
dateTime ->
|
||||
reconfigureLobbyTimerView(dateTime)
|
||||
submitLobbyChanges()
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -253,7 +282,7 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
|
||||
}
|
||||
|
||||
conversation!!.lobbyState = if (isChecked) Conversation.LobbyState
|
||||
.LOBBY_STATE_MODERATORS_ONLY else Conversation.LobbyState.LOBBY_STATE_ALL_PARTICIPANTS
|
||||
.LOBBY_STATE_MODERATORS_ONLY else Conversation.LobbyState.LOBBY_STATE_ALL_PARTICIPANTS
|
||||
|
||||
if (conversation!!.lobbyTimer != null && conversation!!.lobbyTimer != java.lang.Long.MIN_VALUE && conversation!!.lobbyTimer != 0L) {
|
||||
startTimeView.setSummary(DateUtils.getLocalDateStringFromTimestampForLobby(conversation!!.lobbyTimer))
|
||||
@ -269,27 +298,34 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
|
||||
}
|
||||
|
||||
fun submitLobbyChanges() {
|
||||
val state = if ((conversationInfoLobby.findViewById<View>(R.id
|
||||
.mp_checkable) as SwitchCompat).isChecked) 1 else 0
|
||||
ncApi.setLobbyForConversation(ApiUtils.getCredentials(conversationUser!!.username,
|
||||
conversationUser.token), ApiUtils.getUrlForLobbyForConversation
|
||||
(conversationUser.baseUrl, conversation!!.token), state, conversation!!.lobbyTimer)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : Observer<GenericOverall> {
|
||||
override fun onComplete() {
|
||||
}
|
||||
val state = if (
|
||||
(
|
||||
conversationInfoLobby.findViewById<View>(
|
||||
R.id.mp_checkable
|
||||
) as SwitchCompat
|
||||
).isChecked
|
||||
) 1 else 0
|
||||
ncApi.setLobbyForConversation(
|
||||
ApiUtils.getCredentials(conversationUser!!.username, conversationUser.token),
|
||||
ApiUtils.getUrlForLobbyForConversation(conversationUser.baseUrl, conversation!!.token),
|
||||
state,
|
||||
conversation!!.lobbyTimer
|
||||
)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : Observer<GenericOverall> {
|
||||
override fun onComplete() {
|
||||
}
|
||||
|
||||
override fun onSubscribe(d: Disposable) {
|
||||
}
|
||||
override fun onSubscribe(d: Disposable) {
|
||||
}
|
||||
|
||||
override fun onNext(t: GenericOverall) {
|
||||
}
|
||||
override fun onNext(t: GenericOverall) {
|
||||
}
|
||||
|
||||
override fun onError(e: Throwable) {
|
||||
}
|
||||
|
||||
})
|
||||
override fun onError(e: Throwable) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun showLovelyDialog(dialogId: Int, savedInstanceState: Bundle) {
|
||||
@ -313,17 +349,21 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
|
||||
private fun showDeleteConversationDialog(savedInstanceState: Bundle?) {
|
||||
if (activity != null) {
|
||||
LovelyStandardDialog(activity, LovelyStandardDialog.ButtonLayout.HORIZONTAL)
|
||||
.setTopColorRes(R.color.nc_darkRed)
|
||||
.setIcon(DisplayUtils.getTintedDrawable(context!!.resources,
|
||||
R.drawable.ic_delete_black_24dp, R.color.bg_default))
|
||||
.setPositiveButtonColor(context!!.resources.getColor(R.color.nc_darkRed))
|
||||
.setTitle(R.string.nc_delete_call)
|
||||
.setMessage(conversation!!.deleteWarningMessage)
|
||||
.setPositiveButton(R.string.nc_delete) { deleteConversation() }
|
||||
.setNegativeButton(R.string.nc_cancel, null)
|
||||
.setInstanceStateHandler(ID_DELETE_CONVERSATION_DIALOG, saveStateHandler!!)
|
||||
.setSavedInstanceState(savedInstanceState)
|
||||
.show()
|
||||
.setTopColorRes(R.color.nc_darkRed)
|
||||
.setIcon(
|
||||
DisplayUtils.getTintedDrawable(
|
||||
context!!.resources,
|
||||
R.drawable.ic_delete_black_24dp, R.color.bg_default
|
||||
)
|
||||
)
|
||||
.setPositiveButtonColor(context!!.resources.getColor(R.color.nc_darkRed))
|
||||
.setTitle(R.string.nc_delete_call)
|
||||
.setMessage(conversation!!.deleteWarningMessage)
|
||||
.setPositiveButton(R.string.nc_delete) { deleteConversation() }
|
||||
.setNegativeButton(R.string.nc_cancel, null)
|
||||
.setInstanceStateHandler(ID_DELETE_CONVERSATION_DIALOG, saveStateHandler!!)
|
||||
.setSavedInstanceState(savedInstanceState)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
|
||||
@ -335,8 +375,8 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
|
||||
override fun onRestoreViewState(view: View, savedViewState: Bundle) {
|
||||
super.onRestoreViewState(view, savedViewState)
|
||||
if (LovelySaveStateHandler.wasDialogOnScreen(savedViewState)) {
|
||||
//Dialog won't be restarted automatically, so we need to call this method.
|
||||
//Each dialog knows how to restore its state
|
||||
// Dialog won't be restarted automatically, so we need to call this method.
|
||||
// Each dialog knows how to restore its state
|
||||
showLovelyDialog(LovelySaveStateHandler.getSavedDialogId(savedViewState), savedViewState)
|
||||
}
|
||||
}
|
||||
@ -397,27 +437,28 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
|
||||
}
|
||||
|
||||
private fun getListOfParticipants() {
|
||||
ncApi.getPeersForCall(credentials, ApiUtils.getUrlForParticipants(conversationUser!!.baseUrl, conversationToken))
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : Observer<ParticipantsOverall> {
|
||||
override fun onSubscribe(d: Disposable) {
|
||||
participantsDisposable = d
|
||||
}
|
||||
ncApi.getPeersForCall(
|
||||
credentials,
|
||||
ApiUtils.getUrlForParticipants(conversationUser!!.baseUrl, conversationToken)
|
||||
)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : Observer<ParticipantsOverall> {
|
||||
override fun onSubscribe(d: Disposable) {
|
||||
participantsDisposable = d
|
||||
}
|
||||
|
||||
override fun onNext(participantsOverall: ParticipantsOverall) {
|
||||
handleParticipants(participantsOverall.ocs.data)
|
||||
}
|
||||
override fun onNext(participantsOverall: ParticipantsOverall) {
|
||||
handleParticipants(participantsOverall.ocs.data)
|
||||
}
|
||||
|
||||
override fun onError(e: Throwable) {
|
||||
|
||||
}
|
||||
|
||||
override fun onComplete() {
|
||||
participantsDisposable!!.dispose()
|
||||
}
|
||||
})
|
||||
override fun onError(e: Throwable) {
|
||||
}
|
||||
|
||||
override fun onComplete() {
|
||||
participantsDisposable!!.dispose()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@OnClick(R.id.addParticipantsAction)
|
||||
@ -430,21 +471,33 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
|
||||
existingParticipantsId.add(userItem.model.userId)
|
||||
}
|
||||
|
||||
bundle.putBoolean(BundleKeys.KEY_ADD_PARTICIPANTS, true);
|
||||
bundle.putBoolean(BundleKeys.KEY_ADD_PARTICIPANTS, true)
|
||||
bundle.putStringArrayList(BundleKeys.KEY_EXISTING_PARTICIPANTS, existingParticipantsId)
|
||||
bundle.putString(BundleKeys.KEY_TOKEN, conversation!!.token)
|
||||
|
||||
getRouter().pushController((RouterTransaction.with(ContactsController(bundle))
|
||||
.pushChangeHandler(HorizontalChangeHandler())
|
||||
.popChangeHandler(HorizontalChangeHandler())))
|
||||
getRouter().pushController(
|
||||
(
|
||||
RouterTransaction.with(
|
||||
ContactsController(bundle)
|
||||
)
|
||||
.pushChangeHandler(
|
||||
HorizontalChangeHandler()
|
||||
)
|
||||
.popChangeHandler(
|
||||
HorizontalChangeHandler()
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@OnClick(R.id.leaveConversationAction)
|
||||
internal fun leaveConversation() {
|
||||
workerData?.let {
|
||||
WorkManager.getInstance().enqueue(OneTimeWorkRequest.Builder
|
||||
(LeaveConversationWorker::class
|
||||
.java).setInputData(it).build()
|
||||
WorkManager.getInstance().enqueue(
|
||||
OneTimeWorkRequest.Builder(
|
||||
LeaveConversationWorker::class
|
||||
.java
|
||||
).setInputData(it).build()
|
||||
)
|
||||
popTwoLastControllers()
|
||||
}
|
||||
@ -452,8 +505,11 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
|
||||
|
||||
private fun deleteConversation() {
|
||||
workerData?.let {
|
||||
WorkManager.getInstance().enqueue(OneTimeWorkRequest.Builder
|
||||
(DeleteConversationWorker::class.java).setInputData(it).build())
|
||||
WorkManager.getInstance().enqueue(
|
||||
OneTimeWorkRequest.Builder(
|
||||
DeleteConversationWorker::class.java
|
||||
).setInputData(it).build()
|
||||
)
|
||||
popTwoLastControllers()
|
||||
}
|
||||
}
|
||||
@ -471,69 +527,67 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
|
||||
|
||||
private fun fetchRoomInfo() {
|
||||
ncApi.getRoom(credentials, ApiUtils.getRoom(conversationUser!!.baseUrl, conversationToken))
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : Observer<RoomOverall> {
|
||||
override fun onSubscribe(d: Disposable) {
|
||||
roomDisposable = d
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : Observer<RoomOverall> {
|
||||
override fun onSubscribe(d: Disposable) {
|
||||
roomDisposable = d
|
||||
}
|
||||
|
||||
override fun onNext(roomOverall: RoomOverall) {
|
||||
conversation = roomOverall.ocs.data
|
||||
|
||||
val conversationCopy = conversation
|
||||
|
||||
if (conversationCopy!!.canModerate(conversationUser)) {
|
||||
addParticipantsAction.visibility = View.VISIBLE
|
||||
} else {
|
||||
addParticipantsAction.visibility = View.GONE
|
||||
}
|
||||
|
||||
override fun onNext(roomOverall: RoomOverall) {
|
||||
conversation = roomOverall.ocs.data
|
||||
if (isAttached && (!isBeingDestroyed || !isDestroyed)) {
|
||||
ownOptionsCategory.visibility = View.VISIBLE
|
||||
|
||||
val conversationCopy = conversation
|
||||
setupWebinaryView()
|
||||
|
||||
if (conversationCopy!!.canModerate(conversationUser)) {
|
||||
addParticipantsAction.visibility = View.VISIBLE
|
||||
if (!conversation!!.canLeave(conversationUser)) {
|
||||
leaveConversationAction.visibility = View.GONE
|
||||
} else {
|
||||
addParticipantsAction.visibility = View.GONE
|
||||
leaveConversationAction.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
if (isAttached && (!isBeingDestroyed || !isDestroyed)) {
|
||||
ownOptionsCategory.visibility = View.VISIBLE
|
||||
|
||||
setupWebinaryView()
|
||||
|
||||
if (!conversation!!.canLeave(conversationUser)) {
|
||||
leaveConversationAction.visibility = View.GONE
|
||||
} else {
|
||||
leaveConversationAction.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
if (!conversation!!.canModerate(conversationUser)) {
|
||||
deleteConversationAction.visibility = View.GONE
|
||||
} else {
|
||||
deleteConversationAction.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
if (Conversation.ConversationType.ROOM_SYSTEM == conversation!!.type) {
|
||||
muteCalls.visibility = View.GONE
|
||||
}
|
||||
|
||||
getListOfParticipants()
|
||||
|
||||
progressBar.visibility = View.GONE
|
||||
|
||||
nameCategoryView.visibility = View.VISIBLE
|
||||
|
||||
conversationDisplayName.text = conversation!!.displayName
|
||||
|
||||
|
||||
loadConversationAvatar()
|
||||
adjustNotificationLevelUI()
|
||||
|
||||
notificationsPreferenceScreen.visibility = View.VISIBLE
|
||||
if (!conversation!!.canModerate(conversationUser)) {
|
||||
deleteConversationAction.visibility = View.GONE
|
||||
} else {
|
||||
deleteConversationAction.visibility = View.VISIBLE
|
||||
}
|
||||
}
|
||||
|
||||
override fun onError(e: Throwable) {
|
||||
if (Conversation.ConversationType.ROOM_SYSTEM == conversation!!.type) {
|
||||
muteCalls.visibility = View.GONE
|
||||
}
|
||||
|
||||
}
|
||||
getListOfParticipants()
|
||||
|
||||
override fun onComplete() {
|
||||
roomDisposable!!.dispose()
|
||||
progressBar.visibility = View.GONE
|
||||
|
||||
nameCategoryView.visibility = View.VISIBLE
|
||||
|
||||
conversationDisplayName.text = conversation!!.displayName
|
||||
|
||||
loadConversationAvatar()
|
||||
adjustNotificationLevelUI()
|
||||
|
||||
notificationsPreferenceScreen.visibility = View.VISIBLE
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
override fun onError(e: Throwable) {
|
||||
}
|
||||
|
||||
override fun onComplete() {
|
||||
roomDisposable!!.dispose()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun adjustNotificationLevelUI() {
|
||||
@ -543,12 +597,13 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
|
||||
messageNotificationLevel.alpha = 1.0f
|
||||
|
||||
if (conversation!!.notificationLevel != Conversation.NotificationLevel.DEFAULT) {
|
||||
val stringValue: String = when (EnumNotificationLevelConverter().convertToInt(conversation!!.notificationLevel)) {
|
||||
1 -> "always"
|
||||
2 -> "mention"
|
||||
3 -> "never"
|
||||
else -> "mention"
|
||||
}
|
||||
val stringValue: String =
|
||||
when (EnumNotificationLevelConverter().convertToInt(conversation!!.notificationLevel)) {
|
||||
1 -> "always"
|
||||
2 -> "mention"
|
||||
3 -> "never"
|
||||
else -> "mention"
|
||||
}
|
||||
|
||||
messageNotificationLevel.value = stringValue
|
||||
} else {
|
||||
@ -577,22 +632,38 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
|
||||
|
||||
private fun loadConversationAvatar() {
|
||||
when (conversation!!.type) {
|
||||
Conversation.ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL -> if (!TextUtils.isEmpty
|
||||
(conversation!!.name)) {
|
||||
Conversation.ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL -> if (
|
||||
!TextUtils.isEmpty(conversation!!.name)
|
||||
) {
|
||||
val draweeController = Fresco.newDraweeControllerBuilder()
|
||||
.setOldController(conversationAvatarImageView.controller)
|
||||
.setAutoPlayAnimations(true)
|
||||
.setImageRequest(DisplayUtils.getImageRequestForUrl(ApiUtils.getUrlForAvatarWithName(conversationUser!!.baseUrl,
|
||||
conversation!!.name, R.dimen.avatar_size_big), conversationUser))
|
||||
.build()
|
||||
.setOldController(conversationAvatarImageView.controller)
|
||||
.setAutoPlayAnimations(true)
|
||||
.setImageRequest(
|
||||
DisplayUtils.getImageRequestForUrl(
|
||||
ApiUtils.getUrlForAvatarWithName(
|
||||
conversationUser!!.baseUrl,
|
||||
conversation!!.name, R.dimen.avatar_size_big
|
||||
),
|
||||
conversationUser
|
||||
)
|
||||
)
|
||||
.build()
|
||||
conversationAvatarImageView.controller = draweeController
|
||||
}
|
||||
Conversation.ConversationType.ROOM_GROUP_CALL -> conversationAvatarImageView.hierarchy.setPlaceholderImage(DisplayUtils
|
||||
.getRoundedBitmapDrawableFromVectorDrawableResource(resources,
|
||||
R.drawable.ic_people_group_white_24px))
|
||||
Conversation.ConversationType.ROOM_PUBLIC_CALL -> conversationAvatarImageView.hierarchy.setPlaceholderImage(DisplayUtils
|
||||
.getRoundedBitmapDrawableFromVectorDrawableResource(resources,
|
||||
R.drawable.ic_link_white_24px))
|
||||
Conversation.ConversationType.ROOM_GROUP_CALL -> conversationAvatarImageView.hierarchy.setPlaceholderImage(
|
||||
DisplayUtils
|
||||
.getRoundedBitmapDrawableFromVectorDrawableResource(
|
||||
resources,
|
||||
R.drawable.ic_people_group_white_24px
|
||||
)
|
||||
)
|
||||
Conversation.ConversationType.ROOM_PUBLIC_CALL -> conversationAvatarImageView.hierarchy.setPlaceholderImage(
|
||||
DisplayUtils
|
||||
.getRoundedBitmapDrawableFromVectorDrawableResource(
|
||||
resources,
|
||||
R.drawable.ic_link_white_24px
|
||||
)
|
||||
)
|
||||
Conversation.ConversationType.ROOM_SYSTEM -> {
|
||||
val layers = arrayOfNulls<Drawable>(2)
|
||||
layers[0] = context.getDrawable(R.drawable.ic_launcher_background)
|
||||
@ -610,13 +681,14 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
|
||||
val userItem = adapter?.getItem(position) as UserItem
|
||||
val participant = userItem.model
|
||||
|
||||
|
||||
if (participant.userId != conversationUser!!.userId) {
|
||||
var items = mutableListOf(
|
||||
BasicListItemWithImage(R.drawable.ic_pencil_grey600_24dp, context.getString(R.string.nc_promote)),
|
||||
BasicListItemWithImage(R.drawable.ic_pencil_grey600_24dp, context.getString(R.string.nc_demote)),
|
||||
BasicListItemWithImage(R.drawable.ic_delete_grey600_24dp,
|
||||
context.getString(R.string.nc_remove_participant))
|
||||
BasicListItemWithImage(R.drawable.ic_pencil_grey600_24dp, context.getString(R.string.nc_promote)),
|
||||
BasicListItemWithImage(R.drawable.ic_pencil_grey600_24dp, context.getString(R.string.nc_demote)),
|
||||
BasicListItemWithImage(
|
||||
R.drawable.ic_delete_grey600_24dp,
|
||||
context.getString(R.string.nc_remove_participant)
|
||||
)
|
||||
)
|
||||
|
||||
if (!conversation!!.canModerate(conversationUser)) {
|
||||
@ -629,7 +701,6 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (items.isNotEmpty()) {
|
||||
MaterialDialog(activity!!, BottomSheet(WRAP_CONTENT)).show {
|
||||
cornerRadius(res = R.dimen.corner_radius)
|
||||
@ -639,38 +710,62 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
|
||||
|
||||
if (index == 0) {
|
||||
if (participant.type == Participant.ParticipantType.MODERATOR) {
|
||||
ncApi.demoteModeratorToUser(credentials, ApiUtils.getUrlForModerators(conversationUser.baseUrl, conversation!!.token), participant.userId)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe {
|
||||
getListOfParticipants()
|
||||
}
|
||||
ncApi.demoteModeratorToUser(
|
||||
credentials,
|
||||
ApiUtils.getUrlForModerators(conversationUser.baseUrl, conversation!!.token),
|
||||
participant.userId
|
||||
)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe {
|
||||
getListOfParticipants()
|
||||
}
|
||||
} else if (participant.type == Participant.ParticipantType.USER) {
|
||||
ncApi.promoteUserToModerator(credentials, ApiUtils.getUrlForModerators(conversationUser.baseUrl, conversation!!.token), participant.userId)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe {
|
||||
getListOfParticipants()
|
||||
}
|
||||
ncApi.promoteUserToModerator(
|
||||
credentials,
|
||||
ApiUtils.getUrlForModerators(conversationUser.baseUrl, conversation!!.token),
|
||||
participant.userId
|
||||
)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe {
|
||||
getListOfParticipants()
|
||||
}
|
||||
}
|
||||
} else if (index == 1) {
|
||||
if (participant.type == Participant.ParticipantType.GUEST ||
|
||||
participant.type == Participant.ParticipantType.USER_FOLLOWING_LINK) {
|
||||
ncApi.removeParticipantFromConversation(credentials, ApiUtils.getUrlForRemovingParticipantFromConversation(conversationUser.baseUrl, conversation!!.token, true), participant.sessionId)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe {
|
||||
getListOfParticipants()
|
||||
}
|
||||
|
||||
participant.type == Participant.ParticipantType.USER_FOLLOWING_LINK
|
||||
) {
|
||||
ncApi.removeParticipantFromConversation(
|
||||
credentials,
|
||||
ApiUtils.getUrlForRemovingParticipantFromConversation(
|
||||
conversationUser.baseUrl,
|
||||
conversation!!.token,
|
||||
true
|
||||
),
|
||||
participant.sessionId
|
||||
)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe {
|
||||
getListOfParticipants()
|
||||
}
|
||||
} else {
|
||||
ncApi.removeParticipantFromConversation(credentials, ApiUtils.getUrlForRemovingParticipantFromConversation(conversationUser.baseUrl, conversation!!.token, false), participant.userId)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe {
|
||||
getListOfParticipants()
|
||||
// get participants again
|
||||
}
|
||||
ncApi.removeParticipantFromConversation(
|
||||
credentials,
|
||||
ApiUtils.getUrlForRemovingParticipantFromConversation(
|
||||
conversationUser.baseUrl,
|
||||
conversation!!.token,
|
||||
false
|
||||
),
|
||||
participant.userId
|
||||
)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe {
|
||||
getListOfParticipants()
|
||||
// get participants again
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -678,7 +773,7 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return true
|
||||
}
|
||||
|
||||
companion object {
|
||||
@ -709,7 +804,7 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
|
||||
}
|
||||
|
||||
return left.model.displayName.toLowerCase(Locale.ROOT).compareTo(
|
||||
right.model.displayName.toLowerCase(Locale.ROOT)
|
||||
right.model.displayName.toLowerCase(Locale.ROOT)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -53,5 +53,4 @@ abstract class ButterKnifeController : Controller {
|
||||
unbinder!!.unbind()
|
||||
unbinder = null
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -29,10 +29,11 @@ interface ListItemWithImage {
|
||||
}
|
||||
|
||||
data class BasicListItemWithImage(
|
||||
@DrawableRes val iconRes: Int,
|
||||
override val title: String) : ListItemWithImage {
|
||||
@DrawableRes val iconRes: Int,
|
||||
override val title: String
|
||||
) : ListItemWithImage {
|
||||
|
||||
override fun populateIcon(imageView: ImageView) {
|
||||
imageView.setImageResource(iconRes)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,6 @@ package com.nextcloud.talk.controllers.bottomsheet.items
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.afollestad.materialdialogs.WhichButton
|
||||
@ -34,14 +33,14 @@ import com.afollestad.materialdialogs.internal.rtl.RtlTextView
|
||||
import com.afollestad.materialdialogs.list.getItemSelector
|
||||
import com.afollestad.materialdialogs.utils.MDUtil.inflate
|
||||
import com.afollestad.materialdialogs.utils.MDUtil.maybeSetTextColor
|
||||
import com.google.android.material.textview.MaterialTextView
|
||||
import com.nextcloud.talk.R
|
||||
|
||||
private const val KEY_ACTIVATED_INDEX = "activated_index"
|
||||
|
||||
internal class ListItemViewHolder(
|
||||
itemView: View,
|
||||
private val adapter: ListIconDialogAdapter<*>) : RecyclerView.ViewHolder(itemView), View.OnClickListener {
|
||||
itemView: View,
|
||||
private val adapter: ListIconDialogAdapter<*>
|
||||
) : RecyclerView.ViewHolder(itemView), View.OnClickListener {
|
||||
init {
|
||||
itemView.setOnClickListener(this)
|
||||
}
|
||||
@ -53,11 +52,12 @@ internal class ListItemViewHolder(
|
||||
}
|
||||
|
||||
internal class ListIconDialogAdapter<IT : ListItemWithImage>(
|
||||
private var dialog: MaterialDialog,
|
||||
private var items: List<IT>,
|
||||
disabledItems: IntArray?,
|
||||
private var waitForPositiveButton: Boolean,
|
||||
private var selection: ListItemListener<IT>) : RecyclerView.Adapter<ListItemViewHolder>(), DialogAdapter<IT, ListItemListener<IT>> {
|
||||
private var dialog: MaterialDialog,
|
||||
private var items: List<IT>,
|
||||
disabledItems: IntArray?,
|
||||
private var waitForPositiveButton: Boolean,
|
||||
private var selection: ListItemListener<IT>
|
||||
) : RecyclerView.Adapter<ListItemViewHolder>(), DialogAdapter<IT, ListItemListener<IT>> {
|
||||
|
||||
private var disabledIndices: IntArray = disabledItems ?: IntArray(0)
|
||||
|
||||
@ -81,12 +81,13 @@ internal class ListIconDialogAdapter<IT : ListItemWithImage>(
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(
|
||||
parent: ViewGroup,
|
||||
viewType: Int): ListItemViewHolder {
|
||||
parent: ViewGroup,
|
||||
viewType: Int
|
||||
): ListItemViewHolder {
|
||||
val listItemView: View = parent.inflate(dialog.windowContext, R.layout.menu_item_sheet)
|
||||
val viewHolder = ListItemViewHolder(
|
||||
itemView = listItemView,
|
||||
adapter = this
|
||||
itemView = listItemView,
|
||||
adapter = this
|
||||
)
|
||||
viewHolder.titleView.maybeSetTextColor(dialog.windowContext, R.attr.md_color_content)
|
||||
return viewHolder
|
||||
@ -95,8 +96,9 @@ internal class ListIconDialogAdapter<IT : ListItemWithImage>(
|
||||
override fun getItemCount() = items.size
|
||||
|
||||
override fun onBindViewHolder(
|
||||
holder: ListItemViewHolder,
|
||||
position: Int) {
|
||||
holder: ListItemViewHolder,
|
||||
position: Int
|
||||
) {
|
||||
holder.itemView.isEnabled = !disabledIndices.contains(position)
|
||||
val currentItem = items[position]
|
||||
|
||||
@ -121,8 +123,9 @@ internal class ListIconDialogAdapter<IT : ListItemWithImage>(
|
||||
}
|
||||
|
||||
override fun replaceItems(
|
||||
items: List<IT>,
|
||||
listener: ListItemListener<IT>) {
|
||||
items: List<IT>,
|
||||
listener: ListItemListener<IT>
|
||||
) {
|
||||
this.items = items
|
||||
if (listener != null) {
|
||||
this.selection = listener
|
||||
|
@ -28,37 +28,40 @@ import com.afollestad.materialdialogs.list.customListAdapter
|
||||
import com.afollestad.materialdialogs.list.getListAdapter
|
||||
|
||||
typealias ListItemListener<IT> =
|
||||
((dialog: MaterialDialog, index: Int, item: IT) -> Unit)?
|
||||
((dialog: MaterialDialog, index: Int, item: IT) -> Unit)?
|
||||
|
||||
@CheckResult fun <IT : ListItemWithImage> MaterialDialog.listItemsWithImage(
|
||||
items: List<IT>,
|
||||
disabledIndices: IntArray? = null,
|
||||
waitForPositiveButton: Boolean = true,
|
||||
selection: ListItemListener<IT> = null): MaterialDialog {
|
||||
@CheckResult
|
||||
fun <IT : ListItemWithImage> MaterialDialog.listItemsWithImage(
|
||||
items: List<IT>,
|
||||
disabledIndices: IntArray? = null,
|
||||
waitForPositiveButton: Boolean = true,
|
||||
selection: ListItemListener<IT> = null
|
||||
): MaterialDialog {
|
||||
|
||||
if (getListAdapter() != null) {
|
||||
return updateListItemsWithImage(
|
||||
items = items,
|
||||
disabledIndices = disabledIndices
|
||||
items = items,
|
||||
disabledIndices = disabledIndices
|
||||
)
|
||||
}
|
||||
|
||||
val layoutManager = LinearLayoutManager(windowContext)
|
||||
return customListAdapter(
|
||||
adapter = ListIconDialogAdapter(
|
||||
dialog = this,
|
||||
items = items,
|
||||
disabledItems = disabledIndices,
|
||||
waitForPositiveButton = waitForPositiveButton,
|
||||
selection = selection
|
||||
),
|
||||
layoutManager = layoutManager
|
||||
adapter = ListIconDialogAdapter(
|
||||
dialog = this,
|
||||
items = items,
|
||||
disabledItems = disabledIndices,
|
||||
waitForPositiveButton = waitForPositiveButton,
|
||||
selection = selection
|
||||
),
|
||||
layoutManager = layoutManager
|
||||
)
|
||||
}
|
||||
|
||||
fun MaterialDialog.updateListItemsWithImage(
|
||||
items: List<ListItemWithImage>,
|
||||
disabledIndices: IntArray? = null): MaterialDialog {
|
||||
items: List<ListItemWithImage>,
|
||||
disabledIndices: IntArray? = null
|
||||
): MaterialDialog {
|
||||
val adapter = getListAdapter()
|
||||
check(adapter != null) {
|
||||
"updateGridItems(...) can't be used before you've created a bottom sheet grid dialog."
|
||||
|
@ -20,6 +20,4 @@
|
||||
|
||||
package com.nextcloud.talk.events
|
||||
|
||||
class CallNotificationClick {
|
||||
|
||||
}
|
||||
class CallNotificationClick
|
||||
|
@ -33,7 +33,11 @@ import android.provider.ContactsContract
|
||||
import android.util.Log
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.os.ConfigurationCompat
|
||||
import androidx.work.*
|
||||
import androidx.work.Data
|
||||
import androidx.work.OneTimeWorkRequest
|
||||
import androidx.work.WorkManager
|
||||
import androidx.work.Worker
|
||||
import androidx.work.WorkerParameters
|
||||
import autodagger.AutoInjector
|
||||
import com.bluelinelabs.conductor.Controller
|
||||
import com.google.gson.Gson
|
||||
@ -54,10 +58,9 @@ import okhttp3.MediaType
|
||||
import okhttp3.RequestBody
|
||||
import javax.inject.Inject
|
||||
|
||||
|
||||
@AutoInjector(NextcloudTalkApplication::class)
|
||||
class ContactAddressBookWorker(val context: Context, workerParameters: WorkerParameters) :
|
||||
Worker(context, workerParameters) {
|
||||
Worker(context, workerParameters) {
|
||||
|
||||
@Inject
|
||||
lateinit var ncApi: NcApi
|
||||
@ -85,7 +88,7 @@ class ContactAddressBookWorker(val context: Context, workerParameters: WorkerPar
|
||||
}
|
||||
|
||||
val deleteAll = inputData.getBoolean(DELETE_ALL, false)
|
||||
if(deleteAll){
|
||||
if (deleteAll) {
|
||||
deleteAllLinkedAccounts()
|
||||
return Result.success()
|
||||
}
|
||||
@ -99,7 +102,7 @@ class ContactAddressBookWorker(val context: Context, workerParameters: WorkerPar
|
||||
}
|
||||
}
|
||||
|
||||
if(AccountManager.get(context).getAccountsByType(accountType).isEmpty()){
|
||||
if (AccountManager.get(context).getAccountsByType(accountType).isEmpty()) {
|
||||
AccountManager.get(context).addAccountExplicitly(Account(accountName, accountType), "", null)
|
||||
} else {
|
||||
Log.d(TAG, "Account already exists")
|
||||
@ -107,7 +110,7 @@ class ContactAddressBookWorker(val context: Context, workerParameters: WorkerPar
|
||||
|
||||
val deviceContactsWithNumbers = collectContactsWithPhoneNumbersFromDevice()
|
||||
|
||||
if(deviceContactsWithNumbers.isNotEmpty()){
|
||||
if (deviceContactsWithNumbers.isNotEmpty()) {
|
||||
val currentLocale = ConfigurationCompat.getLocales(context.resources.configuration)[0].country
|
||||
|
||||
val map = mutableMapOf<String, Any>()
|
||||
@ -117,28 +120,29 @@ class ContactAddressBookWorker(val context: Context, workerParameters: WorkerPar
|
||||
val json = Gson().toJson(map)
|
||||
|
||||
ncApi.searchContactsByPhoneNumber(
|
||||
ApiUtils.getCredentials(currentUser.username, currentUser.token),
|
||||
ApiUtils.getUrlForSearchByNumber(currentUser.baseUrl),
|
||||
RequestBody.create(MediaType.parse("application/json"), json))
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : Observer<ContactsByNumberOverall> {
|
||||
override fun onComplete() {
|
||||
}
|
||||
ApiUtils.getCredentials(currentUser.username, currentUser.token),
|
||||
ApiUtils.getUrlForSearchByNumber(currentUser.baseUrl),
|
||||
RequestBody.create(MediaType.parse("application/json"), json)
|
||||
)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : Observer<ContactsByNumberOverall> {
|
||||
override fun onComplete() {
|
||||
}
|
||||
|
||||
override fun onSubscribe(d: Disposable) {
|
||||
}
|
||||
override fun onSubscribe(d: Disposable) {
|
||||
}
|
||||
|
||||
override fun onNext(foundContacts: ContactsByNumberOverall) {
|
||||
val contactsWithAssociatedPhoneNumbers = foundContacts.ocs.map
|
||||
deleteLinkedAccounts(contactsWithAssociatedPhoneNumbers)
|
||||
createLinkedAccounts(contactsWithAssociatedPhoneNumbers)
|
||||
}
|
||||
override fun onNext(foundContacts: ContactsByNumberOverall) {
|
||||
val contactsWithAssociatedPhoneNumbers = foundContacts.ocs.map
|
||||
deleteLinkedAccounts(contactsWithAssociatedPhoneNumbers)
|
||||
createLinkedAccounts(contactsWithAssociatedPhoneNumbers)
|
||||
}
|
||||
|
||||
override fun onError(e: Throwable) {
|
||||
Log.e(javaClass.simpleName, "Failed to searchContactsByPhoneNumber", e)
|
||||
}
|
||||
})
|
||||
override fun onError(e: Throwable) {
|
||||
Log.e(javaClass.simpleName, "Failed to searchContactsByPhoneNumber", e)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// store timestamp
|
||||
@ -151,11 +155,11 @@ class ContactAddressBookWorker(val context: Context, workerParameters: WorkerPar
|
||||
val deviceContactsWithNumbers: MutableMap<String, List<String>> = mutableMapOf()
|
||||
|
||||
val contactCursor = context.contentResolver.query(
|
||||
ContactsContract.Contacts.CONTENT_URI,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
ContactsContract.Contacts.CONTENT_URI,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
)
|
||||
|
||||
if (contactCursor != null) {
|
||||
@ -163,7 +167,8 @@ class ContactAddressBookWorker(val context: Context, workerParameters: WorkerPar
|
||||
contactCursor.moveToFirst()
|
||||
for (i in 0 until contactCursor.count) {
|
||||
val id = contactCursor.getString(contactCursor.getColumnIndex(ContactsContract.Contacts._ID))
|
||||
val lookup = contactCursor.getString(contactCursor.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY))
|
||||
val lookup =
|
||||
contactCursor.getString(contactCursor.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY))
|
||||
deviceContactsWithNumbers[lookup] = getPhoneNumbersFromDeviceContact(id)
|
||||
contactCursor.moveToNext()
|
||||
}
|
||||
@ -178,39 +183,50 @@ class ContactAddressBookWorker(val context: Context, workerParameters: WorkerPar
|
||||
Log.d(TAG, "deleteLinkedAccount")
|
||||
fun deleteLinkedAccount(id: String) {
|
||||
val rawContactUri = ContactsContract.RawContacts.CONTENT_URI
|
||||
.buildUpon()
|
||||
.appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "true")
|
||||
.appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_NAME, accountName)
|
||||
.appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_TYPE, accountType)
|
||||
.build()
|
||||
val count = context.contentResolver.delete(rawContactUri, ContactsContract.RawContacts.CONTACT_ID + " " +
|
||||
"LIKE \"" + id + "\"", null)
|
||||
Log.d(TAG, "deleted $count linked accounts for id $id")
|
||||
}
|
||||
|
||||
val rawContactUri = ContactsContract.Data.CONTENT_URI
|
||||
.buildUpon()
|
||||
.appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "true")
|
||||
.appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_NAME, accountName)
|
||||
.appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_TYPE, accountType)
|
||||
.appendQueryParameter(ContactsContract.Data.MIMETYPE, "vnd.android.cursor.item/vnd.com.nextcloud.talk2.chat")
|
||||
.build()
|
||||
val count = context.contentResolver.delete(
|
||||
rawContactUri,
|
||||
ContactsContract.RawContacts.CONTACT_ID + " " + "LIKE \"" + id + "\"",
|
||||
null
|
||||
)
|
||||
Log.d(TAG, "deleted $count linked accounts for id $id")
|
||||
}
|
||||
|
||||
val rawContactUri = ContactsContract.Data.CONTENT_URI
|
||||
.buildUpon()
|
||||
.appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "true")
|
||||
.appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_NAME, accountName)
|
||||
.appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_TYPE, accountType)
|
||||
.appendQueryParameter(
|
||||
ContactsContract.Data.MIMETYPE,
|
||||
"vnd.android.cursor.item/vnd.com.nextcloud.talk2.chat"
|
||||
)
|
||||
.build()
|
||||
|
||||
val rawContactsCursor = context.contentResolver.query(
|
||||
rawContactUri,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
rawContactUri,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
)
|
||||
|
||||
if (rawContactsCursor != null) {
|
||||
if (rawContactsCursor.count > 0) {
|
||||
while (rawContactsCursor.moveToNext()) {
|
||||
val lookupKey = rawContactsCursor.getString(rawContactsCursor.getColumnIndex(ContactsContract.Data.LOOKUP_KEY))
|
||||
val contactId = rawContactsCursor.getString(rawContactsCursor.getColumnIndex(ContactsContract.Data.CONTACT_ID))
|
||||
val lookupKey =
|
||||
rawContactsCursor.getString(rawContactsCursor.getColumnIndex(ContactsContract.Data.LOOKUP_KEY))
|
||||
val contactId =
|
||||
rawContactsCursor.getString(rawContactsCursor.getColumnIndex(ContactsContract.Data.CONTACT_ID))
|
||||
|
||||
if (contactsWithAssociatedPhoneNumbers == null || !contactsWithAssociatedPhoneNumbers.containsKey(lookupKey)) {
|
||||
if (contactsWithAssociatedPhoneNumbers == null || !contactsWithAssociatedPhoneNumbers.containsKey(
|
||||
lookupKey
|
||||
)
|
||||
) {
|
||||
deleteLinkedAccount(contactId)
|
||||
}
|
||||
}
|
||||
@ -222,25 +238,29 @@ class ContactAddressBookWorker(val context: Context, workerParameters: WorkerPar
|
||||
}
|
||||
|
||||
private fun createLinkedAccounts(contactsWithAssociatedPhoneNumbers: Map<String, String>?) {
|
||||
fun hasLinkedAccount(id: String) : Boolean {
|
||||
fun hasLinkedAccount(id: String): Boolean {
|
||||
var hasLinkedAccount = false
|
||||
val where = ContactsContract.Data.MIMETYPE + " = ? AND " + ContactsContract.CommonDataKinds.StructuredName.CONTACT_ID + " = ?"
|
||||
val where =
|
||||
ContactsContract.Data.MIMETYPE + " = ? AND " + ContactsContract.CommonDataKinds.StructuredName.CONTACT_ID + " = ?"
|
||||
val params = arrayOf(ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE, id)
|
||||
|
||||
val rawContactUri = ContactsContract.Data.CONTENT_URI
|
||||
.buildUpon()
|
||||
.appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "true")
|
||||
.appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_NAME, accountName)
|
||||
.appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_TYPE, accountType)
|
||||
.appendQueryParameter(ContactsContract.Data.MIMETYPE, "vnd.android.cursor.item/vnd.com.nextcloud.talk2.chat")
|
||||
.build()
|
||||
.buildUpon()
|
||||
.appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "true")
|
||||
.appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_NAME, accountName)
|
||||
.appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_TYPE, accountType)
|
||||
.appendQueryParameter(
|
||||
ContactsContract.Data.MIMETYPE,
|
||||
"vnd.android.cursor.item/vnd.com.nextcloud.talk2.chat"
|
||||
)
|
||||
.build()
|
||||
|
||||
val rawContactsCursor = context.contentResolver.query(
|
||||
rawContactUri,
|
||||
null,
|
||||
where,
|
||||
params,
|
||||
null
|
||||
rawContactUri,
|
||||
null,
|
||||
where,
|
||||
params,
|
||||
null
|
||||
)
|
||||
|
||||
if (rawContactsCursor != null) {
|
||||
@ -259,18 +279,19 @@ class ContactAddressBookWorker(val context: Context, workerParameters: WorkerPar
|
||||
val lookupUri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_LOOKUP_URI, lookupKey)
|
||||
val lookupContactUri = ContactsContract.Contacts.lookupContact(context.contentResolver, lookupUri)
|
||||
val contactCursor = context.contentResolver.query(
|
||||
lookupContactUri,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null)
|
||||
lookupContactUri,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
)
|
||||
|
||||
if (contactCursor != null) {
|
||||
if (contactCursor.count > 0) {
|
||||
contactCursor.moveToFirst()
|
||||
|
||||
val id = contactCursor.getString(contactCursor.getColumnIndex(ContactsContract.Contacts._ID))
|
||||
if(hasLinkedAccount(id)){
|
||||
if (hasLinkedAccount(id)) {
|
||||
return
|
||||
}
|
||||
|
||||
@ -285,34 +306,60 @@ class ContactAddressBookWorker(val context: Context, workerParameters: WorkerPar
|
||||
val rawContactsUri = ContactsContract.RawContacts.CONTENT_URI.buildUpon().build()
|
||||
val dataUri = ContactsContract.Data.CONTENT_URI.buildUpon().build()
|
||||
|
||||
ops.add(ContentProviderOperation
|
||||
ops.add(
|
||||
ContentProviderOperation
|
||||
.newInsert(rawContactsUri)
|
||||
.withValue(ContactsContract.RawContacts.ACCOUNT_NAME, accountName)
|
||||
.withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, accountType)
|
||||
.withValue(ContactsContract.RawContacts.AGGREGATION_MODE,
|
||||
ContactsContract.RawContacts.AGGREGATION_MODE_DEFAULT)
|
||||
.withValue(
|
||||
ContactsContract.RawContacts.AGGREGATION_MODE,
|
||||
ContactsContract.RawContacts.AGGREGATION_MODE_DEFAULT
|
||||
)
|
||||
.withValue(ContactsContract.RawContacts.SYNC2, cloudId)
|
||||
.build())
|
||||
ops.add(ContentProviderOperation
|
||||
.build()
|
||||
)
|
||||
ops.add(
|
||||
ContentProviderOperation
|
||||
.newInsert(dataUri)
|
||||
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
|
||||
.withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
|
||||
.withValue(
|
||||
ContactsContract.Data.MIMETYPE,
|
||||
ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE
|
||||
)
|
||||
.withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, numbers[0])
|
||||
.build())
|
||||
ops.add(ContentProviderOperation
|
||||
.build()
|
||||
)
|
||||
ops.add(
|
||||
ContentProviderOperation
|
||||
.newInsert(dataUri)
|
||||
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
|
||||
.withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
|
||||
.withValue(
|
||||
ContactsContract.Data.MIMETYPE,
|
||||
ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE
|
||||
)
|
||||
.withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, displayName)
|
||||
.build())
|
||||
ops.add(ContentProviderOperation
|
||||
.build()
|
||||
)
|
||||
ops.add(
|
||||
ContentProviderOperation
|
||||
.newInsert(dataUri)
|
||||
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
|
||||
.withValue(ContactsContract.Data.MIMETYPE, "vnd.android.cursor.item/vnd.com.nextcloud.talk2.chat")
|
||||
.withValue(
|
||||
ContactsContract.Data.MIMETYPE,
|
||||
"vnd.android.cursor.item/vnd.com.nextcloud.talk2.chat"
|
||||
)
|
||||
.withValue(ContactsContract.Data.DATA1, cloudId)
|
||||
.withValue(ContactsContract.Data.DATA2, String.format(context.resources.getString(R
|
||||
.string.nc_phone_book_integration_chat_via), accountName))
|
||||
.build())
|
||||
.withValue(
|
||||
ContactsContract.Data.DATA2,
|
||||
String.format(
|
||||
context.resources.getString(
|
||||
R.string.nc_phone_book_integration_chat_via
|
||||
),
|
||||
accountName
|
||||
)
|
||||
)
|
||||
.build()
|
||||
)
|
||||
|
||||
try {
|
||||
context.contentResolver.applyBatch(ContactsContract.AUTHORITY, ops)
|
||||
@ -322,8 +369,11 @@ class ContactAddressBookWorker(val context: Context, workerParameters: WorkerPar
|
||||
Log.e(javaClass.simpleName, "", e)
|
||||
}
|
||||
|
||||
Log.d(TAG, "added new entry for contact $displayName (cloudId: $cloudId | lookupKey: $lookupKey" +
|
||||
" | id: $id)")
|
||||
Log.d(
|
||||
TAG,
|
||||
"added new entry for contact $displayName (cloudId: $cloudId | lookupKey: $lookupKey" +
|
||||
" | id: $id)"
|
||||
)
|
||||
}
|
||||
contactCursor.close()
|
||||
}
|
||||
@ -341,18 +391,21 @@ class ContactAddressBookWorker(val context: Context, workerParameters: WorkerPar
|
||||
}
|
||||
|
||||
private fun getDisplayNameFromDeviceContact(id: String?): String? {
|
||||
var displayName:String? = null
|
||||
val whereName = ContactsContract.Data.MIMETYPE + " = ? AND " + ContactsContract.CommonDataKinds.StructuredName.CONTACT_ID + " = ?"
|
||||
var displayName: String? = null
|
||||
val whereName =
|
||||
ContactsContract.Data.MIMETYPE + " = ? AND " + ContactsContract.CommonDataKinds.StructuredName.CONTACT_ID + " = ?"
|
||||
val whereNameParams = arrayOf(ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE, id)
|
||||
val nameCursor = context.contentResolver.query(
|
||||
ContactsContract.Data.CONTENT_URI,
|
||||
null,
|
||||
whereName,
|
||||
whereNameParams,
|
||||
ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME)
|
||||
ContactsContract.Data.CONTENT_URI,
|
||||
null,
|
||||
whereName,
|
||||
whereNameParams,
|
||||
ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME
|
||||
)
|
||||
if (nameCursor != null) {
|
||||
while (nameCursor.moveToNext()) {
|
||||
displayName = nameCursor.getString(nameCursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME))
|
||||
displayName =
|
||||
nameCursor.getString(nameCursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME))
|
||||
}
|
||||
nameCursor.close()
|
||||
}
|
||||
@ -362,11 +415,12 @@ class ContactAddressBookWorker(val context: Context, workerParameters: WorkerPar
|
||||
private fun getPhoneNumbersFromDeviceContact(id: String?): MutableList<String> {
|
||||
val numbers = mutableListOf<String>()
|
||||
val phonesNumbersCursor = context.contentResolver.query(
|
||||
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
|
||||
null,
|
||||
ContactsContract.Data.CONTACT_ID + " = " + id,
|
||||
null,
|
||||
null)
|
||||
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
|
||||
null,
|
||||
ContactsContract.Data.CONTACT_ID + " = " + id,
|
||||
null,
|
||||
null
|
||||
)
|
||||
|
||||
if (phonesNumbersCursor != null) {
|
||||
while (phonesNumbersCursor.moveToNext()) {
|
||||
@ -374,7 +428,7 @@ class ContactAddressBookWorker(val context: Context, workerParameters: WorkerPar
|
||||
}
|
||||
phonesNumbersCursor.close()
|
||||
}
|
||||
if(numbers.size > 0){
|
||||
if (numbers.size > 0) {
|
||||
Log.d(TAG, "Found ${numbers.size} phone numbers for contact with id $id")
|
||||
}
|
||||
return numbers
|
||||
@ -382,11 +436,11 @@ class ContactAddressBookWorker(val context: Context, workerParameters: WorkerPar
|
||||
|
||||
fun deleteAllLinkedAccounts() {
|
||||
val rawContactUri = ContactsContract.RawContacts.CONTENT_URI
|
||||
.buildUpon()
|
||||
.appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "true")
|
||||
.appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_NAME, accountName)
|
||||
.appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_TYPE, accountType)
|
||||
.build()
|
||||
.buildUpon()
|
||||
.appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "true")
|
||||
.appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_NAME, accountName)
|
||||
.appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_TYPE, accountType)
|
||||
.build()
|
||||
context.contentResolver.delete(rawContactUri, null, null)
|
||||
Log.d(TAG, "deleted all linked accounts")
|
||||
}
|
||||
@ -398,42 +452,63 @@ class ContactAddressBookWorker(val context: Context, workerParameters: WorkerPar
|
||||
const val DELETE_ALL = "DELETE_ALL"
|
||||
|
||||
fun run(context: Context) {
|
||||
if (ContextCompat.checkSelfPermission(context,
|
||||
Manifest.permission.WRITE_CONTACTS) == PackageManager.PERMISSION_GRANTED &&
|
||||
ContextCompat.checkSelfPermission(context,
|
||||
Manifest.permission.READ_CONTACTS) == PackageManager.PERMISSION_GRANTED) {
|
||||
if (ContextCompat.checkSelfPermission(
|
||||
context,
|
||||
Manifest.permission.WRITE_CONTACTS
|
||||
) == PackageManager.PERMISSION_GRANTED &&
|
||||
ContextCompat.checkSelfPermission(
|
||||
context,
|
||||
Manifest.permission.READ_CONTACTS
|
||||
) == PackageManager.PERMISSION_GRANTED
|
||||
) {
|
||||
WorkManager
|
||||
.getInstance()
|
||||
.enqueue(OneTimeWorkRequest.Builder(ContactAddressBookWorker::class.java)
|
||||
.setInputData(Data.Builder().putBoolean(KEY_FORCE, false).build())
|
||||
.build())
|
||||
.getInstance()
|
||||
.enqueue(
|
||||
OneTimeWorkRequest.Builder(ContactAddressBookWorker::class.java)
|
||||
.setInputData(Data.Builder().putBoolean(KEY_FORCE, false).build())
|
||||
.build()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun checkPermission(controller: Controller, context: Context): Boolean {
|
||||
if (ContextCompat.checkSelfPermission(context,
|
||||
Manifest.permission.WRITE_CONTACTS) != PackageManager.PERMISSION_GRANTED ||
|
||||
ContextCompat.checkSelfPermission(context,
|
||||
Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
|
||||
controller.requestPermissions(arrayOf(Manifest.permission.WRITE_CONTACTS,
|
||||
Manifest.permission.READ_CONTACTS), REQUEST_PERMISSION)
|
||||
if (ContextCompat.checkSelfPermission(
|
||||
context,
|
||||
Manifest.permission.WRITE_CONTACTS
|
||||
) != PackageManager.PERMISSION_GRANTED ||
|
||||
ContextCompat.checkSelfPermission(
|
||||
context,
|
||||
Manifest.permission.READ_CONTACTS
|
||||
) != PackageManager.PERMISSION_GRANTED
|
||||
) {
|
||||
controller.requestPermissions(
|
||||
arrayOf(
|
||||
Manifest.permission.WRITE_CONTACTS,
|
||||
Manifest.permission.READ_CONTACTS
|
||||
),
|
||||
REQUEST_PERMISSION
|
||||
)
|
||||
return false
|
||||
} else {
|
||||
WorkManager
|
||||
.getInstance()
|
||||
.enqueue(OneTimeWorkRequest.Builder(ContactAddressBookWorker::class.java)
|
||||
.setInputData(Data.Builder().putBoolean(KEY_FORCE, true).build())
|
||||
.build())
|
||||
.getInstance()
|
||||
.enqueue(
|
||||
OneTimeWorkRequest.Builder(ContactAddressBookWorker::class.java)
|
||||
.setInputData(Data.Builder().putBoolean(KEY_FORCE, true).build())
|
||||
.build()
|
||||
)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
fun deleteAll() {
|
||||
WorkManager
|
||||
.getInstance()
|
||||
.enqueue(OneTimeWorkRequest.Builder(ContactAddressBookWorker::class.java)
|
||||
.setInputData(Data.Builder().putBoolean(DELETE_ALL, true).build())
|
||||
.build())
|
||||
WorkManager
|
||||
.getInstance()
|
||||
.enqueue(
|
||||
OneTimeWorkRequest.Builder(ContactAddressBookWorker::class.java)
|
||||
.setInputData(Data.Builder().putBoolean(DELETE_ALL, true).build())
|
||||
.build()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -33,13 +33,16 @@ import com.nextcloud.talk.utils.ApiUtils
|
||||
import com.nextcloud.talk.utils.database.user.UserUtils
|
||||
import com.nextcloud.talk.utils.preferences.AppPreferences
|
||||
import okhttp3.ResponseBody
|
||||
import java.io.*
|
||||
import java.io.BufferedInputStream
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import java.io.InputStream
|
||||
import java.io.OutputStream
|
||||
import javax.inject.Inject
|
||||
|
||||
|
||||
@AutoInjector(NextcloudTalkApplication::class)
|
||||
class DownloadFileToCacheWorker(val context: Context, workerParameters: WorkerParameters) :
|
||||
Worker(context, workerParameters) {
|
||||
Worker(context, workerParameters) {
|
||||
|
||||
private var totalFileSize: Int = -1
|
||||
|
||||
@ -86,8 +89,9 @@ class DownloadFileToCacheWorker(val context: Context, workerParameters: WorkerPa
|
||||
|
||||
private fun downloadFile(currentUser: UserEntity, url: String, fileName: String): Result {
|
||||
val downloadCall = ncApi.downloadFile(
|
||||
ApiUtils.getCredentials(currentUser.username, currentUser.token),
|
||||
url)
|
||||
ApiUtils.getCredentials(currentUser.username, currentUser.token),
|
||||
url
|
||||
)
|
||||
|
||||
return executeDownload(downloadCall.execute().body(), fileName)
|
||||
}
|
||||
@ -152,6 +156,5 @@ class DownloadFileToCacheWorker(val context: Context, workerParameters: WorkerPa
|
||||
const val KEY_FILE_SIZE = "KEY_FILE_SIZE"
|
||||
const val PROGRESS = "PROGRESS"
|
||||
const val SUCCESS = "SUCCESS"
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,11 @@ package com.nextcloud.talk.jobs
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import android.util.Log
|
||||
import androidx.work.*
|
||||
import androidx.work.Data
|
||||
import androidx.work.OneTimeWorkRequest
|
||||
import androidx.work.WorkManager
|
||||
import androidx.work.Worker
|
||||
import androidx.work.WorkerParameters
|
||||
import autodagger.AutoInjector
|
||||
import com.nextcloud.talk.api.NcApi
|
||||
import com.nextcloud.talk.application.NextcloudTalkApplication
|
||||
@ -46,13 +50,12 @@ import retrofit2.Response
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import java.io.InputStream
|
||||
import java.util.*
|
||||
import java.util.ArrayList
|
||||
import javax.inject.Inject
|
||||
|
||||
|
||||
@AutoInjector(NextcloudTalkApplication::class)
|
||||
class UploadAndShareFilesWorker(val context: Context, workerParameters: WorkerParameters) :
|
||||
Worker(context, workerParameters) {
|
||||
Worker(context, workerParameters) {
|
||||
|
||||
@Inject
|
||||
lateinit var ncApi: NcApi
|
||||
@ -107,31 +110,37 @@ class UploadAndShareFilesWorker(val context: Context, workerParameters: WorkerPa
|
||||
return requestBody
|
||||
}
|
||||
|
||||
private fun uploadFile(currentUser: UserEntity, ncTargetpath: String?, filename: String, roomToken: String?,
|
||||
requestBody: RequestBody?, sourcefileUri: Uri) {
|
||||
private fun uploadFile(
|
||||
currentUser: UserEntity,
|
||||
ncTargetpath: String?,
|
||||
filename: String,
|
||||
roomToken: String?,
|
||||
requestBody: RequestBody?,
|
||||
sourcefileUri: Uri
|
||||
) {
|
||||
ncApi.uploadFile(
|
||||
ApiUtils.getCredentials(currentUser.username, currentUser.token),
|
||||
ApiUtils.getUrlForFileUpload(currentUser.baseUrl, currentUser.userId, ncTargetpath, filename),
|
||||
requestBody
|
||||
ApiUtils.getCredentials(currentUser.username, currentUser.token),
|
||||
ApiUtils.getUrlForFileUpload(currentUser.baseUrl, currentUser.userId, ncTargetpath, filename),
|
||||
requestBody
|
||||
)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : Observer<Response<GenericOverall>> {
|
||||
override fun onSubscribe(d: Disposable) {
|
||||
}
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : Observer<Response<GenericOverall>> {
|
||||
override fun onSubscribe(d: Disposable) {
|
||||
}
|
||||
|
||||
override fun onNext(t: Response<GenericOverall>) {
|
||||
}
|
||||
override fun onNext(t: Response<GenericOverall>) {
|
||||
}
|
||||
|
||||
override fun onError(e: Throwable) {
|
||||
Log.e(TAG, "failed to upload file $filename")
|
||||
}
|
||||
override fun onError(e: Throwable) {
|
||||
Log.e(TAG, "failed to upload file $filename")
|
||||
}
|
||||
|
||||
override fun onComplete() {
|
||||
shareFile(roomToken, currentUser, ncTargetpath, filename)
|
||||
copyFileToCache(sourcefileUri, filename)
|
||||
}
|
||||
})
|
||||
override fun onComplete() {
|
||||
shareFile(roomToken, currentUser, ncTargetpath, filename)
|
||||
copyFileToCache(sourcefileUri, filename)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun copyFileToCache(sourceFileUri: Uri, filename: String) {
|
||||
@ -151,13 +160,13 @@ class UploadAndShareFilesWorker(val context: Context, workerParameters: WorkerPa
|
||||
paths.add("$ncTargetpath/$filename")
|
||||
|
||||
val data = Data.Builder()
|
||||
.putLong(KEY_INTERNAL_USER_ID, currentUser.id)
|
||||
.putString(KEY_ROOM_TOKEN, roomToken)
|
||||
.putStringArray(KEY_FILE_PATHS, paths.toTypedArray())
|
||||
.build()
|
||||
.putLong(KEY_INTERNAL_USER_ID, currentUser.id)
|
||||
.putString(KEY_ROOM_TOKEN, roomToken)
|
||||
.putStringArray(KEY_FILE_PATHS, paths.toTypedArray())
|
||||
.build()
|
||||
val shareWorker = OneTimeWorkRequest.Builder(ShareOperationWorker::class.java)
|
||||
.setInputData(data)
|
||||
.build()
|
||||
.setInputData(data)
|
||||
.build()
|
||||
WorkManager.getInstance().enqueue(shareWorker)
|
||||
}
|
||||
|
||||
@ -167,4 +176,4 @@ class UploadAndShareFilesWorker(val context: Context, workerParameters: WorkerPa
|
||||
const val NC_TARGETPATH = "NC_TARGETPATH"
|
||||
const val ROOM_TOKEN = "ROOM_TOKEN"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ package com.nextcloud.talk.models.json.chat
|
||||
class ChatUtils {
|
||||
companion object {
|
||||
fun getParsedMessage(message: String?, messageParameters: HashMap<String?, HashMap<String?, String?>>?):
|
||||
String? {
|
||||
String? {
|
||||
var resultMessage = message
|
||||
if (messageParameters != null && messageParameters.size > 0) {
|
||||
for (key in messageParameters.keys) {
|
||||
@ -46,4 +46,3 @@ class ChatUtils {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -22,11 +22,28 @@ package com.nextcloud.talk.models.json.converters
|
||||
|
||||
import com.bluelinelabs.logansquare.typeconverters.StringBasedTypeConverter
|
||||
import com.nextcloud.talk.models.json.chat.ChatMessage
|
||||
|
||||
import com.nextcloud.talk.models.json.chat.ChatMessage.SystemMessageType.*
|
||||
import com.nextcloud.talk.models.json.chat.ChatMessage.SystemMessageType.CALL_ENDED
|
||||
import com.nextcloud.talk.models.json.chat.ChatMessage.SystemMessageType.CALL_JOINED
|
||||
import com.nextcloud.talk.models.json.chat.ChatMessage.SystemMessageType.CALL_LEFT
|
||||
import com.nextcloud.talk.models.json.chat.ChatMessage.SystemMessageType.CALL_STARTED
|
||||
import com.nextcloud.talk.models.json.chat.ChatMessage.SystemMessageType.CONVERSATION_CREATED
|
||||
import com.nextcloud.talk.models.json.chat.ChatMessage.SystemMessageType.CONVERSATION_RENAMED
|
||||
import com.nextcloud.talk.models.json.chat.ChatMessage.SystemMessageType.DUMMY
|
||||
import com.nextcloud.talk.models.json.chat.ChatMessage.SystemMessageType.FILE_SHARED
|
||||
import com.nextcloud.talk.models.json.chat.ChatMessage.SystemMessageType.GUESTS_ALLOWED
|
||||
import com.nextcloud.talk.models.json.chat.ChatMessage.SystemMessageType.GUESTS_DISALLOWED
|
||||
import com.nextcloud.talk.models.json.chat.ChatMessage.SystemMessageType.LOBBY_NONE
|
||||
import com.nextcloud.talk.models.json.chat.ChatMessage.SystemMessageType.LOBBY_NON_MODERATORS
|
||||
import com.nextcloud.talk.models.json.chat.ChatMessage.SystemMessageType.LOBBY_OPEN_TO_EVERYONE
|
||||
import com.nextcloud.talk.models.json.chat.ChatMessage.SystemMessageType.MODERATOR_DEMOTED
|
||||
import com.nextcloud.talk.models.json.chat.ChatMessage.SystemMessageType.MODERATOR_PROMOTED
|
||||
import com.nextcloud.talk.models.json.chat.ChatMessage.SystemMessageType.PARENT_MESSAGE_DELETED
|
||||
import com.nextcloud.talk.models.json.chat.ChatMessage.SystemMessageType.PASSWORD_REMOVED
|
||||
import com.nextcloud.talk.models.json.chat.ChatMessage.SystemMessageType.PASSWORD_SET
|
||||
import com.nextcloud.talk.models.json.chat.ChatMessage.SystemMessageType.USER_ADDED
|
||||
import com.nextcloud.talk.models.json.chat.ChatMessage.SystemMessageType.USER_REMOVED
|
||||
|
||||
/*
|
||||
|
||||
conversation_created - {actor} created the conversation
|
||||
conversation_renamed - {actor} renamed the conversation from "foo" to "bar"
|
||||
call_joined - {actor} joined the call
|
||||
@ -40,7 +57,6 @@ import com.nextcloud.talk.models.json.chat.ChatMessage.SystemMessageType.*
|
||||
user_removed - {actor} removed {user} from the conversation
|
||||
moderator_promoted - {actor} promoted {user} to moderator
|
||||
moderator_demoted - {actor} demoted {user} from moderator
|
||||
|
||||
*/
|
||||
class EnumSystemMessageTypeConverter : StringBasedTypeConverter<ChatMessage.SystemMessageType>() {
|
||||
override fun getFromString(string: String): ChatMessage.SystemMessageType {
|
||||
|
@ -20,12 +20,10 @@
|
||||
|
||||
package com.nextcloud.talk.receivers
|
||||
|
||||
import android.app.NotificationChannelGroup
|
||||
import android.app.NotificationManager
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageInfo
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Build
|
||||
import android.util.Log
|
||||
@ -34,7 +32,6 @@ import com.nextcloud.talk.application.NextcloudTalkApplication
|
||||
import com.nextcloud.talk.utils.NotificationUtils
|
||||
import com.nextcloud.talk.utils.database.user.UserUtils
|
||||
import com.nextcloud.talk.utils.preferences.AppPreferences
|
||||
|
||||
import javax.inject.Inject
|
||||
|
||||
@AutoInjector(NextcloudTalkApplication::class)
|
||||
@ -50,16 +47,20 @@ class PackageReplacedReceiver : BroadcastReceiver() {
|
||||
NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this)
|
||||
|
||||
if (intent != null && intent.action != null &&
|
||||
intent.action == "android.intent.action.MY_PACKAGE_REPLACED") {
|
||||
intent.action == "android.intent.action.MY_PACKAGE_REPLACED"
|
||||
) {
|
||||
try {
|
||||
val packageInfo = context.packageManager.getPackageInfo(context.packageName, 0)
|
||||
if (packageInfo.versionCode > 43 && 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
|
||||
|
||||
if (!appPreferences.isNotificationChannelUpgradedToV2) {
|
||||
for (notificationChannelGroup in notificationManager
|
||||
.notificationChannelGroups) {
|
||||
for (
|
||||
notificationChannelGroup in notificationManager.notificationChannelGroups
|
||||
) {
|
||||
notificationManager.deleteNotificationChannelGroup(notificationChannelGroup.id)
|
||||
}
|
||||
|
||||
@ -80,7 +81,6 @@ class PackageReplacedReceiver : BroadcastReceiver() {
|
||||
} catch (e: PackageManager.NameNotFoundException) {
|
||||
Log.e(TAG, "Failed to fetch package info")
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -32,7 +32,6 @@ import com.nextcloud.talk.R
|
||||
import com.nextcloud.talk.components.filebrowser.controllers.BrowserController
|
||||
import com.nextcloud.talk.controllers.ChatController
|
||||
|
||||
|
||||
class AttachmentDialog(val activity: Activity, var chatController: ChatController) : BottomSheetDialog(activity) {
|
||||
|
||||
@BindView(R.id.txt_attach_file_from_local)
|
||||
@ -54,7 +53,7 @@ class AttachmentDialog(val activity: Activity, var chatController: ChatControlle
|
||||
|
||||
var serverName = chatController.conversationUser?.serverName
|
||||
attachFromCloud?.text = chatController.resources?.let {
|
||||
if(serverName.isNullOrEmpty()){
|
||||
if (serverName.isNullOrEmpty()) {
|
||||
serverName = it.getString(R.string.nc_server_product_name)
|
||||
}
|
||||
String.format(it.getString(R.string.nc_upload_from_cloud), serverName)
|
||||
|
@ -30,12 +30,13 @@ import com.nextcloud.talk.R
|
||||
import com.nextcloud.talk.controllers.ProfileController
|
||||
import com.nextcloud.talk.models.json.userprofile.Scope
|
||||
|
||||
|
||||
class ScopeDialog(con: Context,
|
||||
private val userInfoAdapter: ProfileController.UserInfoAdapter,
|
||||
private val field: ProfileController.Field,
|
||||
private val position: Int) :
|
||||
BottomSheetDialog(con) {
|
||||
class ScopeDialog(
|
||||
con: Context,
|
||||
private val userInfoAdapter: ProfileController.UserInfoAdapter,
|
||||
private val field: ProfileController.Field,
|
||||
private val position: Int
|
||||
) :
|
||||
BottomSheetDialog(con) {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
val view = layoutInflater.inflate(R.layout.dialog_scope, null)
|
||||
|
@ -32,7 +32,8 @@ import com.nextcloud.talk.R
|
||||
import com.nextcloud.talk.application.NextcloudTalkApplication
|
||||
import com.nextcloud.talk.models.ImportAccount
|
||||
import com.nextcloud.talk.models.database.UserEntity
|
||||
import java.util.*
|
||||
import java.util.ArrayList
|
||||
import java.util.Arrays
|
||||
|
||||
object AccountUtils {
|
||||
|
||||
@ -60,14 +61,15 @@ object AccountUtils {
|
||||
break
|
||||
}
|
||||
} else {
|
||||
if (internalUserEntity.username == importAccount.username && (internalUserEntity
|
||||
.baseUrl == "http://" + importAccount.baseUrl ||
|
||||
internalUserEntity.baseUrl == "https://" + importAccount
|
||||
.baseUrl)) {
|
||||
if (internalUserEntity.username == importAccount.username &&
|
||||
(
|
||||
internalUserEntity.baseUrl == "http://" + importAccount.baseUrl ||
|
||||
internalUserEntity.baseUrl == "https://" + importAccount.baseUrl
|
||||
)
|
||||
) {
|
||||
accountFound = true
|
||||
break
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
accountFound = true
|
||||
@ -88,8 +90,12 @@ object AccountUtils {
|
||||
val packageManager = context.packageManager
|
||||
var appName = ""
|
||||
try {
|
||||
appName = packageManager.getApplicationLabel(packageManager.getApplicationInfo(packageName,
|
||||
PackageManager.GET_META_DATA)) as String
|
||||
appName = packageManager.getApplicationLabel(
|
||||
packageManager.getApplicationInfo(
|
||||
packageName,
|
||||
PackageManager.GET_META_DATA
|
||||
)
|
||||
) as String
|
||||
} catch (e: PackageManager.NameNotFoundException) {
|
||||
Log.e(TAG, "Failed to get app name based on package")
|
||||
}
|
||||
@ -103,7 +109,10 @@ object AccountUtils {
|
||||
val packageInfo = pm.getPackageInfo(context.getString(R.string.nc_import_accounts_from), 0)
|
||||
if (packageInfo.versionCode >= 30060151) {
|
||||
val ownSignatures = pm.getPackageInfo(context.packageName, PackageManager.GET_SIGNATURES).signatures
|
||||
val filesAppSignatures = pm.getPackageInfo(context.getString(R.string.nc_import_accounts_from), PackageManager.GET_SIGNATURES).signatures
|
||||
val filesAppSignatures = pm.getPackageInfo(
|
||||
context.getString(R.string.nc_import_accounts_from),
|
||||
PackageManager.GET_SIGNATURES
|
||||
).signatures
|
||||
|
||||
if (Arrays.equals(ownSignatures, filesAppSignatures)) {
|
||||
val accMgr = AccountManager.get(context)
|
||||
@ -118,7 +127,7 @@ object AccountUtils {
|
||||
}
|
||||
}
|
||||
} catch (appNotFoundException: PackageManager.NameNotFoundException) {
|
||||
|
||||
// ignore
|
||||
}
|
||||
|
||||
return false
|
||||
@ -146,4 +155,3 @@ object AccountUtils {
|
||||
return ImportAccount(username, password, urlString)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -27,7 +27,13 @@ import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler
|
||||
import com.nextcloud.talk.controllers.ChatController
|
||||
|
||||
object ConductorRemapping {
|
||||
fun remapChatController(router: Router, internalUserId: Long, roomTokenOrId: String, bundle: Bundle, replaceTop: Boolean) {
|
||||
fun remapChatController(
|
||||
router: Router,
|
||||
internalUserId: Long,
|
||||
roomTokenOrId: String,
|
||||
bundle: Bundle,
|
||||
replaceTop: Boolean
|
||||
) {
|
||||
val tag = "$internalUserId@$roomTokenOrId"
|
||||
if (router.getControllerWithTag(tag) != null) {
|
||||
val backstack = router.backstack
|
||||
@ -44,13 +50,17 @@ object ConductorRemapping {
|
||||
router.setBackstack(backstack, HorizontalChangeHandler())
|
||||
} else {
|
||||
if (!replaceTop) {
|
||||
router.pushController(RouterTransaction.with(ChatController(bundle))
|
||||
router.pushController(
|
||||
RouterTransaction.with(ChatController(bundle))
|
||||
.pushChangeHandler(HorizontalChangeHandler())
|
||||
.popChangeHandler(HorizontalChangeHandler()).tag(tag))
|
||||
.popChangeHandler(HorizontalChangeHandler()).tag(tag)
|
||||
)
|
||||
} else {
|
||||
router.replaceTopController(RouterTransaction.with(ChatController(bundle))
|
||||
router.replaceTopController(
|
||||
RouterTransaction.with(ChatController(bundle))
|
||||
.pushChangeHandler(HorizontalChangeHandler())
|
||||
.popChangeHandler(HorizontalChangeHandler()).tag(tag))
|
||||
.popChangeHandler(HorizontalChangeHandler()).tag(tag)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -21,8 +21,9 @@
|
||||
package com.nextcloud.talk.utils
|
||||
|
||||
import java.text.DateFormat
|
||||
import java.util.*
|
||||
|
||||
import java.util.Calendar
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
|
||||
object DateUtils {
|
||||
fun getLocalDateTimeStringFromTimestamp(timestamp: Long): String {
|
||||
@ -30,14 +31,16 @@ object DateUtils {
|
||||
val tz = cal.timeZone
|
||||
|
||||
/* date formatter in local timezone */
|
||||
val format = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.SHORT, Locale
|
||||
.getDefault())
|
||||
val format = DateFormat.getDateTimeInstance(
|
||||
DateFormat.DEFAULT, DateFormat.SHORT,
|
||||
Locale.getDefault()
|
||||
)
|
||||
format.timeZone = tz
|
||||
|
||||
return format.format(Date(timestamp))
|
||||
}
|
||||
|
||||
fun getLocalDateStringFromTimestampForLobby(timestamp: Long): String {
|
||||
return getLocalDateTimeStringFromTimestamp(timestamp * 1000);
|
||||
return getLocalDateTimeStringFromTimestamp(timestamp * 1000)
|
||||
}
|
||||
}
|
||||
|
@ -21,12 +21,10 @@
|
||||
package com.nextcloud.talk.utils
|
||||
|
||||
import com.nextcloud.talk.R
|
||||
|
||||
import java.util.HashMap
|
||||
|
||||
object DrawableUtils {
|
||||
|
||||
|
||||
fun getDrawableResourceIdForMimeType(mimetype: String): Int {
|
||||
var localMimetype = mimetype
|
||||
val drawableMap = HashMap<String, Int>()
|
||||
@ -55,15 +53,20 @@ object DrawableUtils {
|
||||
drawableMap["application/vnd.google-earth.kmz"] = R.drawable.ic_mimetype_location
|
||||
drawableMap["application/vnd.ms-excel"] = R.drawable.ic_mimetype_x_office_spreadsheet
|
||||
drawableMap["application/vnd.ms-excel.addin.macroEnabled.12"] = R.drawable.ic_mimetype_x_office_spreadsheet
|
||||
drawableMap["application/vnd.ms-excel.sheet.binary.macroEnabled.12"] = R.drawable.ic_mimetype_x_office_spreadsheet
|
||||
drawableMap["application/vnd.ms-excel.sheet.binary.macroEnabled.12"] =
|
||||
R.drawable.ic_mimetype_x_office_spreadsheet
|
||||
drawableMap["application/vnd.ms-excel.sheet.macroEnabled.12"] = R.drawable.ic_mimetype_x_office_spreadsheet
|
||||
drawableMap["application/vnd.ms-excel.template.macroEnabled.12"] = R.drawable.ic_mimetype_x_office_spreadsheet
|
||||
drawableMap["application/vnd.ms-fontobject"] = R.drawable.ic_mimetype_image
|
||||
drawableMap["application/vnd.ms-powerpoint"] = R.drawable.ic_mimetype_x_office_presentation
|
||||
drawableMap["application/vnd.ms-powerpoint.addin.macroEnabled.12"] = R.drawable.ic_mimetype_x_office_presentation
|
||||
drawableMap["application/vnd.ms-powerpoint.presentation.macroEnabled.12"] = R.drawable.ic_mimetype_x_office_presentation
|
||||
drawableMap["application/vnd.ms-powerpoint.slideshow.macroEnabled.12"] = R.drawable.ic_mimetype_x_office_presentation
|
||||
drawableMap["application/vnd.ms-powerpoint.template.macroEnabled.12"] = R.drawable.ic_mimetype_x_office_presentation
|
||||
drawableMap["application/vnd.ms-powerpoint.addin.macroEnabled.12"] =
|
||||
R.drawable.ic_mimetype_x_office_presentation
|
||||
drawableMap["application/vnd.ms-powerpoint.presentation.macroEnabled.12"] =
|
||||
R.drawable.ic_mimetype_x_office_presentation
|
||||
drawableMap["application/vnd.ms-powerpoint.slideshow.macroEnabled.12"] =
|
||||
R.drawable.ic_mimetype_x_office_presentation
|
||||
drawableMap["application/vnd.ms-powerpoint.template.macroEnabled.12"] =
|
||||
R.drawable.ic_mimetype_x_office_presentation
|
||||
drawableMap["application/vnd.ms-visio.drawing.macroEnabled.12"] = R.drawable.ic_mimetype_x_office_document
|
||||
drawableMap["application/vnd.ms-visio.drawing"] = R.drawable.ic_mimetype_x_office_document
|
||||
drawableMap["application/vnd.ms-visio.stencil.macroEnabled.12"] = R.drawable.ic_mimetype_x_office_document
|
||||
@ -72,20 +75,29 @@ object DrawableUtils {
|
||||
drawableMap["application/vnd.ms-visio.template"] = R.drawable.ic_mimetype_x_office_document
|
||||
drawableMap["application/vnd.ms-word.template.macroEnabled.12"] = R.drawable.ic_mimetype_x_office_document
|
||||
drawableMap["application/vnd.oasis.opendocument.presentation"] = R.drawable.ic_mimetype_x_office_presentation
|
||||
drawableMap["application/vnd.oasis.opendocument.presentation-template"] = R.drawable.ic_mimetype_x_office_presentation
|
||||
drawableMap["application/vnd.oasis.opendocument.presentation-template"] =
|
||||
R.drawable.ic_mimetype_x_office_presentation
|
||||
drawableMap["application/vnd.oasis.opendocument.spreadsheet"] = R.drawable.ic_mimetype_x_office_spreadsheet
|
||||
drawableMap["application/vnd.oasis.opendocument.spreadsheet-template"] = R.drawable.ic_mimetype_x_office_spreadsheet
|
||||
drawableMap["application/vnd.oasis.opendocument.spreadsheet-template"] =
|
||||
R.drawable.ic_mimetype_x_office_spreadsheet
|
||||
drawableMap["application/vnd.oasis.opendocument.text"] = R.drawable.ic_mimetype_x_office_document
|
||||
drawableMap["application/vnd.oasis.opendocument.text-master"] = R.drawable.ic_mimetype_x_office_document
|
||||
drawableMap["application/vnd.oasis.opendocument.text-template"] = R.drawable.ic_mimetype_x_office_document
|
||||
drawableMap["application/vnd.oasis.opendocument.text-web"] = R.drawable.ic_mimetype_x_office_document
|
||||
drawableMap["application/vnd.openxmlformats-officedocument.presentationml.presentation"] = R.drawable.ic_mimetype_x_office_presentation
|
||||
drawableMap["application/vnd.openxmlformats-officedocument.presentationml.slideshow"] = R.drawable.ic_mimetype_x_office_presentation
|
||||
drawableMap["application/vnd.openxmlformats-officedocument.presentationml.template"] = R.drawable.ic_mimetype_x_office_presentation
|
||||
drawableMap["application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"] = R.drawable.ic_mimetype_x_office_spreadsheet
|
||||
drawableMap["application/vnd.openxmlformats-officedocument.spreadsheetml.template"] = R.drawable.ic_mimetype_x_office_spreadsheet
|
||||
drawableMap["application/vnd.openxmlformats-officedocument.wordprocessingml.document"] = R.drawable.ic_mimetype_x_office_document
|
||||
drawableMap["application/vnd.openxmlformats-officedocument.wordprocessingml.template"] = R.drawable.ic_mimetype_x_office_document
|
||||
drawableMap["application/vnd.openxmlformats-officedocument.presentationml.presentation"] =
|
||||
R.drawable.ic_mimetype_x_office_presentation
|
||||
drawableMap["application/vnd.openxmlformats-officedocument.presentationml.slideshow"] =
|
||||
R.drawable.ic_mimetype_x_office_presentation
|
||||
drawableMap["application/vnd.openxmlformats-officedocument.presentationml.template"] =
|
||||
R.drawable.ic_mimetype_x_office_presentation
|
||||
drawableMap["application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"] =
|
||||
R.drawable.ic_mimetype_x_office_spreadsheet
|
||||
drawableMap["application/vnd.openxmlformats-officedocument.spreadsheetml.template"] =
|
||||
R.drawable.ic_mimetype_x_office_spreadsheet
|
||||
drawableMap["application/vnd.openxmlformats-officedocument.wordprocessingml.document"] =
|
||||
R.drawable.ic_mimetype_x_office_document
|
||||
drawableMap["application/vnd.openxmlformats-officedocument.wordprocessingml.template"] =
|
||||
R.drawable.ic_mimetype_x_office_document
|
||||
drawableMap["application/vnd.visio"] = R.drawable.ic_mimetype_x_office_document
|
||||
drawableMap["application/vnd.wordperfect"] = R.drawable.ic_mimetype_x_office_document
|
||||
drawableMap["application/x-7z-compressed"] = R.drawable.ic_mimetype_package_x_generic
|
||||
|
@ -29,7 +29,7 @@ import com.nextcloud.talk.BuildConfig
|
||||
import java.io.FileNotFoundException
|
||||
import java.io.IOException
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
import java.util.Date
|
||||
|
||||
object LoggingUtils {
|
||||
fun writeLogEntryToFile(context: Context, logEntry: String) {
|
||||
@ -38,8 +38,10 @@ object LoggingUtils {
|
||||
val logEntryWithDateTime = dateFormat.format(date) + ": " + logEntry + "\n"
|
||||
|
||||
try {
|
||||
val outputStream = context.openFileOutput("nc_log.txt",
|
||||
Context.MODE_PRIVATE or Context.MODE_APPEND)
|
||||
val outputStream = context.openFileOutput(
|
||||
"nc_log.txt",
|
||||
Context.MODE_PRIVATE or Context.MODE_APPEND
|
||||
)
|
||||
outputStream.write(logEntryWithDateTime.toByteArray())
|
||||
outputStream.flush()
|
||||
outputStream.close()
|
||||
@ -48,13 +50,12 @@ object LoggingUtils {
|
||||
} catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun sendMailWithAttachment(context: Context) {
|
||||
val logFile = context.getFileStreamPath("nc_log.txt")
|
||||
val emailIntent = Intent(Intent.ACTION_SEND)
|
||||
val mailto = "mario@nextcloud.com"
|
||||
val mailto = "android@nextcloud.com"
|
||||
emailIntent.putExtra(Intent.EXTRA_EMAIL, arrayOf(mailto))
|
||||
emailIntent.putExtra(Intent.EXTRA_SUBJECT, "Talk logs")
|
||||
emailIntent.type = "text/plain"
|
||||
|
@ -33,7 +33,7 @@ import android.service.notification.StatusBarNotification
|
||||
import com.nextcloud.talk.R
|
||||
import com.nextcloud.talk.models.database.UserEntity
|
||||
import com.nextcloud.talk.utils.bundle.BundleKeys
|
||||
import java.util.*
|
||||
import java.util.Objects
|
||||
|
||||
object NotificationUtils {
|
||||
val NOTIFICATION_CHANNEL_CALLS = "NOTIFICATION_CHANNEL_CALLS"
|
||||
@ -47,25 +47,50 @@ object NotificationUtils {
|
||||
return longArrayOf(0L, 400L, 800L, 600L, 800L, 800L, 800L, 1000L)
|
||||
}
|
||||
|
||||
fun getNotificationChannelId(channelName: String,
|
||||
channelDescription: String, enableLights: Boolean,
|
||||
importance: Int, sound: Uri, audioAttributes: AudioAttributes, vibrationPattern: LongArray?, bypassDnd: Boolean): String {
|
||||
return Objects.hash(channelName, channelDescription, enableLights, importance, sound, audioAttributes, vibrationPattern, bypassDnd).toString()
|
||||
fun getNotificationChannelId(
|
||||
channelName: String,
|
||||
channelDescription: String,
|
||||
enableLights: Boolean,
|
||||
importance: Int,
|
||||
sound: Uri,
|
||||
audioAttributes: AudioAttributes,
|
||||
vibrationPattern: LongArray?,
|
||||
bypassDnd: Boolean
|
||||
): String {
|
||||
return Objects.hash(
|
||||
channelName,
|
||||
channelDescription,
|
||||
enableLights,
|
||||
importance,
|
||||
sound,
|
||||
audioAttributes,
|
||||
vibrationPattern,
|
||||
bypassDnd
|
||||
).toString()
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.O)
|
||||
fun createNotificationChannel(context: Context,
|
||||
channelId: String, channelName: String,
|
||||
channelDescription: String, enableLights: Boolean,
|
||||
importance: Int, sound: Uri, audioAttributes: AudioAttributes,
|
||||
vibrationPattern: LongArray?, bypassDnd: Boolean = false) {
|
||||
fun createNotificationChannel(
|
||||
context: Context,
|
||||
channelId: String,
|
||||
channelName: String,
|
||||
channelDescription: String,
|
||||
enableLights: Boolean,
|
||||
importance: Int,
|
||||
sound: Uri,
|
||||
audioAttributes: AudioAttributes,
|
||||
vibrationPattern: LongArray?,
|
||||
bypassDnd: Boolean = false
|
||||
) {
|
||||
|
||||
val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && notificationManager.getNotificationChannel(channelId) == null) {
|
||||
|
||||
val channel = NotificationChannel(channelId, channelName,
|
||||
importance)
|
||||
val channel = NotificationChannel(
|
||||
channelId, channelName,
|
||||
importance
|
||||
)
|
||||
|
||||
channel.description = channelDescription
|
||||
channel.enableLights(enableLights)
|
||||
@ -84,8 +109,11 @@ object NotificationUtils {
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.O)
|
||||
fun createNotificationChannelGroup(context: Context,
|
||||
groupId: String, groupName: CharSequence) {
|
||||
fun createNotificationChannelGroup(
|
||||
context: Context,
|
||||
groupId: String,
|
||||
groupName: CharSequence
|
||||
) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
|
||||
@ -113,12 +141,12 @@ object NotificationUtils {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun cancelExistingNotificationWithId(context: Context?, conversationUser: UserEntity, notificationId: Long) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && conversationUser.id != -1L &&
|
||||
context != null) {
|
||||
context != null
|
||||
) {
|
||||
|
||||
val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
|
||||
@ -128,7 +156,10 @@ object NotificationUtils {
|
||||
notification = statusBarNotification.notification
|
||||
|
||||
if (notification != null && !notification.extras.isEmpty) {
|
||||
if (conversationUser.id == notification.extras.getLong(BundleKeys.KEY_INTERNAL_USER_ID) && notificationId == notification.extras.getLong(BundleKeys.KEY_NOTIFICATION_ID)) {
|
||||
if (conversationUser.id == notification.extras.getLong(BundleKeys.KEY_INTERNAL_USER_ID) && notificationId == notification.extras.getLong(
|
||||
BundleKeys.KEY_NOTIFICATION_ID
|
||||
)
|
||||
) {
|
||||
notificationManager.cancel(statusBarNotification.id)
|
||||
}
|
||||
}
|
||||
@ -136,11 +167,14 @@ object NotificationUtils {
|
||||
}
|
||||
}
|
||||
|
||||
fun findNotificationForRoom(context: Context?,
|
||||
conversationUser: UserEntity,
|
||||
roomTokenOrId: String): StatusBarNotification? {
|
||||
fun findNotificationForRoom(
|
||||
context: Context?,
|
||||
conversationUser: UserEntity,
|
||||
roomTokenOrId: String
|
||||
): StatusBarNotification? {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && conversationUser.id != -1L &&
|
||||
context != null) {
|
||||
context != null
|
||||
) {
|
||||
|
||||
val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
|
||||
@ -150,7 +184,10 @@ object NotificationUtils {
|
||||
notification = statusBarNotification.notification
|
||||
|
||||
if (notification != null && !notification.extras.isEmpty) {
|
||||
if (conversationUser.id == notification.extras.getLong(BundleKeys.KEY_INTERNAL_USER_ID) && roomTokenOrId == statusBarNotification.notification.extras.getString(BundleKeys.KEY_ROOM_TOKEN)) {
|
||||
if (conversationUser.id == notification.extras.getLong(BundleKeys.KEY_INTERNAL_USER_ID) && roomTokenOrId == statusBarNotification.notification.extras.getString(
|
||||
BundleKeys.KEY_ROOM_TOKEN
|
||||
)
|
||||
) {
|
||||
return statusBarNotification
|
||||
}
|
||||
}
|
||||
@ -160,10 +197,14 @@ object NotificationUtils {
|
||||
return null
|
||||
}
|
||||
|
||||
fun cancelExistingNotificationsForRoom(context: Context?, conversationUser: UserEntity,
|
||||
roomTokenOrId: String) {
|
||||
fun cancelExistingNotificationsForRoom(
|
||||
context: Context?,
|
||||
conversationUser: UserEntity,
|
||||
roomTokenOrId: String
|
||||
) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && conversationUser.id != -1L &&
|
||||
context != null) {
|
||||
context != null
|
||||
) {
|
||||
|
||||
val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
|
||||
@ -173,7 +214,11 @@ object NotificationUtils {
|
||||
notification = statusBarNotification.notification
|
||||
|
||||
if (notification != null && !notification.extras.isEmpty) {
|
||||
if (conversationUser.id == notification.extras.getLong(BundleKeys.KEY_INTERNAL_USER_ID) && roomTokenOrId == statusBarNotification.notification.extras.getString(BundleKeys.KEY_ROOM_TOKEN)) {
|
||||
if (conversationUser.id == notification.extras.getLong(BundleKeys.KEY_INTERNAL_USER_ID) &&
|
||||
roomTokenOrId == statusBarNotification.notification.extras.getString(
|
||||
BundleKeys.KEY_ROOM_TOKEN
|
||||
)
|
||||
) {
|
||||
notificationManager.cancel(statusBarNotification.id)
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,6 @@ import android.database.Cursor
|
||||
import android.net.Uri
|
||||
import android.provider.OpenableColumns
|
||||
import android.util.Log
|
||||
import com.nextcloud.talk.jobs.UploadAndShareFilesWorker
|
||||
|
||||
object UriUtils {
|
||||
|
||||
@ -51,5 +50,4 @@ object UriUtils {
|
||||
}
|
||||
return filename
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -21,8 +21,8 @@
|
||||
package com.nextcloud.talk.utils.bundle
|
||||
|
||||
object BundleKeys {
|
||||
val KEY_SELECTED_USERS = "KEY_SELECTED_USERS";
|
||||
val KEY_SELECTED_GROUPS = "KEY_SELECTED_GROUPS";
|
||||
val KEY_SELECTED_USERS = "KEY_SELECTED_USERS"
|
||||
val KEY_SELECTED_GROUPS = "KEY_SELECTED_GROUPS"
|
||||
val KEY_USERNAME = "KEY_USERNAME"
|
||||
val KEY_TOKEN = "KEY_TOKEN"
|
||||
val KEY_BASE_URL = "KEY_BASE_URL"
|
||||
|
@ -13,11 +13,17 @@ import java.io.IOException
|
||||
import java.net.InetAddress
|
||||
import java.net.Socket
|
||||
import java.security.GeneralSecurityException
|
||||
import java.util.*
|
||||
import javax.net.ssl.*
|
||||
import java.util.LinkedList
|
||||
import javax.net.ssl.KeyManager
|
||||
import javax.net.ssl.SSLContext
|
||||
import javax.net.ssl.SSLSocket
|
||||
import javax.net.ssl.SSLSocketFactory
|
||||
import javax.net.ssl.X509TrustManager
|
||||
|
||||
class SSLSocketFactoryCompat(keyManager: KeyManager?,
|
||||
trustManager: X509TrustManager) : SSLSocketFactory() {
|
||||
class SSLSocketFactoryCompat(
|
||||
keyManager: KeyManager?,
|
||||
trustManager: X509TrustManager
|
||||
) : SSLSocketFactory() {
|
||||
|
||||
private var delegate: SSLSocketFactory
|
||||
|
||||
@ -50,24 +56,24 @@ class SSLSocketFactoryCompat(keyManager: KeyManager?,
|
||||
|
||||
/* set up reasonable cipher suites */
|
||||
val knownCiphers = arrayOf<String>(
|
||||
// TLS 1.2
|
||||
"TLS_RSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||
// maximum interoperability
|
||||
"TLS_RSA_WITH_3DES_EDE_CBC_SHA",
|
||||
"SSL_RSA_WITH_3DES_EDE_CBC_SHA",
|
||||
"TLS_RSA_WITH_AES_128_CBC_SHA",
|
||||
// additionally
|
||||
"TLS_RSA_WITH_AES_256_CBC_SHA",
|
||||
"TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
|
||||
"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA"
|
||||
// TLS 1.2
|
||||
"TLS_RSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||
// maximum interoperability
|
||||
"TLS_RSA_WITH_3DES_EDE_CBC_SHA",
|
||||
"SSL_RSA_WITH_3DES_EDE_CBC_SHA",
|
||||
"TLS_RSA_WITH_AES_128_CBC_SHA",
|
||||
// additionally
|
||||
"TLS_RSA_WITH_AES_256_CBC_SHA",
|
||||
"TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
|
||||
"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA"
|
||||
)
|
||||
val availableCiphers = socket.supportedCipherSuites
|
||||
|
||||
@ -89,31 +95,31 @@ class SSLSocketFactoryCompat(keyManager: KeyManager?,
|
||||
} catch (e: IOException) {
|
||||
// Exception is to be ignored
|
||||
} finally {
|
||||
socket?.close() // doesn't implement Closeable on all supported Android versions
|
||||
socket?.close() // doesn't implement Closeable on all supported Android versions
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
init {
|
||||
try {
|
||||
val sslContext = SSLContext.getInstance("TLS")
|
||||
sslContext.init(
|
||||
if (keyManager != null) arrayOf(keyManager) else null,
|
||||
arrayOf(trustManager),
|
||||
null)
|
||||
if (keyManager != null) arrayOf(keyManager) else null,
|
||||
arrayOf(trustManager),
|
||||
null
|
||||
)
|
||||
delegate = sslContext.socketFactory
|
||||
} catch (e: GeneralSecurityException) {
|
||||
throw IllegalStateException() // system has no TLS
|
||||
throw IllegalStateException() // system has no TLS
|
||||
}
|
||||
}
|
||||
|
||||
override fun getDefaultCipherSuites(): Array<String>? = cipherSuites
|
||||
?: delegate.defaultCipherSuites
|
||||
?: delegate.defaultCipherSuites
|
||||
|
||||
override fun getSupportedCipherSuites(): Array<String>? = cipherSuites
|
||||
?: delegate.supportedCipherSuites
|
||||
?: delegate.supportedCipherSuites
|
||||
|
||||
override fun createSocket(s: Socket, host: String, port: Int, autoClose: Boolean): Socket {
|
||||
val ssl = delegate.createSocket(s, host, port, autoClose)
|
||||
@ -150,10 +156,8 @@ class SSLSocketFactoryCompat(keyManager: KeyManager?,
|
||||
return ssl
|
||||
}
|
||||
|
||||
|
||||
private fun upgradeTLS(ssl: SSLSocket) {
|
||||
protocols?.let { ssl.enabledProtocols = it }
|
||||
cipherSuites?.let { ssl.enabledCipherSuites = it }
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user