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)
|
||||
@ -227,7 +261,9 @@ class MagicFirebaseMessagingService : FirebaseMessagingService() {
|
||||
.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,14 +280,23 @@ 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))
|
||||
ncApi.getPeersForCall(
|
||||
ApiUtils.getCredentials(signatureVerification.userEntity.username, signatureVerification.userEntity.token),
|
||||
ApiUtils.getUrlForCall(
|
||||
signatureVerification.userEntity.baseUrl,
|
||||
decryptedPushMessage.id
|
||||
)
|
||||
)
|
||||
.takeWhile {
|
||||
isServiceInForeground
|
||||
}
|
||||
@ -276,9 +321,12 @@ class MagicFirebaseMessagingService : FirebaseMessagingService() {
|
||||
stopForeground(true)
|
||||
handler.removeCallbacksAndMessages(null)
|
||||
} else if (isServiceInForeground) {
|
||||
handler.postDelayed({
|
||||
handler.postDelayed(
|
||||
{
|
||||
checkIfCallIsActive(signatureVerification, decryptedPushMessage)
|
||||
}, 5000)
|
||||
},
|
||||
5000
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,9 +104,11 @@ 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)
|
||||
@ -120,11 +125,9 @@ open class BaseActivity : AppCompatActivity() {
|
||||
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,
|
||||
val shareUri = FileProvider.getUriForFile(
|
||||
this,
|
||||
BuildConfig.APPLICATION_ID,
|
||||
File(path))
|
||||
File(path)
|
||||
)
|
||||
|
||||
val shareIntent: Intent = Intent().apply {
|
||||
action = Intent.ACTION_SEND
|
||||
@ -78,7 +79,7 @@ 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)
|
||||
@ -116,7 +117,7 @@ class FullScreenImageActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
private fun toggleFullscreen() {
|
||||
showFullscreen = !showFullscreen;
|
||||
showFullscreen = !showFullscreen
|
||||
if (showFullscreen) {
|
||||
hideSystemUI()
|
||||
supportActionBar?.hide()
|
||||
@ -127,17 +128,21 @@ class FullScreenImageActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
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,
|
||||
val shareUri = FileProvider.getUriForFile(
|
||||
this,
|
||||
BuildConfig.APPLICATION_ID,
|
||||
File(path))
|
||||
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,
|
||||
val shareUri = FileProvider.getUriForFile(
|
||||
this,
|
||||
BuildConfig.APPLICATION_ID,
|
||||
File(path))
|
||||
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)
|
||||
|
||||
}
|
||||
|
@ -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,13 +76,17 @@ 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())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -89,9 +95,11 @@ class MagicCallActivity : BaseActivity() {
|
||||
|
||||
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() {
|
||||
|
@ -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())
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -193,8 +215,10 @@ 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()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -206,10 +230,14 @@ class MainActivity : BaseActivity(), ActionBarProvider {
|
||||
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)
|
||||
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> {
|
||||
@ -221,18 +249,26 @@ class MainActivity : BaseActivity(), ActionBarProvider {
|
||||
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))
|
||||
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)
|
||||
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) {}
|
||||
@ -241,11 +277,14 @@ class MainActivity : BaseActivity(), ActionBarProvider {
|
||||
} else {
|
||||
conversationIntent.putExtras(bundle)
|
||||
startActivity(conversationIntent)
|
||||
Handler().postDelayed({
|
||||
Handler().postDelayed(
|
||||
{
|
||||
if (!isDestroyed) {
|
||||
router!!.popCurrentController()
|
||||
}
|
||||
}, 100)
|
||||
},
|
||||
100
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -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)
|
||||
@ -231,7 +229,10 @@ 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
|
||||
|
@ -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,
|
||||
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)
|
||||
R.xml.chip_others
|
||||
)
|
||||
} else if (individualHashMap["type"] == "file") {
|
||||
realView.setOnClickListener(View.OnClickListener { v: View? ->
|
||||
realView.setOnClickListener(
|
||||
View.OnClickListener { v: View? ->
|
||||
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(individualHashMap["link"]))
|
||||
context!!.startActivity(browserIntent)
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -138,14 +143,16 @@ class MagicOutcomingTextMessageViewHolder(itemView: View) : OutcomingTextMessage
|
||||
bgBubbleColor,
|
||||
resources.getColor(R.color.transparent),
|
||||
bgBubbleColor,
|
||||
R.drawable.shape_grouped_outcoming_message)
|
||||
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)
|
||||
R.drawable.shape_outcoming_message
|
||||
)
|
||||
ViewCompat.setBackground(bubble, bubbleDrawable)
|
||||
}
|
||||
messageText!!.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize)
|
||||
@ -160,7 +167,10 @@ 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
|
||||
|
@ -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)
|
||||
}
|
||||
@ -137,11 +140,13 @@ class NextcloudTalkApplication : MultiDexApplication(), LifecycleObserver {
|
||||
|
||||
val imagePipelineConfig = ImagePipelineConfig.newBuilder(this)
|
||||
.setNetworkFetcher(OkHttpNetworkFetcherWithCache(okHttpClient))
|
||||
.setMainDiskCacheConfig(DiskCacheConfig.newBuilder(this)
|
||||
.setMainDiskCacheConfig(
|
||||
DiskCacheConfig.newBuilder(this)
|
||||
.setMaxCacheSize(0)
|
||||
.setMaxCacheSizeOnLowDiskSpace(0)
|
||||
.setMaxCacheSizeOnVeryLowDiskSpace(0)
|
||||
.build())
|
||||
.build()
|
||||
)
|
||||
.build()
|
||||
|
||||
Fresco.initialize(this, imagePipelineConfig)
|
||||
@ -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,7 +187,6 @@ class NextcloudTalkApplication : MultiDexApplication(), LifecycleObserver {
|
||||
}
|
||||
//endregion
|
||||
|
||||
|
||||
//region Protected methods
|
||||
protected fun buildComponent() {
|
||||
componentApplication = DaggerNextcloudTalkApplicationComponent.builder()
|
||||
@ -209,6 +219,7 @@ class NextcloudTalkApplication : MultiDexApplication(), LifecycleObserver {
|
||||
.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;
|
||||
|
@ -40,8 +40,22 @@ import android.text.TextUtils
|
||||
import android.text.TextWatcher
|
||||
import android.util.Log
|
||||
import android.util.TypedValue
|
||||
import android.view.*
|
||||
import android.widget.*
|
||||
import android.view.Gravity
|
||||
import android.view.LayoutInflater
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.AbsListView
|
||||
import android.widget.ImageButton
|
||||
import android.widget.ImageView
|
||||
import android.widget.PopupMenu
|
||||
import android.widget.ProgressBar
|
||||
import android.widget.RelativeLayout
|
||||
import android.widget.Space
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory
|
||||
import androidx.emoji.text.EmojiCompat
|
||||
import androidx.emoji.widget.EmojiEditText
|
||||
@ -55,7 +69,6 @@ import autodagger.AutoInjector
|
||||
import butterknife.BindView
|
||||
import butterknife.OnClick
|
||||
import coil.load
|
||||
import coil.transform.CircleCropTransformation
|
||||
import com.bluelinelabs.conductor.RouterTransaction
|
||||
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler
|
||||
import com.bluelinelabs.conductor.changehandler.VerticalChangeHandler
|
||||
@ -69,7 +82,12 @@ import com.facebook.imagepipeline.image.CloseableImage
|
||||
import com.google.android.flexbox.FlexboxLayout
|
||||
import com.nextcloud.talk.R
|
||||
import com.nextcloud.talk.activities.MagicCallActivity
|
||||
import com.nextcloud.talk.adapters.messages.*
|
||||
import com.nextcloud.talk.adapters.messages.MagicIncomingTextMessageViewHolder
|
||||
import com.nextcloud.talk.adapters.messages.MagicOutcomingTextMessageViewHolder
|
||||
import com.nextcloud.talk.adapters.messages.MagicPreviewMessageViewHolder
|
||||
import com.nextcloud.talk.adapters.messages.MagicSystemMessageViewHolder
|
||||
import com.nextcloud.talk.adapters.messages.MagicUnreadNoticeMessageViewHolder
|
||||
import com.nextcloud.talk.adapters.messages.TalkMessagesListAdapter
|
||||
import com.nextcloud.talk.api.NcApi
|
||||
import com.nextcloud.talk.application.NextcloudTalkApplication
|
||||
import com.nextcloud.talk.callbacks.MentionAutocompleteCallback
|
||||
@ -91,7 +109,14 @@ import com.nextcloud.talk.models.json.generic.GenericOverall
|
||||
import com.nextcloud.talk.models.json.mention.Mention
|
||||
import com.nextcloud.talk.presenters.MentionAutocompletePresenter
|
||||
import com.nextcloud.talk.ui.dialog.AttachmentDialog
|
||||
import com.nextcloud.talk.utils.*
|
||||
import com.nextcloud.talk.utils.ApiUtils
|
||||
import com.nextcloud.talk.utils.ConductorRemapping
|
||||
import com.nextcloud.talk.utils.DateUtils
|
||||
import com.nextcloud.talk.utils.DisplayUtils
|
||||
import com.nextcloud.talk.utils.KeyboardUtils
|
||||
import com.nextcloud.talk.utils.MagicCharPolicy
|
||||
import com.nextcloud.talk.utils.NotificationUtils
|
||||
import com.nextcloud.talk.utils.UriUtils
|
||||
import com.nextcloud.talk.utils.bundle.BundleKeys
|
||||
import com.nextcloud.talk.utils.database.user.UserUtils
|
||||
import com.nextcloud.talk.utils.preferences.AppPreferences
|
||||
@ -121,14 +146,20 @@ import org.parceler.Parcels
|
||||
import retrofit2.HttpException
|
||||
import retrofit2.Response
|
||||
import java.net.HttpURLConnection
|
||||
import java.util.*
|
||||
import java.util.ArrayList
|
||||
import java.util.Date
|
||||
import java.util.HashMap
|
||||
import java.util.Objects
|
||||
import java.util.concurrent.TimeUnit
|
||||
import javax.inject.Inject
|
||||
|
||||
@AutoInjector(NextcloudTalkApplication::class)
|
||||
class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
||||
.OnLoadMoreListener, MessagesListAdapter.Formatter<Date>, MessagesListAdapter
|
||||
.OnMessageViewLongClickListener<IMessage>, MessageHolders.ContentChecker<IMessage> {
|
||||
class ChatController(args: Bundle) :
|
||||
BaseController(args),
|
||||
MessagesListAdapter.OnLoadMoreListener,
|
||||
MessagesListAdapter.Formatter<Date>,
|
||||
MessagesListAdapter.OnMessageViewLongClickListener<IMessage>,
|
||||
MessageHolders.ContentChecker<IMessage> {
|
||||
|
||||
@Inject
|
||||
@JvmField
|
||||
@ -236,7 +267,8 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
||||
this.roomToken = args.getString(BundleKeys.KEY_ROOM_TOKEN, "")
|
||||
|
||||
if (args.containsKey(BundleKeys.KEY_ACTIVE_CONVERSATION)) {
|
||||
this.currentConversation = Parcels.unwrap<Conversation>(args.getParcelable<Parcelable>(BundleKeys.KEY_ACTIVE_CONVERSATION))
|
||||
this.currentConversation =
|
||||
Parcels.unwrap<Conversation>(args.getParcelable<Parcelable>(BundleKeys.KEY_ACTIVE_CONVERSATION))
|
||||
}
|
||||
|
||||
this.roomPassword = args.getString(BundleKeys.KEY_CONVERSATION_PASSWORD, "")
|
||||
@ -260,9 +292,9 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
||||
checkingLobbyStatus = true
|
||||
}
|
||||
|
||||
|
||||
if (conversationUser != null) {
|
||||
ncApi?.getRoom(credentials, ApiUtils.getRoom(conversationUser.baseUrl, roomToken))?.subscribeOn(Schedulers.io())
|
||||
ncApi?.getRoom(credentials, ApiUtils.getRoom(conversationUser.baseUrl, roomToken))
|
||||
?.subscribeOn(Schedulers.io())
|
||||
?.observeOn(AndroidSchedulers.mainThread())
|
||||
?.subscribe(object : Observer<RoomOverall> {
|
||||
override fun onSubscribe(d: Disposable) {
|
||||
@ -281,11 +313,9 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
||||
if (!inConversation) {
|
||||
joinRoomWithPassword()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun onError(e: Throwable) {
|
||||
|
||||
}
|
||||
|
||||
override fun onComplete() {
|
||||
@ -303,7 +333,8 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
||||
|
||||
private fun handleFromNotification() {
|
||||
ncApi?.getRooms(credentials, ApiUtils.getUrlForGetRooms(conversationUser?.baseUrl))
|
||||
?.subscribeOn(Schedulers.io())?.observeOn(AndroidSchedulers.mainThread())?.subscribe(object : Observer<RoomsOverall> {
|
||||
?.subscribeOn(Schedulers.io())?.observeOn(AndroidSchedulers.mainThread())
|
||||
?.subscribe(object : Observer<RoomsOverall> {
|
||||
override fun onSubscribe(d: Disposable) {
|
||||
disposableList.add(d)
|
||||
}
|
||||
@ -321,11 +352,9 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
||||
}
|
||||
|
||||
override fun onError(e: Throwable) {
|
||||
|
||||
}
|
||||
|
||||
override fun onComplete() {
|
||||
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -336,16 +365,25 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
||||
|
||||
private fun loadAvatarForStatusBar() {
|
||||
if (inOneToOneCall() && activity != null && conversationVoiceCallMenuItem != null) {
|
||||
val avatarSize = DisplayUtils.convertDpToPixel(conversationVoiceCallMenuItem?.icon!!
|
||||
.intrinsicWidth.toFloat(), activity).toInt()
|
||||
val avatarSize = DisplayUtils.convertDpToPixel(
|
||||
conversationVoiceCallMenuItem?.icon!!
|
||||
.intrinsicWidth.toFloat(),
|
||||
activity
|
||||
).toInt()
|
||||
|
||||
val imageRequest = DisplayUtils.getImageRequestForUrl(ApiUtils.getUrlForAvatarWithNameAndPixels(conversationUser?.baseUrl,
|
||||
currentConversation?.name, avatarSize / 2), conversationUser!!)
|
||||
val imageRequest = DisplayUtils.getImageRequestForUrl(
|
||||
ApiUtils.getUrlForAvatarWithNameAndPixels(
|
||||
conversationUser?.baseUrl,
|
||||
currentConversation?.name, avatarSize / 2
|
||||
),
|
||||
conversationUser!!
|
||||
)
|
||||
|
||||
val imagePipeline = Fresco.getImagePipeline()
|
||||
val dataSource = imagePipeline.fetchDecodedImage(imageRequest, null)
|
||||
|
||||
dataSource.subscribe(object : BaseBitmapDataSubscriber() {
|
||||
dataSource.subscribe(
|
||||
object : BaseBitmapDataSubscriber() {
|
||||
override fun onNewResultImpl(bitmap: Bitmap?) {
|
||||
if (actionBar != null && bitmap != null && resources != null) {
|
||||
val roundedBitmapDrawable = RoundedBitmapDrawableFactory.create(resources!!, bitmap)
|
||||
@ -356,7 +394,9 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
||||
}
|
||||
|
||||
override fun onFailureImpl(dataSource: DataSource<CloseableReference<CloseableImage>>) {}
|
||||
}, UiThreadImmediateExecutorService.getInstance())
|
||||
},
|
||||
UiThreadImmediateExecutorService.getInstance()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -374,21 +414,40 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
||||
adapterWasNull = true
|
||||
|
||||
val messageHolders = MessageHolders()
|
||||
messageHolders.setIncomingTextConfig(MagicIncomingTextMessageViewHolder::class.java, R.layout.item_custom_incoming_text_message)
|
||||
messageHolders.setOutcomingTextConfig(MagicOutcomingTextMessageViewHolder::class.java, R.layout.item_custom_outcoming_text_message)
|
||||
messageHolders.setIncomingTextConfig(
|
||||
MagicIncomingTextMessageViewHolder::class.java,
|
||||
R.layout.item_custom_incoming_text_message
|
||||
)
|
||||
messageHolders.setOutcomingTextConfig(
|
||||
MagicOutcomingTextMessageViewHolder::class.java,
|
||||
R.layout.item_custom_outcoming_text_message
|
||||
)
|
||||
|
||||
messageHolders.setIncomingImageConfig(MagicPreviewMessageViewHolder::class.java, R.layout.item_custom_incoming_preview_message)
|
||||
messageHolders.setOutcomingImageConfig(MagicPreviewMessageViewHolder::class.java, R.layout.item_custom_outcoming_preview_message)
|
||||
messageHolders.setIncomingImageConfig(
|
||||
MagicPreviewMessageViewHolder::class.java,
|
||||
R.layout.item_custom_incoming_preview_message
|
||||
)
|
||||
messageHolders.setOutcomingImageConfig(
|
||||
MagicPreviewMessageViewHolder::class.java,
|
||||
R.layout.item_custom_outcoming_preview_message
|
||||
)
|
||||
|
||||
messageHolders.registerContentType(CONTENT_TYPE_SYSTEM_MESSAGE, MagicSystemMessageViewHolder::class.java,
|
||||
messageHolders.registerContentType(
|
||||
CONTENT_TYPE_SYSTEM_MESSAGE, MagicSystemMessageViewHolder::class.java,
|
||||
R.layout.item_system_message, MagicSystemMessageViewHolder::class.java, R.layout.item_system_message,
|
||||
this)
|
||||
this
|
||||
)
|
||||
|
||||
messageHolders.registerContentType(CONTENT_TYPE_UNREAD_NOTICE_MESSAGE,
|
||||
messageHolders.registerContentType(
|
||||
CONTENT_TYPE_UNREAD_NOTICE_MESSAGE,
|
||||
MagicUnreadNoticeMessageViewHolder::class.java, R.layout.item_date_header,
|
||||
MagicUnreadNoticeMessageViewHolder::class.java, R.layout.item_date_header, this)
|
||||
MagicUnreadNoticeMessageViewHolder::class.java, R.layout.item_date_header, this
|
||||
)
|
||||
|
||||
adapter = TalkMessagesListAdapter(conversationUser?.userId, messageHolders, ImageLoader { imageView, url, payload ->
|
||||
adapter = TalkMessagesListAdapter(
|
||||
conversationUser?.userId,
|
||||
messageHolders,
|
||||
ImageLoader { imageView, url, payload ->
|
||||
val draweeController = Fresco.newDraweeControllerBuilder()
|
||||
.setImageRequest(DisplayUtils.getImageRequestForUrl(url, conversationUser))
|
||||
.setControllerListener(DisplayUtils.getImageControllerListener(imageView))
|
||||
@ -396,7 +455,8 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
||||
.setAutoPlayAnimations(true)
|
||||
.build()
|
||||
imageView.controller = draweeController
|
||||
})
|
||||
}
|
||||
)
|
||||
} else {
|
||||
messagesListView?.visibility = View.VISIBLE
|
||||
}
|
||||
@ -449,7 +509,6 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
val filters = arrayOfNulls<InputFilter>(1)
|
||||
val lengthFilter = conversationUser?.messageMaxLength ?: 1000
|
||||
|
||||
@ -458,27 +517,34 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
||||
|
||||
messageInput?.addTextChangedListener(object : TextWatcher {
|
||||
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
|
||||
|
||||
}
|
||||
|
||||
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
|
||||
if (s.length >= lengthFilter) {
|
||||
messageInput?.error = String.format(Objects.requireNonNull<Resources>
|
||||
(resources).getString(R.string.nc_limit_hit), Integer.toString(lengthFilter))
|
||||
messageInput?.error = String.format(
|
||||
Objects.requireNonNull<Resources>
|
||||
(resources).getString(R.string.nc_limit_hit),
|
||||
Integer.toString(lengthFilter)
|
||||
)
|
||||
} else {
|
||||
messageInput?.error = null
|
||||
}
|
||||
|
||||
val editable = messageInput?.editableText
|
||||
if (editable != null && messageInput != null) {
|
||||
val mentionSpans = editable.getSpans(0, messageInput!!.length(),
|
||||
Spans.MentionChipSpan::class.java)
|
||||
val mentionSpans = editable.getSpans(
|
||||
0, messageInput!!.length(),
|
||||
Spans.MentionChipSpan::class.java
|
||||
)
|
||||
var mentionSpan: Spans.MentionChipSpan
|
||||
for (i in mentionSpans.indices) {
|
||||
mentionSpan = mentionSpans[i]
|
||||
if (start >= editable.getSpanStart(mentionSpan) && start < editable.getSpanEnd(mentionSpan)) {
|
||||
if (editable.subSequence(editable.getSpanStart(mentionSpan),
|
||||
editable.getSpanEnd(mentionSpan)).toString().trim { it <= ' ' } != mentionSpan.label) {
|
||||
if (editable.subSequence(
|
||||
editable.getSpanStart(mentionSpan),
|
||||
editable.getSpanEnd(mentionSpan)
|
||||
).toString().trim { it <= ' ' } != mentionSpan.label
|
||||
) {
|
||||
editable.removeSpan(mentionSpan)
|
||||
}
|
||||
}
|
||||
@ -487,18 +553,19 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
||||
}
|
||||
|
||||
override fun afterTextChanged(s: Editable) {
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
messageInputView?.setAttachmentsListener {
|
||||
activity?.let { AttachmentDialog(it, this).show() };
|
||||
activity?.let { AttachmentDialog(it, this).show() }
|
||||
}
|
||||
|
||||
messageInputView?.button?.setOnClickListener { v -> submitMessage() }
|
||||
|
||||
messageInputView?.button?.contentDescription = resources?.getString(R.string
|
||||
.nc_description_send_message_button)
|
||||
messageInputView?.button?.contentDescription = resources?.getString(
|
||||
R.string
|
||||
.nc_description_send_message_button
|
||||
)
|
||||
|
||||
if (currentConversation != null && currentConversation?.roomId != null) {
|
||||
loadAvatarForStatusBar()
|
||||
@ -516,7 +583,6 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
||||
super.onViewBound(view)
|
||||
}
|
||||
|
||||
|
||||
private fun checkReadOnlyState() {
|
||||
if (currentConversation != null) {
|
||||
if (currentConversation?.shouldShowLobby(conversationUser) ?: false || currentConversation?.conversationReadOnlyState != null && currentConversation?.conversationReadOnlyState == Conversation.ConversationReadOnlyState.CONVERSATION_READ_ONLY) {
|
||||
@ -524,7 +590,6 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
||||
conversationVoiceCallMenuItem?.icon?.alpha = 99
|
||||
conversationVideoMenuItem?.icon?.alpha = 99
|
||||
messageInputView?.visibility = View.GONE
|
||||
|
||||
} else {
|
||||
if (conversationVoiceCallMenuItem != null) {
|
||||
conversationVoiceCallMenuItem?.icon?.alpha = 255
|
||||
@ -535,7 +600,8 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
||||
}
|
||||
|
||||
if (currentConversation != null && currentConversation!!.shouldShowLobby
|
||||
(conversationUser)) {
|
||||
(conversationUser)
|
||||
) {
|
||||
messageInputView?.visibility = View.GONE
|
||||
} else {
|
||||
messageInputView?.visibility = View.VISIBLE
|
||||
@ -558,9 +624,15 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
||||
loadingProgressBar?.visibility = View.GONE
|
||||
|
||||
if (currentConversation?.lobbyTimer != null && currentConversation?.lobbyTimer !=
|
||||
0L) {
|
||||
conversationLobbyText?.text = String.format(resources!!.getString(R.string.nc_lobby_waiting_with_date), DateUtils.getLocalDateStringFromTimestampForLobby(currentConversation?.lobbyTimer
|
||||
?: 0))
|
||||
0L
|
||||
) {
|
||||
conversationLobbyText?.text = String.format(
|
||||
resources!!.getString(R.string.nc_lobby_waiting_with_date),
|
||||
DateUtils.getLocalDateStringFromTimestampForLobby(
|
||||
currentConversation?.lobbyTimer
|
||||
?: 0
|
||||
)
|
||||
)
|
||||
} else {
|
||||
conversationLobbyText?.setText(R.string.nc_lobby_waiting)
|
||||
}
|
||||
@ -622,16 +694,20 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
||||
.setMessage(filenamesWithLinebreaks)
|
||||
.setPositiveButton(R.string.nc_yes) { v ->
|
||||
uploadFiles(files)
|
||||
Toast.makeText(context, context?.resources?.getString(R.string.nc_upload_in_progess), Toast
|
||||
.LENGTH_LONG).show();
|
||||
Toast.makeText(
|
||||
context, context?.resources?.getString(R.string.nc_upload_in_progess),
|
||||
Toast.LENGTH_LONG
|
||||
).show()
|
||||
}
|
||||
.setNegativeButton(R.string.nc_no) {}
|
||||
.show()
|
||||
} catch (e: IllegalStateException) {
|
||||
Toast.makeText(context, context?.resources?.getString(R.string.nc_upload_failed), Toast.LENGTH_LONG).show()
|
||||
Toast.makeText(context, context?.resources?.getString(R.string.nc_upload_failed), Toast.LENGTH_LONG)
|
||||
.show()
|
||||
Log.e(javaClass.simpleName, "Something went wrong when trying to upload file", e)
|
||||
} catch (e: IllegalArgumentException) {
|
||||
Toast.makeText(context, context?.resources?.getString(R.string.nc_upload_failed), Toast.LENGTH_LONG).show()
|
||||
Toast.makeText(context, context?.resources?.getString(R.string.nc_upload_failed), Toast.LENGTH_LONG)
|
||||
.show()
|
||||
Log.e(javaClass.simpleName, "Something went wrong when trying to upload file", e)
|
||||
}
|
||||
}
|
||||
@ -662,8 +738,15 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
||||
addCategory(Intent.CATEGORY_OPENABLE)
|
||||
putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
|
||||
}
|
||||
startActivityForResult(Intent.createChooser(action, context?.resources?.getString(
|
||||
R.string.nc_upload_choose_local_files)), REQUEST_CODE_CHOOSE_FILE);
|
||||
startActivityForResult(
|
||||
Intent.createChooser(
|
||||
action,
|
||||
context?.resources?.getString(
|
||||
R.string.nc_upload_choose_local_files
|
||||
)
|
||||
),
|
||||
REQUEST_CODE_CHOOSE_FILE
|
||||
)
|
||||
}
|
||||
|
||||
fun showBrowserScreen(browserType: BrowserController.BrowserType) {
|
||||
@ -671,19 +754,23 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
||||
bundle.putParcelable(BundleKeys.KEY_BROWSER_TYPE, Parcels.wrap<BrowserController.BrowserType>(browserType))
|
||||
bundle.putParcelable(BundleKeys.KEY_USER_ENTITY, Parcels.wrap<UserEntity>(conversationUser))
|
||||
bundle.putString(BundleKeys.KEY_ROOM_TOKEN, roomToken)
|
||||
router.pushController(RouterTransaction.with(BrowserForSharingController(bundle))
|
||||
router.pushController(
|
||||
RouterTransaction.with(BrowserForSharingController(bundle))
|
||||
.pushChangeHandler(VerticalChangeHandler())
|
||||
.popChangeHandler(VerticalChangeHandler()))
|
||||
.popChangeHandler(VerticalChangeHandler())
|
||||
)
|
||||
}
|
||||
|
||||
private fun showConversationInfoScreen() {
|
||||
val bundle = Bundle()
|
||||
bundle.putParcelable(BundleKeys.KEY_USER_ENTITY, conversationUser)
|
||||
bundle.putString(BundleKeys.KEY_ROOM_TOKEN, roomToken)
|
||||
bundle.putBoolean(BundleKeys.KEY_ROOM_ONE_TO_ONE, inOneToOneCall());
|
||||
router.pushController(RouterTransaction.with(ConversationInfoController(bundle))
|
||||
bundle.putBoolean(BundleKeys.KEY_ROOM_ONE_TO_ONE, inOneToOneCall())
|
||||
router.pushController(
|
||||
RouterTransaction.with(ConversationInfoController(bundle))
|
||||
.pushChangeHandler(HorizontalChangeHandler())
|
||||
.popChangeHandler(HorizontalChangeHandler()))
|
||||
.popChangeHandler(HorizontalChangeHandler())
|
||||
)
|
||||
}
|
||||
|
||||
private fun setupMentionAutocomplete() {
|
||||
@ -691,8 +778,10 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
||||
resources?.let {
|
||||
val backgroundDrawable = ColorDrawable(it.getColor(R.color.bg_default))
|
||||
val presenter = MentionAutocompletePresenter(applicationContext, roomToken)
|
||||
val callback = MentionAutocompleteCallback(activity,
|
||||
conversationUser, messageInput)
|
||||
val callback = MentionAutocompleteCallback(
|
||||
activity,
|
||||
conversationUser, messageInput
|
||||
)
|
||||
|
||||
if (mentionAutocomplete == null && messageInput != null) {
|
||||
mentionAutocomplete = Autocomplete.on<Mention>(messageInput)
|
||||
@ -730,8 +819,10 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
||||
smileyButton?.setColorFilter(resources!!.getColor(R.color.colorPrimary), PorterDuff.Mode.SRC_IN)
|
||||
}
|
||||
}.setOnEmojiPopupDismissListener {
|
||||
smileyButton?.setColorFilter(resources!!.getColor(R.color.emoji_icons),
|
||||
PorterDuff.Mode.SRC_IN)
|
||||
smileyButton?.setColorFilter(
|
||||
resources!!.getColor(R.color.emoji_icons),
|
||||
PorterDuff.Mode.SRC_IN
|
||||
)
|
||||
}.setOnEmojiClickListener { emoji, imageView -> messageInput?.editableText?.append(" ") }.build(it)
|
||||
}
|
||||
|
||||
@ -753,11 +844,15 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
||||
private fun cancelNotificationsForCurrentConversation() {
|
||||
if (conversationUser != null) {
|
||||
if (!conversationUser.hasSpreedFeatureCapability("no-ping") && !TextUtils.isEmpty(roomId)) {
|
||||
NotificationUtils.cancelExistingNotificationsForRoom(applicationContext,
|
||||
conversationUser, roomId)
|
||||
NotificationUtils.cancelExistingNotificationsForRoom(
|
||||
applicationContext,
|
||||
conversationUser, roomId
|
||||
)
|
||||
} else if (!TextUtils.isEmpty(roomToken)) {
|
||||
NotificationUtils.cancelExistingNotificationsForRoom(applicationContext,
|
||||
conversationUser, roomToken!!)
|
||||
NotificationUtils.cancelExistingNotificationsForRoom(
|
||||
applicationContext,
|
||||
conversationUser, roomToken!!
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -775,8 +870,12 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
||||
activity?.findViewById<View>(R.id.toolbar)?.setOnClickListener(null)
|
||||
}
|
||||
|
||||
if (conversationUser != null && conversationUser?.hasSpreedFeatureCapability("no-ping")
|
||||
&& activity != null && !activity?.isChangingConfigurations!! && !isLeavingForConversation) {
|
||||
if (conversationUser != null &&
|
||||
conversationUser.hasSpreedFeatureCapability("no-ping") &&
|
||||
activity != null &&
|
||||
!activity?.isChangingConfigurations!! &&
|
||||
!isLeavingForConversation
|
||||
) {
|
||||
wasDetached = true
|
||||
leaveRoom()
|
||||
}
|
||||
@ -819,8 +918,13 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
||||
|
||||
private fun startPing() {
|
||||
if (conversationUser != null && !conversationUser.hasSpreedFeatureCapability("no-ping")) {
|
||||
ncApi?.pingCall(credentials, ApiUtils.getUrlForCallPing(conversationUser.baseUrl,
|
||||
roomToken))
|
||||
ncApi?.pingCall(
|
||||
credentials,
|
||||
ApiUtils.getUrlForCallPing(
|
||||
conversationUser.baseUrl,
|
||||
roomToken
|
||||
)
|
||||
)
|
||||
?.subscribeOn(Schedulers.io())
|
||||
?.observeOn(AndroidSchedulers.mainThread())
|
||||
?.repeatWhen { observable -> observable.delay(5000, TimeUnit.MILLISECONDS) }
|
||||
@ -832,7 +936,6 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
||||
}
|
||||
|
||||
override fun onNext(genericOverall: GenericOverall) {
|
||||
|
||||
}
|
||||
|
||||
override fun onError(e: Throwable) {}
|
||||
@ -850,9 +953,12 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
||||
private fun joinRoomWithPassword() {
|
||||
|
||||
if (currentConversation == null || TextUtils.isEmpty(currentConversation?.sessionId) ||
|
||||
currentConversation?.sessionId == "0") {
|
||||
ncApi?.joinRoom(credentials,
|
||||
ApiUtils.getUrlForSettingMyselfAsActiveParticipant(conversationUser?.baseUrl, roomToken), roomPassword)
|
||||
currentConversation?.sessionId == "0"
|
||||
) {
|
||||
ncApi?.joinRoom(
|
||||
credentials,
|
||||
ApiUtils.getUrlForSettingMyselfAsActiveParticipant(conversationUser?.baseUrl, roomToken), roomPassword
|
||||
)
|
||||
?.subscribeOn(Schedulers.io())
|
||||
?.observeOn(AndroidSchedulers.mainThread())
|
||||
?.retry(3)
|
||||
@ -879,7 +985,10 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
||||
}
|
||||
|
||||
if (magicWebSocketInstance != null) {
|
||||
magicWebSocketInstance?.joinRoomWithRoomTokenAndSession(roomToken, currentConversation?.sessionId)
|
||||
magicWebSocketInstance?.joinRoomWithRoomTokenAndSession(
|
||||
roomToken,
|
||||
currentConversation?.sessionId
|
||||
)
|
||||
}
|
||||
if (startCallFromNotification != null && startCallFromNotification ?: false) {
|
||||
startCallFromNotification = false
|
||||
@ -888,19 +997,19 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
||||
}
|
||||
|
||||
override fun onError(e: Throwable) {
|
||||
|
||||
}
|
||||
|
||||
override fun onComplete() {
|
||||
|
||||
}
|
||||
})
|
||||
} else {
|
||||
inConversation = true
|
||||
ApplicationWideCurrentRoomHolder.getInstance().session = currentConversation?.sessionId
|
||||
if (magicWebSocketInstance != null) {
|
||||
magicWebSocketInstance?.joinRoomWithRoomTokenAndSession(roomToken,
|
||||
currentConversation?.sessionId)
|
||||
magicWebSocketInstance?.joinRoomWithRoomTokenAndSession(
|
||||
roomToken,
|
||||
currentConversation?.sessionId
|
||||
)
|
||||
}
|
||||
startPing()
|
||||
if (isFirstMessagesProcessing) {
|
||||
@ -912,9 +1021,13 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
||||
}
|
||||
|
||||
private fun leaveRoom() {
|
||||
ncApi?.leaveRoom(credentials,
|
||||
ApiUtils.getUrlForSettingMyselfAsActiveParticipant(conversationUser?.baseUrl,
|
||||
roomToken))
|
||||
ncApi?.leaveRoom(
|
||||
credentials,
|
||||
ApiUtils.getUrlForSettingMyselfAsActiveParticipant(
|
||||
conversationUser?.baseUrl,
|
||||
roomToken
|
||||
)
|
||||
)
|
||||
?.subscribeOn(Schedulers.io())
|
||||
?.observeOn(AndroidSchedulers.mainThread())
|
||||
?.subscribe(object : Observer<GenericOverall> {
|
||||
@ -930,8 +1043,10 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
||||
}
|
||||
|
||||
if (magicWebSocketInstance != null && currentConversation != null) {
|
||||
magicWebSocketInstance?.joinRoomWithRoomTokenAndSession("",
|
||||
currentConversation?.sessionId)
|
||||
magicWebSocketInstance?.joinRoomWithRoomTokenAndSession(
|
||||
"",
|
||||
currentConversation?.sessionId
|
||||
)
|
||||
}
|
||||
|
||||
if (!isDestroyed && !isBeingDestroyed && !wasDetached) {
|
||||
@ -957,14 +1072,15 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
||||
} catch (e: IllegalAccessException) {
|
||||
Log.w(TAG, "Failed to access and set field")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun submitMessage() {
|
||||
if (messageInput != null) {
|
||||
val editable = messageInput!!.editableText
|
||||
val mentionSpans = editable.getSpans(0, editable.length,
|
||||
Spans.MentionChipSpan::class.java)
|
||||
val mentionSpans = editable.getSpans(
|
||||
0, editable.length,
|
||||
Spans.MentionChipSpan::class.java
|
||||
)
|
||||
var mentionSpan: Spans.MentionChipSpan
|
||||
for (i in mentionSpans.indices) {
|
||||
mentionSpan = mentionSpans[i]
|
||||
@ -977,7 +1093,10 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
||||
|
||||
messageInput?.setText("")
|
||||
val replyMessageId: Int? = view?.findViewById<RelativeLayout>(R.id.quotedChatMessageView)?.tag as Int?
|
||||
sendMessage(editable, if (view?.findViewById<RelativeLayout>(R.id.quotedChatMessageView)?.visibility == View.VISIBLE) replyMessageId else null)
|
||||
sendMessage(
|
||||
editable,
|
||||
if (view?.findViewById<RelativeLayout>(R.id.quotedChatMessageView)?.visibility == View.VISIBLE) replyMessageId else null
|
||||
)
|
||||
cancelReply()
|
||||
}
|
||||
}
|
||||
@ -996,7 +1115,6 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
||||
?.observeOn(AndroidSchedulers.mainThread())
|
||||
?.subscribe(object : Observer<GenericOverall> {
|
||||
override fun onSubscribe(d: Disposable) {
|
||||
|
||||
}
|
||||
|
||||
override fun onNext(genericOverall: GenericOverall) {
|
||||
@ -1025,7 +1143,6 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
||||
}
|
||||
|
||||
override fun onComplete() {
|
||||
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -1034,7 +1151,8 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
||||
private fun setupWebsocket() {
|
||||
if (conversationUser != null) {
|
||||
if (WebSocketConnectionHelper.getMagicWebSocketInstanceForUserId(conversationUser.id) != null) {
|
||||
magicWebSocketInstance = WebSocketConnectionHelper.getMagicWebSocketInstanceForUserId(conversationUser.id)
|
||||
magicWebSocketInstance =
|
||||
WebSocketConnectionHelper.getMagicWebSocketInstanceForUserId(conversationUser.id)
|
||||
} else {
|
||||
magicWebSocketInstance = null
|
||||
}
|
||||
@ -1090,8 +1208,10 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
||||
if (!wasDetached) {
|
||||
if (lookIntoFuture > 0) {
|
||||
val finalTimeout = timeout
|
||||
ncApi?.pullChatMessages(credentials,
|
||||
ApiUtils.getUrlForChat(conversationUser?.baseUrl, roomToken), fieldMap)
|
||||
ncApi?.pullChatMessages(
|
||||
credentials,
|
||||
ApiUtils.getUrlForChat(conversationUser?.baseUrl, roomToken), fieldMap
|
||||
)
|
||||
?.subscribeOn(Schedulers.io())
|
||||
?.observeOn(AndroidSchedulers.mainThread())
|
||||
?.takeWhile { observable -> inConversation && !wasDetached }
|
||||
@ -1114,13 +1234,13 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
||||
}
|
||||
|
||||
override fun onComplete() {
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
} else {
|
||||
ncApi?.pullChatMessages(credentials,
|
||||
ApiUtils.getUrlForChat(conversationUser?.baseUrl, roomToken), fieldMap)
|
||||
ncApi?.pullChatMessages(
|
||||
credentials,
|
||||
ApiUtils.getUrlForChat(conversationUser?.baseUrl, roomToken), fieldMap
|
||||
)
|
||||
?.subscribeOn(Schedulers.io())
|
||||
?.observeOn(AndroidSchedulers.mainThread())
|
||||
?.takeWhile { observable -> inConversation && !wasDetached }
|
||||
@ -1141,7 +1261,6 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
||||
}
|
||||
|
||||
override fun onComplete() {
|
||||
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -1180,7 +1299,6 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
||||
loadingProgressBar?.visibility = View.GONE
|
||||
|
||||
messagesListView?.visibility = View.VISIBLE
|
||||
|
||||
}
|
||||
|
||||
var countGroupedMessages = 0
|
||||
@ -1191,9 +1309,12 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
||||
if (TextUtils.isEmpty(chatMessageList[i].systemMessage) &&
|
||||
TextUtils.isEmpty(chatMessageList[i + 1].systemMessage) &&
|
||||
chatMessageList[i + 1].actorId == chatMessageList[i].actorId &&
|
||||
countGroupedMessages < 4 && DateFormatter.isSameDay(chatMessageList[i].createdAt,
|
||||
chatMessageList[i + 1].createdAt)) {
|
||||
chatMessageList[i].isGrouped = true;
|
||||
countGroupedMessages < 4 && DateFormatter.isSameDay(
|
||||
chatMessageList[i].createdAt,
|
||||
chatMessageList[i + 1].createdAt
|
||||
)
|
||||
) {
|
||||
chatMessageList[i].isGrouped = true
|
||||
countGroupedMessages++
|
||||
} else {
|
||||
countGroupedMessages = 0
|
||||
@ -1201,7 +1322,8 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
||||
}
|
||||
|
||||
val chatMessage = chatMessageList[i]
|
||||
chatMessage.isOneToOneConversation = currentConversation?.type == Conversation.ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL
|
||||
chatMessage.isOneToOneConversation =
|
||||
currentConversation?.type == Conversation.ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL
|
||||
chatMessage.isLinkPreviewAllowed = isLinkPreviewAllowed
|
||||
chatMessage.activeUser = conversationUser
|
||||
}
|
||||
@ -1209,7 +1331,6 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
||||
if (adapter != null) {
|
||||
adapter?.addToEnd(chatMessageList, false)
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
var chatMessage: ChatMessage
|
||||
@ -1225,7 +1346,8 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
||||
adapter?.addToStart(unreadChatMessage, false)
|
||||
}
|
||||
|
||||
val isThereANewNotice = shouldAddNewMessagesNotice || adapter?.getMessagePositionByIdInReverse("-1") != -1
|
||||
val isThereANewNotice =
|
||||
shouldAddNewMessagesNotice || adapter?.getMessagePositionByIdInReverse("-1") != -1
|
||||
|
||||
for (i in chatMessageList.indices) {
|
||||
chatMessage = chatMessageList[i]
|
||||
@ -1241,7 +1363,8 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
||||
}
|
||||
}
|
||||
|
||||
val shouldScroll = !isThereANewNotice && !shouldAddNewMessagesNotice && layoutManager?.findFirstVisibleItemPosition() == 0 || adapter != null && adapter?.itemCount == 0
|
||||
val shouldScroll =
|
||||
!isThereANewNotice && !shouldAddNewMessagesNotice && layoutManager?.findFirstVisibleItemPosition() == 0 || adapter != null && adapter?.itemCount == 0
|
||||
|
||||
if (!shouldAddNewMessagesNotice && !shouldScroll && popupBubble != null) {
|
||||
if (!popupBubble!!.isShown) {
|
||||
@ -1255,18 +1378,24 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
||||
}
|
||||
|
||||
if (adapter != null) {
|
||||
chatMessage.isGrouped = (adapter!!.isPreviousSameAuthor(chatMessage
|
||||
.actorId, -1) && adapter!!.getSameAuthorLastMessagesCount(chatMessage.actorId) % 5 > 0)
|
||||
chatMessage.isOneToOneConversation = (currentConversation?.type == Conversation.ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL)
|
||||
chatMessage.isGrouped = (
|
||||
adapter!!.isPreviousSameAuthor(
|
||||
chatMessage.actorId,
|
||||
-1
|
||||
) && adapter!!.getSameAuthorLastMessagesCount(chatMessage.actorId) % 5 > 0
|
||||
)
|
||||
chatMessage.isOneToOneConversation =
|
||||
(currentConversation?.type == Conversation.ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL)
|
||||
adapter?.addToStart(chatMessage, shouldScroll)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (shouldAddNewMessagesNotice && adapter != null && messagesListView != null) {
|
||||
layoutManager?.scrollToPositionWithOffset(adapter!!.getMessagePositionByIdInReverse("-1"), messagesListView!!.height / 2)
|
||||
layoutManager?.scrollToPositionWithOffset(
|
||||
adapter!!.getMessagePositionByIdInReverse("-1"),
|
||||
messagesListView!!.height / 2
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// update read status of all messages
|
||||
@ -1310,7 +1439,6 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun format(date: Date): String {
|
||||
return if (DateFormatter.isToday(date)) {
|
||||
resources!!.getString(R.string.nc_date_header_today)
|
||||
@ -1344,7 +1472,6 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
when (item.itemId) {
|
||||
android.R.id.home -> {
|
||||
@ -1397,7 +1524,6 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
||||
.SystemMessageType.PARENT_MESSAGE_DELETED
|
||||
}
|
||||
|
||||
|
||||
private fun startACall(isVoiceOnlyCall: Boolean) {
|
||||
isLeavingForConversation = true
|
||||
val callIntent = getIntentForCall(isVoiceOnlyCall)
|
||||
@ -1440,7 +1566,11 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
||||
}
|
||||
|
||||
override fun onMessageViewLongClick(view: View?, message: IMessage?) {
|
||||
PopupMenu(this.context, view, if (message?.user?.id == conversationUser?.userId) Gravity.END else Gravity.START).apply {
|
||||
PopupMenu(
|
||||
this.context,
|
||||
view,
|
||||
if (message?.user?.id == conversationUser?.userId) Gravity.END else Gravity.START
|
||||
).apply {
|
||||
setOnMenuItemClickListener { item ->
|
||||
when (item?.itemId) {
|
||||
|
||||
@ -1456,28 +1586,40 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
||||
chatMessage?.let {
|
||||
messageInputView?.findViewById<ImageButton>(R.id.attachmentButton)?.visibility = View.GONE
|
||||
messageInputView?.findViewById<Space>(R.id.attachmentButtonSpace)?.visibility = View.GONE
|
||||
messageInputView?.findViewById<ImageButton>(R.id.cancelReplyButton)?.visibility = View.VISIBLE
|
||||
messageInputView?.findViewById<ImageButton>(R.id.cancelReplyButton)?.visibility =
|
||||
View.VISIBLE
|
||||
messageInputView?.findViewById<EmojiTextView>(R.id.quotedMessage)?.maxLines = 2
|
||||
messageInputView?.findViewById<EmojiTextView>(R.id.quotedMessage)?.ellipsize = TextUtils.TruncateAt.END
|
||||
messageInputView?.findViewById<EmojiTextView>(R.id.quotedMessage)?.ellipsize =
|
||||
TextUtils.TruncateAt.END
|
||||
messageInputView?.findViewById<EmojiTextView>(R.id.quotedMessage)?.text = it.text
|
||||
messageInputView?.findViewById<EmojiTextView>(R.id.quotedMessageAuthor)?.text = it.actorDisplayName
|
||||
?: context!!.getText(R.string.nc_nick_guest)
|
||||
messageInputView?.findViewById<EmojiTextView>(R.id.quotedMessageAuthor)?.text =
|
||||
it.actorDisplayName ?: context!!.getText(R.string.nc_nick_guest)
|
||||
|
||||
conversationUser?.let { currentUser ->
|
||||
|
||||
chatMessage.imageUrl?.let { previewImageUrl ->
|
||||
messageInputView?.findViewById<ImageView>(R.id.quotedMessageImage)?.visibility = View.VISIBLE
|
||||
messageInputView?.findViewById<ImageView>(R.id.quotedMessageImage)?.visibility =
|
||||
View.VISIBLE
|
||||
|
||||
val px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 96f, resources?.displayMetrics)
|
||||
messageInputView?.findViewById<ImageView>(R.id.quotedMessageImage)?.maxHeight = px.toInt()
|
||||
val layoutParams = messageInputView?.findViewById<ImageView>(R.id.quotedMessageImage)?.layoutParams as FlexboxLayout.LayoutParams
|
||||
val px = TypedValue.applyDimension(
|
||||
TypedValue.COMPLEX_UNIT_DIP,
|
||||
96f,
|
||||
resources?.displayMetrics
|
||||
)
|
||||
messageInputView?.findViewById<ImageView>(R.id.quotedMessageImage)?.maxHeight =
|
||||
px.toInt()
|
||||
val layoutParams =
|
||||
messageInputView?.findViewById<ImageView>(R.id.quotedMessageImage)?.layoutParams as FlexboxLayout.LayoutParams
|
||||
layoutParams.flexGrow = 0f
|
||||
messageInputView?.findViewById<ImageView>(R.id.quotedMessageImage)?.layoutParams = layoutParams
|
||||
messageInputView?.findViewById<ImageView>(R.id.quotedMessageImage)?.load(previewImageUrl) {
|
||||
messageInputView?.findViewById<ImageView>(R.id.quotedMessageImage)?.layoutParams =
|
||||
layoutParams
|
||||
messageInputView?.findViewById<ImageView>(R.id.quotedMessageImage)
|
||||
?.load(previewImageUrl) {
|
||||
addHeader("Authorization", credentials!!)
|
||||
}
|
||||
} ?: run {
|
||||
messageInputView?.findViewById<ImageView>(R.id.quotedMessageImage)?.visibility = View.GONE
|
||||
messageInputView?.findViewById<ImageView>(R.id.quotedMessageImage)?.visibility =
|
||||
View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
@ -1498,14 +1640,20 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
||||
|
||||
override fun onNext(t: ChatOverallSingleMessage) {
|
||||
if (t.ocs.meta.statusCode == HttpURLConnection.HTTP_ACCEPTED) {
|
||||
Toast.makeText(context, R.string.nc_delete_message_leaked_to_matterbridge,
|
||||
Toast.LENGTH_LONG).show()
|
||||
Toast.makeText(
|
||||
context, R.string.nc_delete_message_leaked_to_matterbridge,
|
||||
Toast.LENGTH_LONG
|
||||
).show()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onError(e: Throwable) {
|
||||
Log.e(TAG, "Something went wrong when trying to delete message with id " +
|
||||
message?.id, e)
|
||||
Log.e(
|
||||
TAG,
|
||||
"Something went wrong when trying to delete message with id " +
|
||||
message?.id,
|
||||
e
|
||||
)
|
||||
Toast.makeText(context, R.string.nc_common_error_sorry, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
|
||||
@ -1531,7 +1679,8 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
||||
val messageTemp = message as ChatMessage
|
||||
messageTemp.isDeleted = true
|
||||
|
||||
messageTemp.isOneToOneConversation = currentConversation?.type == Conversation.ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL
|
||||
messageTemp.isOneToOneConversation =
|
||||
currentConversation?.type == Conversation.ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL
|
||||
messageTemp.isLinkPreviewAllowed = isLinkPreviewAllowed
|
||||
messageTemp.activeUser = conversationUser
|
||||
|
||||
@ -1561,7 +1710,6 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
override fun hasContentFor(message: IMessage, type: Byte): Boolean {
|
||||
when (type) {
|
||||
CONTENT_TYPE_SYSTEM_MESSAGE -> return !TextUtils.isEmpty(message.systemMessage)
|
||||
@ -1589,19 +1737,22 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.BACKGROUND)
|
||||
fun onMessageEvent(userMentionClickEvent: UserMentionClickEvent) {
|
||||
if (currentConversation?.type != Conversation.ConversationType
|
||||
.ROOM_TYPE_ONE_TO_ONE_CALL || currentConversation?.name !=
|
||||
userMentionClickEvent.userId) {
|
||||
val retrofitBucket = ApiUtils.getRetrofitBucketForCreateRoom(conversationUser?.baseUrl, "1",
|
||||
userMentionClickEvent.userId, null)
|
||||
if (currentConversation?.type != Conversation.ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL ||
|
||||
currentConversation?.name != userMentionClickEvent.userId
|
||||
) {
|
||||
val retrofitBucket = ApiUtils.getRetrofitBucketForCreateRoom(
|
||||
conversationUser?.baseUrl, "1",
|
||||
userMentionClickEvent.userId, null
|
||||
)
|
||||
|
||||
ncApi?.createRoom(credentials,
|
||||
retrofitBucket.url, retrofitBucket.queryMap)
|
||||
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) {
|
||||
@ -1613,27 +1764,32 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
||||
|
||||
if (conversationUser != null) {
|
||||
if (conversationUser.hasSpreedFeatureCapability("chat-v2")) {
|
||||
bundle.putParcelable(BundleKeys.KEY_ACTIVE_CONVERSATION,
|
||||
Parcels.wrap(roomOverall.ocs.data))
|
||||
bundle.putParcelable(
|
||||
BundleKeys.KEY_ACTIVE_CONVERSATION,
|
||||
Parcels.wrap(roomOverall.ocs.data)
|
||||
)
|
||||
conversationIntent.putExtras(bundle)
|
||||
|
||||
ConductorRemapping.remapChatController(router, conversationUser.id,
|
||||
roomOverall.ocs.data.token, bundle, false)
|
||||
ConductorRemapping.remapChatController(
|
||||
router, conversationUser.id,
|
||||
roomOverall.ocs.data.token, bundle, false
|
||||
)
|
||||
}
|
||||
|
||||
} else {
|
||||
conversationIntent.putExtras(bundle)
|
||||
startActivity(conversationIntent)
|
||||
Handler().postDelayed({
|
||||
Handler().postDelayed(
|
||||
{
|
||||
if (!isDestroyed && !isBeingDestroyed) {
|
||||
router.popCurrentController()
|
||||
}
|
||||
}, 100)
|
||||
},
|
||||
100
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onError(e: Throwable) {
|
||||
|
||||
}
|
||||
|
||||
override fun onComplete() {}
|
||||
|
@ -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,12 +226,17 @@ 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
|
||||
|
||||
@ -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 = { _,
|
||||
dateTimePicker(
|
||||
minDateTime = Calendar.getInstance(),
|
||||
requireFutureDateTime =
|
||||
true,
|
||||
currentDateTime = currentTimeCalendar,
|
||||
dateTimeCallback = { _,
|
||||
dateTime ->
|
||||
reconfigureLobbyTimerView(dateTime)
|
||||
submitLobbyChanges()
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -269,11 +298,19 @@ 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)
|
||||
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> {
|
||||
@ -288,7 +325,6 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
|
||||
|
||||
override fun onError(e: Throwable) {
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
@ -314,8 +350,12 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
|
||||
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))
|
||||
.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)
|
||||
@ -397,7 +437,10 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
|
||||
}
|
||||
|
||||
private fun getListOfParticipants() {
|
||||
ncApi.getPeersForCall(credentials, ApiUtils.getUrlForParticipants(conversationUser!!.baseUrl, conversationToken))
|
||||
ncApi.getPeersForCall(
|
||||
credentials,
|
||||
ApiUtils.getUrlForParticipants(conversationUser!!.baseUrl, conversationToken)
|
||||
)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : Observer<ParticipantsOverall> {
|
||||
@ -410,14 +453,12 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
@ -518,7 +574,6 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
|
||||
|
||||
conversationDisplayName.text = conversation!!.displayName
|
||||
|
||||
|
||||
loadConversationAvatar()
|
||||
adjustNotificationLevelUI()
|
||||
|
||||
@ -527,7 +582,6 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
|
||||
}
|
||||
|
||||
override fun onError(e: Throwable) {
|
||||
|
||||
}
|
||||
|
||||
override fun onComplete() {
|
||||
@ -543,7 +597,8 @@ 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)) {
|
||||
val stringValue: String =
|
||||
when (EnumNotificationLevelConverter().convertToInt(conversation!!.notificationLevel)) {
|
||||
1 -> "always"
|
||||
2 -> "mention"
|
||||
3 -> "never"
|
||||
@ -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))
|
||||
.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_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,14 +710,22 @@ 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)
|
||||
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)
|
||||
ncApi.promoteUserToModerator(
|
||||
credentials,
|
||||
ApiUtils.getUrlForModerators(conversationUser.baseUrl, conversation!!.token),
|
||||
participant.userId
|
||||
)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe {
|
||||
@ -655,16 +734,32 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
|
||||
}
|
||||
} 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)
|
||||
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)
|
||||
ncApi.removeParticipantFromConversation(
|
||||
credentials,
|
||||
ApiUtils.getUrlForRemovingParticipantFromConversation(
|
||||
conversationUser.baseUrl,
|
||||
conversation!!.token,
|
||||
false
|
||||
),
|
||||
participant.userId
|
||||
)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe {
|
||||
@ -678,7 +773,7 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return true
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
@ -53,5 +53,4 @@ abstract class ButterKnifeController : Controller {
|
||||
unbinder!!.unbind()
|
||||
unbinder = null
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -30,7 +30,8 @@ interface ListItemWithImage {
|
||||
|
||||
data class BasicListItemWithImage(
|
||||
@DrawableRes val iconRes: Int,
|
||||
override val title: String) : ListItemWithImage {
|
||||
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 {
|
||||
private val adapter: ListIconDialogAdapter<*>
|
||||
) : RecyclerView.ViewHolder(itemView), View.OnClickListener {
|
||||
init {
|
||||
itemView.setOnClickListener(this)
|
||||
}
|
||||
@ -57,7 +56,8 @@ internal class ListIconDialogAdapter<IT : ListItemWithImage>(
|
||||
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 selection: ListItemListener<IT>
|
||||
) : RecyclerView.Adapter<ListItemViewHolder>(), DialogAdapter<IT, ListItemListener<IT>> {
|
||||
|
||||
private var disabledIndices: IntArray = disabledItems ?: IntArray(0)
|
||||
|
||||
@ -82,7 +82,8 @@ internal class ListIconDialogAdapter<IT : ListItemWithImage>(
|
||||
|
||||
override fun onCreateViewHolder(
|
||||
parent: ViewGroup,
|
||||
viewType: Int): ListItemViewHolder {
|
||||
viewType: Int
|
||||
): ListItemViewHolder {
|
||||
val listItemView: View = parent.inflate(dialog.windowContext, R.layout.menu_item_sheet)
|
||||
val viewHolder = ListItemViewHolder(
|
||||
itemView = listItemView,
|
||||
@ -96,7 +97,8 @@ internal class ListIconDialogAdapter<IT : ListItemWithImage>(
|
||||
|
||||
override fun onBindViewHolder(
|
||||
holder: ListItemViewHolder,
|
||||
position: Int) {
|
||||
position: Int
|
||||
) {
|
||||
holder.itemView.isEnabled = !disabledIndices.contains(position)
|
||||
val currentItem = items[position]
|
||||
|
||||
@ -122,7 +124,8 @@ internal class ListIconDialogAdapter<IT : ListItemWithImage>(
|
||||
|
||||
override fun replaceItems(
|
||||
items: List<IT>,
|
||||
listener: ListItemListener<IT>) {
|
||||
listener: ListItemListener<IT>
|
||||
) {
|
||||
this.items = items
|
||||
if (listener != null) {
|
||||
this.selection = listener
|
||||
|
@ -30,11 +30,13 @@ import com.afollestad.materialdialogs.list.getListAdapter
|
||||
typealias ListItemListener<IT> =
|
||||
((dialog: MaterialDialog, index: Int, item: IT) -> Unit)?
|
||||
|
||||
@CheckResult fun <IT : ListItemWithImage> MaterialDialog.listItemsWithImage(
|
||||
@CheckResult
|
||||
fun <IT : ListItemWithImage> MaterialDialog.listItemsWithImage(
|
||||
items: List<IT>,
|
||||
disabledIndices: IntArray? = null,
|
||||
waitForPositiveButton: Boolean = true,
|
||||
selection: ListItemListener<IT> = null): MaterialDialog {
|
||||
selection: ListItemListener<IT> = null
|
||||
): MaterialDialog {
|
||||
|
||||
if (getListAdapter() != null) {
|
||||
return updateListItemsWithImage(
|
||||
@ -58,7 +60,8 @@ typealias ListItemListener<IT> =
|
||||
|
||||
fun MaterialDialog.updateListItemsWithImage(
|
||||
items: List<ListItemWithImage>,
|
||||
disabledIndices: IntArray? = null): MaterialDialog {
|
||||
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,7 +58,6 @@ import okhttp3.MediaType
|
||||
import okhttp3.RequestBody
|
||||
import javax.inject.Inject
|
||||
|
||||
|
||||
@AutoInjector(NextcloudTalkApplication::class)
|
||||
class ContactAddressBookWorker(val context: Context, workerParameters: WorkerParameters) :
|
||||
Worker(context, workerParameters) {
|
||||
@ -119,7 +122,8 @@ class ContactAddressBookWorker(val context: Context, workerParameters: WorkerPar
|
||||
ncApi.searchContactsByPhoneNumber(
|
||||
ApiUtils.getCredentials(currentUser.username, currentUser.token),
|
||||
ApiUtils.getUrlForSearchByNumber(currentUser.baseUrl),
|
||||
RequestBody.create(MediaType.parse("application/json"), json))
|
||||
RequestBody.create(MediaType.parse("application/json"), json)
|
||||
)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : Observer<ContactsByNumberOverall> {
|
||||
@ -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()
|
||||
}
|
||||
@ -183,8 +188,11 @@ class ContactAddressBookWorker(val context: Context, workerParameters: WorkerPar
|
||||
.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)
|
||||
val count = context.contentResolver.delete(
|
||||
rawContactUri,
|
||||
ContactsContract.RawContacts.CONTACT_ID + " " + "LIKE \"" + id + "\"",
|
||||
null
|
||||
)
|
||||
Log.d(TAG, "deleted $count linked accounts for id $id")
|
||||
}
|
||||
|
||||
@ -193,7 +201,10 @@ class ContactAddressBookWorker(val context: Context, workerParameters: WorkerPar
|
||||
.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")
|
||||
.appendQueryParameter(
|
||||
ContactsContract.Data.MIMETYPE,
|
||||
"vnd.android.cursor.item/vnd.com.nextcloud.talk2.chat"
|
||||
)
|
||||
.build()
|
||||
|
||||
val rawContactsCursor = context.contentResolver.query(
|
||||
@ -207,10 +218,15 @@ class ContactAddressBookWorker(val context: Context, workerParameters: WorkerPar
|
||||
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)
|
||||
}
|
||||
}
|
||||
@ -224,7 +240,8 @@ class ContactAddressBookWorker(val context: Context, workerParameters: WorkerPar
|
||||
private fun createLinkedAccounts(contactsWithAssociatedPhoneNumbers: Map<String, String>?) {
|
||||
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
|
||||
@ -232,7 +249,10 @@ class ContactAddressBookWorker(val context: Context, workerParameters: WorkerPar
|
||||
.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")
|
||||
.appendQueryParameter(
|
||||
ContactsContract.Data.MIMETYPE,
|
||||
"vnd.android.cursor.item/vnd.com.nextcloud.talk2.chat"
|
||||
)
|
||||
.build()
|
||||
|
||||
val rawContactsCursor = context.contentResolver.query(
|
||||
@ -263,7 +283,8 @@ class ContactAddressBookWorker(val context: Context, workerParameters: WorkerPar
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null)
|
||||
null
|
||||
)
|
||||
|
||||
if (contactCursor != null) {
|
||||
if (contactCursor.count > 0) {
|
||||
@ -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()
|
||||
}
|
||||
@ -342,17 +392,20 @@ 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 + " = ?"
|
||||
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.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()
|
||||
}
|
||||
@ -366,7 +419,8 @@ class ContactAddressBookWorker(val context: Context, workerParameters: WorkerPar
|
||||
null,
|
||||
ContactsContract.Data.CONTACT_ID + " = " + id,
|
||||
null,
|
||||
null)
|
||||
null
|
||||
)
|
||||
|
||||
if (phonesNumbersCursor != null) {
|
||||
while (phonesNumbersCursor.moveToNext()) {
|
||||
@ -398,32 +452,51 @@ 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)
|
||||
.enqueue(
|
||||
OneTimeWorkRequest.Builder(ContactAddressBookWorker::class.java)
|
||||
.setInputData(Data.Builder().putBoolean(KEY_FORCE, false).build())
|
||||
.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)
|
||||
.enqueue(
|
||||
OneTimeWorkRequest.Builder(ContactAddressBookWorker::class.java)
|
||||
.setInputData(Data.Builder().putBoolean(KEY_FORCE, true).build())
|
||||
.build())
|
||||
.build()
|
||||
)
|
||||
return true
|
||||
}
|
||||
}
|
||||
@ -431,9 +504,11 @@ class ContactAddressBookWorker(val context: Context, workerParameters: WorkerPar
|
||||
fun deleteAll() {
|
||||
WorkManager
|
||||
.getInstance()
|
||||
.enqueue(OneTimeWorkRequest.Builder(ContactAddressBookWorker::class.java)
|
||||
.enqueue(
|
||||
OneTimeWorkRequest.Builder(ContactAddressBookWorker::class.java)
|
||||
.setInputData(Data.Builder().putBoolean(DELETE_ALL, true).build())
|
||||
.build())
|
||||
.build()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -33,10 +33,13 @@ 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) {
|
||||
@ -87,7 +90,8 @@ 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)
|
||||
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,10 +50,9 @@ 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) {
|
||||
@ -107,8 +110,14 @@ 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),
|
||||
|
@ -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)
|
||||
|
@ -30,11 +30,12 @@ import com.nextcloud.talk.R
|
||||
import com.nextcloud.talk.controllers.ProfileController
|
||||
import com.nextcloud.talk.models.json.userprofile.Scope
|
||||
|
||||
|
||||
class ScopeDialog(con: Context,
|
||||
class ScopeDialog(
|
||||
con: Context,
|
||||
private val userInfoAdapter: ProfileController.UserInfoAdapter,
|
||||
private val field: ProfileController.Field,
|
||||
private val position: Int) :
|
||||
private val position: Int
|
||||
) :
|
||||
BottomSheetDialog(con) {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
@ -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?,
|
||||
fun findNotificationForRoom(
|
||||
context: Context?,
|
||||
conversationUser: UserEntity,
|
||||
roomTokenOrId: String): StatusBarNotification? {
|
||||
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
|
||||
|
||||
@ -95,14 +101,14 @@ class SSLSocketFactoryCompat(keyManager: KeyManager?,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
init {
|
||||
try {
|
||||
val sslContext = SSLContext.getInstance("TLS")
|
||||
sslContext.init(
|
||||
if (keyManager != null) arrayOf(keyManager) else null,
|
||||
arrayOf(trustManager),
|
||||
null)
|
||||
null
|
||||
)
|
||||
delegate = sslContext.socketFactory
|
||||
} catch (e: GeneralSecurityException) {
|
||||
throw IllegalStateException() // system has no TLS
|
||||
@ -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