@@ -16,19 +16,17 @@ import android.graphics.Bitmap
16
16
import android.graphics.BitmapFactory
17
17
import android.net.Uri
18
18
import android.os.Bundle
19
- import android.os.Environment
20
19
import android.provider.MediaStore
21
20
import android.text.Editable
22
21
import android.text.TextWatcher
23
22
import android.util.Log
24
- import android.util.Patterns
25
- import android.util.TypedValue
26
23
import android.view.LayoutInflater
27
24
import android.view.View
28
25
import android.view.ViewGroup
29
26
import android.view.inputmethod.InputMethodManager
30
27
import android.widget.Toast
31
28
import androidx.appcompat.app.AlertDialog
29
+ import androidx.compose.ui.text.capitalize
32
30
import androidx.core.app.ActivityCompat
33
31
import androidx.core.content.ContextCompat
34
32
import androidx.core.content.FileProvider
@@ -59,6 +57,7 @@ import com.ncs.o2.Domain.Utility.ExtensionsUtil.appendTextAtCursor
59
57
import com.ncs.o2.Domain.Utility.ExtensionsUtil.appendTextAtCursorMiddleCursor
60
58
import com.ncs.o2.Domain.Utility.ExtensionsUtil.gone
61
59
import com.ncs.o2.Domain.Utility.ExtensionsUtil.isNull
60
+ import com.ncs.o2.Domain.Utility.ExtensionsUtil.load
62
61
import com.ncs.o2.Domain.Utility.ExtensionsUtil.performHapticFeedback
63
62
import com.ncs.o2.Domain.Utility.ExtensionsUtil.setOnClickThrottleBounceListener
64
63
import com.ncs.o2.Domain.Utility.ExtensionsUtil.slideDownAndGone
@@ -102,11 +101,12 @@ import kotlinx.coroutines.CoroutineScope
102
101
import kotlinx.coroutines.Dispatchers
103
102
import kotlinx.coroutines.launch
104
103
import kotlinx.coroutines.withContext
104
+ import org.jsoup.Jsoup
105
105
import timber.log.Timber
106
106
import java.io.File
107
+ import java.io.IOException
107
108
import java.io.InputStream
108
109
import java.util.concurrent.Executors
109
- import java.util.regex.Matcher
110
110
import javax.inject.Inject
111
111
112
112
@@ -144,6 +144,7 @@ class TaskChatFragment : Fragment(), ChatAdapter.onChatDoubleClickListner,
144
144
private val CAMERA_PERMISSION_CODE = 101
145
145
private var currentPhotoPath: String? = null
146
146
private var replyingTo: String? = null
147
+ private val data: Metadata ? = null
147
148
148
149
149
150
var contributors: MutableList <String > = mutableListOf ()
@@ -214,6 +215,12 @@ class TaskChatFragment : Fragment(), ChatAdapter.onChatDoubleClickListner,
214
215
override fun afterTextChanged (s : Editable ? ) {
215
216
val input = s.toString()
216
217
218
+ // val links = extractLinks(input)
219
+ // processLinks(links)
220
+ // if (links.isEmpty() || links=="") {
221
+ // processLinks("")
222
+ // }
223
+
217
224
val lastAtSymbolIndex = input.lastIndexOf(' @' )
218
225
219
226
if (lastAtSymbolIndex != - 1 && lastAtSymbolIndex == input.length - 1 ) {
@@ -320,22 +327,116 @@ class TaskChatFragment : Fragment(), ChatAdapter.onChatDoubleClickListner,
320
327
" ` `" , type = 2
321
328
)
322
329
}
330
+
331
+ binding.inputBox.closeLinkPreview.setOnClickThrottleBounceListener {
332
+ binding.inputBox.linkPreviewSender.gone()
333
+ }
323
334
}
335
+ private fun extractLinks (input : String ) : String {
336
+ val urlPattern = " (https?|ftp)://[^\\ s/$.?#].[^\\ s]*" .toRegex()
337
+ val matches = urlPattern.findAll(input)
338
+ val firstMatch = matches.firstOrNull()
339
+ if (firstMatch != null ) {
340
+ val link = firstMatch.value
341
+ return link
342
+ } else {
343
+ return " "
344
+ }
345
+ }
346
+ private fun processLinks (link : String ) {
347
+ if (link.isNotEmpty() || link!= " " ) {
348
+ binding.inputBox.linkPreviewSender.visible()
349
+ CoroutineScope (Dispatchers .IO ).launch {
324
350
351
+ // "Title" to title,
352
+ // "Description" to description,
353
+ // "Open Graph Title" to ogTitle,
354
+ // "Open Graph Description" to ogDescription,
355
+ // "Open Graph Image" to ogImage
356
+
357
+ val metadata = fetchMetadata(link)
358
+ withContext(Dispatchers .Main ) {
359
+ if (metadata.isNull) {
360
+ binding.inputBox.linkPreviewSender.gone()
361
+ } else {
362
+ if (metadata?.getValue(" Type" )== " normal" ) {
363
+ binding.inputBox.linkPreviewTitle.text = metadata?.getValue(" Title" )
364
+
365
+ binding.inputBox.linkPreviewDesc.text = if (metadata?.getValue(" Open Graph Description" ).isNullOrEmpty()) link else metadata.getValue(" Open Graph Description" )
366
+
367
+ }
368
+ else {
369
+ binding.inputBox.linkPreviewTitle.text = metadata?.getValue(" Title" )
370
+ binding.inputBox.linkPreviewDesc.text = link
371
+ }
372
+ }
373
+ }
374
+ }
325
375
326
- private fun extractLinks (text : String ): List <String > {
327
- val links = mutableListOf<String >()
328
- val pattern = Patterns .WEB_URL
329
- val matcher: Matcher = pattern.matcher(text)
330
- while (matcher.find()) {
331
- val url = matcher.group()
332
- links.add(url)
376
+ } else {
377
+ binding.inputBox.linkPreviewSender.gone()
333
378
}
334
- return links
335
379
}
336
380
337
- private fun processLink (link : String ) {
338
-
381
+ suspend fun fetchMetadata (url : String ): Map <String , String >? {
382
+ return try {
383
+ val document = Jsoup .connect(url).get()
384
+
385
+ val title = document.title()
386
+ val description = document.select(" meta[name=description]" ).attr(" content" )
387
+ val ogTitle = document.select(" meta[property=og:title]" ).attr(" content" )
388
+ val ogDescription = document.select(" meta[property=og:description]" ).attr(" content" )
389
+ val ogImage = document.select(" meta[property=og:image]" ).attr(" content" )
390
+
391
+ mapOf (
392
+ " Title" to title,
393
+ " Description" to description,
394
+ " Open Graph Title" to ogTitle,
395
+ " Open Graph Description" to ogDescription,
396
+ " Open Graph Image" to ogImage,
397
+ " Type" to " normal"
398
+ )
399
+ } catch (e: IOException ) {
400
+ Log .d(" metadatafetch" ,e.message.toString())
401
+ val list= extractPartsFromUrl(e.message!! )
402
+ if (list.isNullOrEmpty()) {
403
+ util.showSnackbar(binding.root, " Unable to fetch the link details" , 2000 )
404
+ null
405
+ }
406
+ else {
407
+ if (list.size== 4 ){
408
+ mapOf (
409
+ " Title" to " ${list[0 ].capitalize()} #${list[3 ].dropLast(1 )} -${list[1 ]} " ,
410
+ " Description" to " " ,
411
+ " Open Graph Title" to " " ,
412
+ " Open Graph Description" to " " ,
413
+ " Open Graph Image" to " " ,
414
+ " Type" to " o2"
415
+ )
416
+ }
417
+ else {
418
+ mapOf (
419
+ " Title" to " ${list[0 ].capitalize()} - ${list[1 ].capitalize().dropLast(1 )} " ,
420
+ " Description" to " " ,
421
+ " Open Graph Title" to " " ,
422
+ " Open Graph Description" to " " ,
423
+ " Open Graph Image" to " " ,
424
+ " Type" to " o2"
425
+ )
426
+ }
427
+ }
428
+ }
429
+ }
430
+ fun extractPartsFromUrl (inputString : String ): List <String > {
431
+ val urlPattern = Regex (" https://oxgn\\ .page\\ .link/([^/]+)/([^/]+)(?:/([^/]+)(?:/([^/\\ ]]+))?)?" )
432
+ val matchResult = urlPattern.find(inputString)
433
+ return matchResult?.let {
434
+ val (part1, part2, part3, part4) = matchResult.destructured
435
+ when {
436
+ part3.isEmpty() -> listOf (part1, part2)
437
+ else -> listOf (part1, part2, part3, part4).filter { it.isNotEmpty() }
438
+ }
439
+ } ? : emptyList()
339
440
}
340
441
341
442
private fun pasteFromClipboard () {
0 commit comments