From 16ab9a8dfae44eb26c6e0de6e16ada6c2641cb23 Mon Sep 17 00:00:00 2001 From: Allan Wang Date: Wed, 3 Jul 2019 14:01:19 -0700 Subject: Redo image activity to support text content --- .idea/codeStyles/Project.xml | 9 ++ app/build.gradle | 8 +- .../kotlin/com/pitchedapps/frost/StartActivity.kt | 12 +- .../pitchedapps/frost/activities/ImageActivity.kt | 126 +++++++++++++-------- .../com/pitchedapps/frost/views/DragFrame.kt | 39 +++++++ app/src/main/res/layout/activity_image.xml | 76 ++++++------- .../main/res/layout/activity_image_textless.xml | 37 ------ buildSrc/src/main/kotlin/Versions.kt | 2 + 8 files changed, 175 insertions(+), 134 deletions(-) delete mode 100644 app/src/main/res/layout/activity_image_textless.xml diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml index 3962e1c3..7d1ace49 100644 --- a/.idea/codeStyles/Project.xml +++ b/.idea/codeStyles/Project.xml @@ -21,6 +21,7 @@ xmlns:android + ^$ @@ -31,6 +32,7 @@ xmlns:.* + ^$ @@ -42,6 +44,7 @@ .*:id + http://schemas.android.com/apk/res/android @@ -52,6 +55,7 @@ .*:name + http://schemas.android.com/apk/res/android @@ -62,6 +66,7 @@ name + ^$ @@ -72,6 +77,7 @@ style + ^$ @@ -82,6 +88,7 @@ .* + ^$ @@ -93,6 +100,7 @@ .* + http://schemas.android.com/apk/res/android @@ -104,6 +112,7 @@ .* + .* diff --git a/app/build.gradle b/app/build.gradle index b21162f9..60159812 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -22,7 +22,7 @@ apply from: '../spotless.gradle' group = APP_GROUP android { - compileSdkVersion kau.Versions.targetSdk + compileSdkVersion Versions.targetSdk buildToolsVersion kau.Versions.buildTools androidGitVersion { @@ -34,7 +34,7 @@ android { defaultConfig { applicationId "${project.APP_GROUP}.${project.APP_ID.toLowerCase(Locale.CANADA)}" minSdkVersion kau.Versions.minSdk - targetSdkVersion kau.Versions.targetSdk + targetSdkVersion Versions.targetSdk versionCode androidGitVersion.code() versionName androidGitVersion.name() multiDexEnabled true @@ -65,6 +65,10 @@ android { textOutput 'stdout' } + dataBinding { + enabled = true + } + def testKeystoreFile = file('../files/test.keystore') def testPropFile = file('../files/test.properties') def withTestSigning = testKeystoreFile.exists() && testPropFile.exists() diff --git a/app/src/main/kotlin/com/pitchedapps/frost/StartActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/StartActivity.kt index 61b4a194..051b3235 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/StartActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/StartActivity.kt @@ -46,6 +46,7 @@ import com.pitchedapps.frost.utils.BiometricUtils import com.pitchedapps.frost.utils.EXTRA_COOKIES import com.pitchedapps.frost.utils.L import com.pitchedapps.frost.utils.Prefs +import com.pitchedapps.frost.utils.launchImageActivity import com.pitchedapps.frost.utils.launchNewTask import com.pitchedapps.frost.utils.loadAssets import com.raizlabs.android.dbflow.kotlinextensions.from @@ -98,11 +99,12 @@ class StartActivity : KauBaseActivity() { cookies.isEmpty() -> launchNewTask() // Has cookies but no selected account Prefs.userId == -1L -> launchNewTask(cookies) - else -> startActivity(intentBuilder = { - putParcelableArrayListExtra(EXTRA_COOKIES, cookies) - flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP or - Intent.FLAG_ACTIVITY_SINGLE_TOP - }) + else -> launchImageActivity("https://images.pexels.com/photos/374870/pexels-photo-374870.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500", "Hello world\nLong Text\nLSEF") +// else -> startActivity(intentBuilder = { +// putParcelableArrayListExtra(EXTRA_COOKIES, cookies) +// flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP or +// Intent.FLAG_ACTIVITY_SINGLE_TOP +// }) } } catch (e: Exception) { L._e(e) { "Load start failed" } diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/ImageActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/ImageActivity.kt index c7d31032..46e53887 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/ImageActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/ImageActivity.kt @@ -24,6 +24,7 @@ import android.os.Bundle import android.os.Environment import android.view.View import androidx.customview.widget.ViewDragHelper +import androidx.databinding.DataBindingUtil import ca.allanwang.kau.internal.KauBaseActivity import ca.allanwang.kau.logging.KauLoggerExtension import ca.allanwang.kau.mediapicker.scanMedia @@ -33,6 +34,7 @@ import ca.allanwang.kau.utils.adjustAlpha import ca.allanwang.kau.utils.colorToForeground import ca.allanwang.kau.utils.copyFromInputStream import ca.allanwang.kau.utils.fadeOut +import ca.allanwang.kau.utils.gone import ca.allanwang.kau.utils.isHidden import ca.allanwang.kau.utils.isVisible import ca.allanwang.kau.utils.materialDialog @@ -43,10 +45,12 @@ import ca.allanwang.kau.utils.withAlpha import ca.allanwang.kau.utils.withMinAlpha import com.davemorrissey.labs.subscaleview.ImageSource import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView +import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.floatingactionbutton.FloatingActionButton import com.mikepenz.google_material_typeface_library.GoogleMaterial import com.mikepenz.iconics.typeface.IIcon import com.pitchedapps.frost.R +import com.pitchedapps.frost.databinding.ActivityImageBinding import com.pitchedapps.frost.facebook.FB_IMAGE_ID_MATCHER import com.pitchedapps.frost.facebook.get import com.pitchedapps.frost.facebook.requests.call @@ -63,8 +67,6 @@ import com.pitchedapps.frost.utils.isIndirectImageUrl import com.pitchedapps.frost.utils.logFrostEvent import com.pitchedapps.frost.utils.sendFrostEmail import com.pitchedapps.frost.utils.setFrostColors -import com.sothree.slidinguppanel.SlidingUpPanelLayout -import kotlinx.android.synthetic.main.activity_image.* import kotlinx.coroutines.CoroutineExceptionHandler import kotlinx.coroutines.Deferred import kotlinx.coroutines.Dispatchers @@ -104,7 +106,7 @@ class ImageActivity : KauBaseActivity() { set(value) { if (field == value) return field = value - value.update(image_fab) + value.update(binding.imageFab) } private lateinit var dragHelper: ViewDragHelper @@ -141,14 +143,19 @@ class ImageActivity : KauBaseActivity() { )}_${Math.abs(imageUrl.hashCode())}" } + private lateinit var binding: ActivityImageBinding + private lateinit var bottomBehavior: BottomSheetBehavior + private val baseBackgroundColor = if (Prefs.blackMediaBg) Color.BLACK else Prefs.bgColor.withMinAlpha(235) private fun loadError(e: Throwable) { errorRef = e e.logFrostEvent("Image load error") - if (image_progress.isVisible) - image_progress.fadeOut() + with(binding) { + if (imageProgress.isVisible) + imageProgress.fadeOut() + } tempFile.delete() fabAction = FabStates.ERROR } @@ -166,28 +173,49 @@ class ImageActivity : KauBaseActivity() { L.v { "Launching with true url $result" } result } + binding = DataBindingUtil.setContentView(this, R.layout.activity_image) + binding.onCreate() + tempFile = File(cacheDir(this), imageHash) + launch(CoroutineExceptionHandler { _, throwable -> loadError(throwable) }) { + downloadImageTo(tempFile) + binding.imageProgress.fadeOut() + binding.imagePhoto.setImage(ImageSource.uri(frostUriFromFile(tempFile))) + fabAction = FabStates.DOWNLOAD + binding.imagePhoto.animate().alpha(1f).scaleXY(1f).start() + } + } - val layout = - if (!imageText.isNullOrBlank()) R.layout.activity_image else R.layout.activity_image_textless - setContentView(layout) - image_container.setBackgroundColor(baseBackgroundColor) - image_text?.setTextColor(if (Prefs.blackMediaBg) Color.WHITE else Prefs.textColor) - image_text?.setBackgroundColor( - (if (Prefs.blackMediaBg) Color.BLACK else Prefs.bgColor) - .colorToForeground(0.2f).withAlpha(255) - ) - image_text?.text = imageText - image_progress.tint(if (Prefs.blackMediaBg) Color.WHITE else Prefs.accentColor) - image_panel?.addPanelSlideListener(object : - SlidingUpPanelLayout.SimplePanelSlideListener() { - override fun onPanelSlide(panel: View, slideOffset: Float) { - if (slideOffset == 0f && !image_fab.isShown) image_fab.show() - else if (slideOffset != 0f && image_fab.isShown) image_fab.hide() - image_text?.alpha = slideOffset / 2 + 0.5f + private fun ActivityImageBinding.onCreate() { + imageContainer.setBackgroundColor(baseBackgroundColor) + this@ImageActivity.imageText.also { text -> + if (text == null) { + imageText.gone() + } else { + imageText.setTextColor(if (Prefs.blackMediaBg) Color.WHITE else Prefs.textColor) + imageText.setBackgroundColor( + (if (Prefs.blackMediaBg) Color.BLACK else Prefs.bgColor) + .colorToForeground(0.2f).withAlpha(255) + ) + imageText.text = text + bottomBehavior = BottomSheetBehavior.from(imageText).apply { + setBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() { + override fun onSlide(bottomSheet: View, slideOffset: Float) { + if (slideOffset == 0f && !imageFab.isShown) imageFab.show() + else if (slideOffset != 0f && imageFab.isShown) imageFab.hide() + imageText.alpha = slideOffset / 2 + 0.5f + } + + override fun onStateChanged(bottomSheet: View, newState: Int) { + // No op + } + }) + } + imageText.bringToFront() } - }) - image_fab.setOnClickListener { fabAction.onClick(this) } - image_photo.setOnImageEventListener(object : + } + imageProgress.tint(if (Prefs.blackMediaBg) Color.WHITE else Prefs.accentColor) + imageFab.setOnClickListener { fabAction.onClick(this@ImageActivity) } + imagePhoto.setOnImageEventListener(object : SubsamplingScaleImageView.DefaultOnImageEventListener() { override fun onImageLoadError(e: Exception) { loadError(e) @@ -196,18 +224,11 @@ class ImageActivity : KauBaseActivity() { setFrostColors { themeWindow = false } - tempFile = File(cacheDir(this), imageHash) - launch(CoroutineExceptionHandler { _, throwable -> loadError(throwable) }) { - downloadImageTo(tempFile) - image_progress.fadeOut() - image_photo.setImage(ImageSource.uri(frostUriFromFile(tempFile))) - fabAction = FabStates.DOWNLOAD - image_photo.animate().alpha(1f).scaleXY(1f).start() - dragHelper = ViewDragHelper.create(image_drag, ViewDragCallback()).apply { - setEdgeTrackingEnabled(ViewDragHelper.EDGE_TOP or ViewDragHelper.EDGE_BOTTOM) - } - image_drag.dragHelper = dragHelper + dragHelper = ViewDragHelper.create(imageDrag, ViewDragCallback()).apply { + setEdgeTrackingEnabled(ViewDragHelper.EDGE_TOP or ViewDragHelper.EDGE_BOTTOM) } + imageDrag.dragHelper = dragHelper + imageDrag.viewToIgnore = imageText } private inner class ViewDragCallback : ViewDragHelper.Callback() { @@ -216,7 +237,8 @@ class ImageActivity : KauBaseActivity() { private var scrollToTop = false override fun tryCaptureView(view: View, i: Int): Boolean { - return true + L.d { "Try capture ${view.id} $i ${binding.imagePhoto.id} ${binding.imageText.id}" } + return view === binding.imagePhoto } override fun getViewHorizontalDragRange(child: View): Int = 0 @@ -231,18 +253,22 @@ class ImageActivity : KauBaseActivity() { dy: Int ) { super.onViewPositionChanged(changedView, left, top, dx, dy) - //make sure that we are using the proper axis - scrollPercent = abs(top.toFloat() / image_container.height) - scrollToTop = top < 0 - val multiplier = max(1f - scrollPercent, 0f) - image_fab.alpha = multiplier - image_panel?.alpha = multiplier - image_container.setBackgroundColor(baseBackgroundColor.adjustAlpha(multiplier)) - - if (scrollPercent >= 1) { - if (!isFinishing) { - finish() - overridePendingTransition(0, 0) + with(binding) { + //make sure that we are using the proper axis + scrollPercent = abs(top.toFloat() / imageContainer.height) + scrollToTop = top < 0 + val multiplier = max(1f - scrollPercent, 0f) + + imageFab.alpha = multiplier + imageText.alpha = + multiplier * (if (bottomBehavior.state == BottomSheetBehavior.STATE_COLLAPSED) 0.5f else 1f) + imageContainer.setBackgroundColor(baseBackgroundColor.adjustAlpha(multiplier)) + + if (scrollPercent >= 1) { + if (!isFinishing) { + finish() + overridePendingTransition(0, 0) + } } } } @@ -256,7 +282,7 @@ class ImageActivity : KauBaseActivity() { else -> 0 } dragHelper.settleCapturedViewAt(0, finalTop) - image_drag.invalidate() + binding.imageDrag.invalidate() } override fun clampViewPositionHorizontal(child: View, left: Int, dx: Int): Int = 0 diff --git a/app/src/main/kotlin/com/pitchedapps/frost/views/DragFrame.kt b/app/src/main/kotlin/com/pitchedapps/frost/views/DragFrame.kt index c2f36536..2ba490cb 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/views/DragFrame.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/views/DragFrame.kt @@ -18,20 +18,34 @@ package com.pitchedapps.frost.views import android.annotation.SuppressLint import android.content.Context +import android.graphics.Rect import android.util.AttributeSet import android.view.MotionEvent +import android.view.View import android.widget.FrameLayout import androidx.core.view.ViewCompat import androidx.customview.widget.ViewDragHelper +import com.pitchedapps.frost.utils.L class DragFrame @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : FrameLayout(context, attrs, defStyleAttr) { + var dragHelper: ViewDragHelper? = null + var viewToIgnore: View? = null + private val rect = Rect() + private val location = IntArray(2) + private var shouldIgnore: Boolean = false override fun onInterceptTouchEvent(event: MotionEvent): Boolean { + if (event.actionMasked == MotionEvent.ACTION_DOWN) { + shouldIgnore = shouldIgnore(event) + } + if (shouldIgnore) { + return false + } return try { dragHelper?.shouldInterceptTouchEvent(event) ?: false } catch (e: Exception) { @@ -41,6 +55,12 @@ class DragFrame @JvmOverloads constructor( @SuppressLint("ClickableViewAccessibility") override fun onTouchEvent(event: MotionEvent): Boolean { + if (event.actionMasked == MotionEvent.ACTION_DOWN) { + shouldIgnore = shouldIgnore(event) + } + if (shouldIgnore) { + return false + } try { dragHelper?.processTouchEvent(event) ?: return false } catch (e: Exception) { @@ -49,6 +69,25 @@ class DragFrame @JvmOverloads constructor( return true } + override fun dispatchTouchEvent(event: MotionEvent): Boolean { + if (event.actionMasked == MotionEvent.ACTION_DOWN) { + shouldIgnore = shouldIgnore(event) + } + if (shouldIgnore) { + return false + } + return super.dispatchTouchEvent(event) + } + + private fun shouldIgnore(event: MotionEvent): Boolean { + val v = viewToIgnore ?: return false + v.getDrawingRect(rect) + v.getLocationOnScreen(location) + rect.offset(location[0], location[1]) + L.d { "${event.rawX} ${event.x} ${event.rawY} ${event.y} ${rect}" } + return rect.contains(event.rawX.toInt(), event.rawY.toInt()) + } + override fun computeScroll() { super.computeScroll() if (dragHelper?.continueSettling(true) == true) { diff --git a/app/src/main/res/layout/activity_image.xml b/app/src/main/res/layout/activity_image.xml index 85837fc3..2bf68056 100644 --- a/app/src/main/res/layout/activity_image.xml +++ b/app/src/main/res/layout/activity_image.xml @@ -1,44 +1,23 @@ - - - - - - - + + - + - + - - - + - \ No newline at end of file + + + + + + + diff --git a/app/src/main/res/layout/activity_image_textless.xml b/app/src/main/res/layout/activity_image_textless.xml deleted file mode 100644 index 41fd43a2..00000000 --- a/app/src/main/res/layout/activity_image_textless.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - \ No newline at end of file diff --git a/buildSrc/src/main/kotlin/Versions.kt b/buildSrc/src/main/kotlin/Versions.kt index 5d93dbfa..e8ce7f0e 100644 --- a/buildSrc/src/main/kotlin/Versions.kt +++ b/buildSrc/src/main/kotlin/Versions.kt @@ -1,5 +1,7 @@ object Versions { + const val targetSdk = 28 + const val andxBiometric = "1.0.0-alpha04" // https://mvnrepository.com/artifact/org.apache.commons/commons-text -- cgit v1.2.3