FullScreenImageActivity.kt 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. /*
  2. * Nextcloud Talk application
  3. *
  4. * @author Marcel Hibbe
  5. * @author Dariusz Olszewski
  6. * @author Andy Scherzinger
  7. * Copyright (C) 2021 Andy Scherzinger <info@andy-scherzinger.de>
  8. * Copyright (C) 2021 Marcel Hibbe <dev@mhibbe.de>
  9. * Copyright (C) 2021 Dariusz Olszewski
  10. *
  11. * This program is free software: you can redistribute it and/or modify
  12. * it under the terms of the GNU General Public License as published by
  13. * the Free Software Foundation, either version 3 of the License, or
  14. * at your option) any later version.
  15. *
  16. * This program is distributed in the hope that it will be useful,
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19. * GNU General Public License for more details.
  20. *
  21. * You should have received a copy of the GNU General Public License
  22. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  23. */
  24. package com.nextcloud.talk.activities
  25. import android.content.Intent
  26. import android.os.Bundle
  27. import android.util.Log
  28. import android.view.Menu
  29. import android.view.MenuItem
  30. import android.view.View
  31. import android.widget.Toast
  32. import androidx.appcompat.app.AppCompatActivity
  33. import androidx.core.content.FileProvider
  34. import com.nextcloud.talk.BuildConfig
  35. import com.nextcloud.talk.R
  36. import com.nextcloud.talk.databinding.ActivityFullScreenImageBinding
  37. import com.nextcloud.talk.utils.BitmapShrinker
  38. import com.nextcloud.talk.utils.Mimetype.IMAGE_PREFIX_GENERIC
  39. import pl.droidsonroids.gif.GifDrawable
  40. import java.io.File
  41. class FullScreenImageActivity : AppCompatActivity() {
  42. lateinit var binding: ActivityFullScreenImageBinding
  43. private lateinit var path: String
  44. private var showFullscreen = false
  45. override fun onCreateOptionsMenu(menu: Menu?): Boolean {
  46. menuInflater.inflate(R.menu.menu_preview, menu)
  47. return true
  48. }
  49. override fun onOptionsItemSelected(item: MenuItem): Boolean {
  50. return if (item.itemId == android.R.id.home) {
  51. onBackPressed()
  52. true
  53. } else if (item.itemId == R.id.share) {
  54. val shareUri = FileProvider.getUriForFile(
  55. this,
  56. BuildConfig.APPLICATION_ID,
  57. File(path)
  58. )
  59. val shareIntent: Intent = Intent().apply {
  60. action = Intent.ACTION_SEND
  61. putExtra(Intent.EXTRA_STREAM, shareUri)
  62. type = IMAGE_PREFIX_GENERIC
  63. addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
  64. }
  65. startActivity(Intent.createChooser(shareIntent, resources.getText(R.string.send_to)))
  66. true
  67. } else {
  68. super.onOptionsItemSelected(item)
  69. }
  70. }
  71. override fun onCreate(savedInstanceState: Bundle?) {
  72. super.onCreate(savedInstanceState)
  73. binding = ActivityFullScreenImageBinding.inflate(layoutInflater)
  74. setContentView(binding.root)
  75. setSupportActionBar(binding.imageviewToolbar)
  76. binding.photoView.setOnPhotoTapListener { view, x, y ->
  77. toggleFullscreen()
  78. }
  79. binding.photoView.setOnOutsidePhotoTapListener {
  80. toggleFullscreen()
  81. }
  82. binding.gifView.setOnClickListener {
  83. toggleFullscreen()
  84. }
  85. // Enable enlarging the image more than default 3x maximumScale.
  86. // Medium scale adapted to make double-tap behaviour more consistent.
  87. binding.photoView.maximumScale = MAX_SCALE
  88. binding.photoView.mediumScale = MEDIUM_SCALE
  89. val fileName = intent.getStringExtra("FILE_NAME")
  90. val isGif = intent.getBooleanExtra("IS_GIF", false)
  91. supportActionBar?.title = fileName
  92. supportActionBar?.setDisplayHomeAsUpEnabled(true)
  93. path = applicationContext.cacheDir.absolutePath + "/" + fileName
  94. if (isGif) {
  95. binding.photoView.visibility = View.INVISIBLE
  96. binding.gifView.visibility = View.VISIBLE
  97. val gifFromUri = GifDrawable(path)
  98. binding.gifView.setImageDrawable(gifFromUri)
  99. } else {
  100. binding.gifView.visibility = View.INVISIBLE
  101. binding.photoView.visibility = View.VISIBLE
  102. displayImage(path)
  103. }
  104. }
  105. private fun displayImage(path: String) {
  106. val displayMetrics = applicationContext.resources.displayMetrics
  107. val doubleScreenWidth = displayMetrics.widthPixels * 2
  108. val doubleScreenHeight = displayMetrics.heightPixels * 2
  109. val bitmap = BitmapShrinker.shrinkBitmap(path, doubleScreenWidth, doubleScreenHeight)
  110. val bitmapSize: Int = bitmap.byteCount
  111. // info that 100MB is the limit comes from https://stackoverflow.com/a/53334563
  112. if (bitmapSize > HUNDRED_MB) {
  113. Log.e(TAG, "bitmap will be too large to display. It won't be displayed to avoid RuntimeException")
  114. Toast.makeText(this, R.string.nc_common_error_sorry, Toast.LENGTH_LONG).show()
  115. } else {
  116. binding.photoView.setImageBitmap(bitmap)
  117. }
  118. }
  119. private fun toggleFullscreen() {
  120. showFullscreen = !showFullscreen
  121. if (showFullscreen) {
  122. hideSystemUI()
  123. supportActionBar?.hide()
  124. } else {
  125. showSystemUI()
  126. supportActionBar?.show()
  127. }
  128. }
  129. private fun hideSystemUI() {
  130. window.decorView.systemUiVisibility = (
  131. View.SYSTEM_UI_FLAG_IMMERSIVE
  132. or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
  133. or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
  134. or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
  135. or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
  136. or View.SYSTEM_UI_FLAG_FULLSCREEN
  137. )
  138. }
  139. private fun showSystemUI() {
  140. window.decorView.systemUiVisibility = (
  141. View.SYSTEM_UI_FLAG_LAYOUT_STABLE
  142. or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
  143. or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
  144. )
  145. }
  146. companion object {
  147. private val TAG = "FullScreenImageActivity"
  148. private const val HUNDRED_MB = 100 * 1024 * 1024
  149. private const val MAX_SCALE = 6.0f
  150. private const val MEDIUM_SCALE = 2.45f
  151. }
  152. }