From 41b96beb1c66933b80016f925aa9d2dc8e20b41d Mon Sep 17 00:00:00 2001 From: Adolfo Santiago Date: Sat, 4 Sep 2021 16:00:39 +0200 Subject: [PATCH] Fixed video player This commit fixes the issue n. 122 of the list of issues reported in the previous repository (https://git.mentality.rip/FWGS/Husky/issues/122). --- husky/app/build.gradle.kts | 3 +- .../keylesspalace/tusky/TuskyApplication.kt | 4 + .../components/compose/ComposeActivity.kt | 66 ++-- .../tusky/fragment/ViewMediaFragment.kt | 1 + .../tusky/fragment/ViewVideoFragment.kt | 344 ++++++++++-------- .../main/res/layout/fragment_view_video.xml | 76 ++-- husky/buildSrc/src/main/kotlin/AppLibs.kt | 89 +++-- husky/gradlew | 0 8 files changed, 329 insertions(+), 254 deletions(-) mode change 100755 => 100644 husky/gradlew diff --git a/husky/app/build.gradle.kts b/husky/app/build.gradle.kts index 9282d65..25ba3dd 100644 --- a/husky/app/build.gradle.kts +++ b/husky/app/build.gradle.kts @@ -172,7 +172,8 @@ dependencies { implementation(ApplicationLibs.Glide.glideOkhttp) kapt(ApplicationLibs.Glide.glideCompiler) - implementation(ApplicationLibs.Google.flexBox) + implementation(ApplicationLibs.Google.flexbox) + implementation(ApplicationLibs.Google.exoplayer) implementation(ApplicationLibs.Google.materialDesign) implementation(ApplicationLibs.RxJava.rxAndroid) diff --git a/husky/app/src/main/java/com/keylesspalace/tusky/TuskyApplication.kt b/husky/app/src/main/java/com/keylesspalace/tusky/TuskyApplication.kt index fe5f3b8..81fe7f1 100644 --- a/husky/app/src/main/java/com/keylesspalace/tusky/TuskyApplication.kt +++ b/husky/app/src/main/java/com/keylesspalace/tusky/TuskyApplication.kt @@ -39,6 +39,8 @@ import io.reactivex.plugins.RxJavaPlugins import org.conscrypt.Conscrypt import java.security.Security import javax.inject.Inject +import timber.log.Timber +import timber.log.Timber.DebugTree class TuskyApplication : Application(), HasAndroidInjector { @@ -93,6 +95,8 @@ class TuskyApplication : Application(), HasAndroidInjector { .setWorkerFactory(notificationWorkerFactory) .build() ) + + Timber.plant(DebugTree()) } override fun attachBaseContext(base: Context) { diff --git a/husky/app/src/main/java/com/keylesspalace/tusky/components/compose/ComposeActivity.kt b/husky/app/src/main/java/com/keylesspalace/tusky/components/compose/ComposeActivity.kt index 5539d10..5b1f6da 100644 --- a/husky/app/src/main/java/com/keylesspalace/tusky/components/compose/ComposeActivity.kt +++ b/husky/app/src/main/java/com/keylesspalace/tusky/components/compose/ComposeActivity.kt @@ -109,7 +109,7 @@ class ComposeActivity : BaseActivity(), @Inject lateinit var viewModelFactory: ViewModelFactory - + @Inject lateinit var eventHub: EventHub @@ -177,12 +177,12 @@ class ComposeActivity : BaseActivity(), val composeOptions = intent.getParcelableExtra(COMPOSE_OPTIONS_EXTRA) - if (!composeOptions?.formattingSyntax.isNullOrEmpty()) { - suggestFormattingSyntax = composeOptions?.formattingSyntax!! + suggestFormattingSyntax = if (!composeOptions?.formattingSyntax.isNullOrEmpty()) { + composeOptions?.formattingSyntax!! } else { - suggestFormattingSyntax = activeAccount.defaultFormattingSyntax + activeAccount.defaultFormattingSyntax } - + viewModel.setup(composeOptions) setupReplyViews(composeOptions?.replyingStatusAuthor, composeOptions?.replyingStatusContent) val tootText = composeOptions?.tootText @@ -210,7 +210,7 @@ class ComposeActivity : BaseActivity(), } } } - + private fun applyShareIntent(intent: Intent, savedInstanceState: Bundle?) { if (savedInstanceState == null) { /* Get incoming images being sent through a share action from another app. Only do this @@ -314,7 +314,7 @@ class ComposeActivity : BaseActivity(), composeEditField.setLayerType(View.LAYER_TYPE_SOFTWARE, null) } } - + private fun reenableAttachments() { // in case of we already had disabled attachments // but got information about extension later @@ -336,20 +336,20 @@ class ComposeActivity : BaseActivity(), if(instanceData.supportsMarkdown) { supportedFormattingSyntax.add("text/markdown") } - + if(instanceData.supportsBBcode) { supportedFormattingSyntax.add("text/bbcode") } - + if(instanceData.supportsHTML) { supportedFormattingSyntax.add("text/html") } - + if(supportedFormattingSyntax.size != 0) { composeFormattingSyntax.visible(true) - + val supportsPrefferedSyntax = supportedFormattingSyntax.contains(viewModel.formattingSyntax.value!!) - + if(!supportsPrefferedSyntax) { suggestFormattingSyntax = if(supportedFormattingSyntax.contains(activeAccount.defaultFormattingSyntax)) activeAccount.defaultFormattingSyntax @@ -358,7 +358,7 @@ class ComposeActivity : BaseActivity(), viewModel.formattingSyntax.value = "" } } - + if(instanceData.software == "pleroma") { composePreviewButton.visibility = View.VISIBLE reenableAttachments() @@ -528,37 +528,37 @@ class ComposeActivity : BaseActivity(), // Set the cursor after the inserted text composeEditField.setSelection(start + text.length) } - + private fun enableFormattingSyntaxButton(syntax: String, enable: Boolean) { val stringId = when(syntax) { "text/html" -> R.string.action_html "text/bbcode" -> R.string.action_bbcode else -> R.string.action_markdown } - + val actionStringId = if(enable) R.string.action_disable_formatting_syntax else R.string.action_enable_formatting_syntax val tooltipText = getString(actionStringId).format(stringId) - + composeFormattingSyntax.contentDescription = tooltipText - + @ColorInt val color = ThemeUtils.getColor(this, if(enable) R.attr.colorPrimary else android.R.attr.textColorTertiary); composeFormattingSyntax.drawable.colorFilter = PorterDuffColorFilter(color, PorterDuff.Mode.SRC_IN); - + enableMarkdownWYSIWYGButtons(enable); } - + private fun setIconForSyntax(syntax: String, enable: Boolean) { val drawableId = when(syntax) { "text/html" -> R.drawable.ic_html_24dp "text/bbcode" -> R.drawable.ic_bbcode_24dp else -> R.drawable.ic_markdown } - + suggestFormattingSyntax = if(drawableId == R.drawable.ic_markdown) "text/markdown" else syntax composeFormattingSyntax.setImageResource(drawableId) enableFormattingSyntaxButton(syntax, enable) } - + private fun toggleFormattingMode() { if(viewModel.formattingSyntax.value!! == suggestFormattingSyntax) { viewModel.formattingSyntax.value = "" @@ -566,7 +566,7 @@ class ComposeActivity : BaseActivity(), viewModel.formattingSyntax.value = suggestFormattingSyntax } } - + private fun selectFormattingSyntax() : Boolean { val menu = PopupMenu(this, composeFormattingSyntax) val plaintextId = 0 @@ -582,7 +582,7 @@ class ComposeActivity : BaseActivity(), if(viewModel.instanceMetadata.value?.supportsHTML ?: false) menu.menu.add(0, htmlId, 0, R.string.action_html) - + menu.setOnMenuItemClickListener { menuItem -> val choose = when (menuItem.itemId) { markdownId -> "text/markdown" @@ -595,10 +595,10 @@ class ComposeActivity : BaseActivity(), true } menu.show() - + return true } - + private fun enableMarkdownWYSIWYGButtons(visible: Boolean) { val visibility = if(visible) View.VISIBLE else View.GONE codeButton.visibility = visibility @@ -656,7 +656,7 @@ class ComposeActivity : BaseActivity(), private fun hashButtonClicked() { prependSelectedWordsWith("#") } - + private fun codeButtonClicked() { when(viewModel.formattingSyntax.value!!) { "text/markdown" -> MarkdownEdit.addCode(composeEditField) @@ -664,7 +664,7 @@ class ComposeActivity : BaseActivity(), "text/html" -> HTMLEdit.addCode(composeEditField) } } - + private fun linkButtonClicked() { when(viewModel.formattingSyntax.value!!) { "text/markdown" -> MarkdownEdit.addLink(composeEditField) @@ -672,7 +672,7 @@ class ComposeActivity : BaseActivity(), "text/html" -> HTMLEdit.addLink(composeEditField) } } - + private fun strikethroughButtonClicked() { when(viewModel.formattingSyntax.value!!) { "text/markdown" -> MarkdownEdit.addStrikeThrough(composeEditField) @@ -680,7 +680,7 @@ class ComposeActivity : BaseActivity(), "text/html" -> HTMLEdit.addStrikeThrough(composeEditField) } } - + private fun italicButtonClicked() { when(viewModel.formattingSyntax.value!!) { "text/markdown" -> MarkdownEdit.addItalic(composeEditField) @@ -688,7 +688,7 @@ class ComposeActivity : BaseActivity(), "text/html" -> HTMLEdit.addItalic(composeEditField) } } - + private fun boldButtonClicked() { when(viewModel.formattingSyntax.value!!) { "text/markdown" -> MarkdownEdit.addBold(composeEditField) @@ -945,14 +945,14 @@ class ComposeActivity : BaseActivity(), if(preview && previewBehavior.state != BottomSheetBehavior.STATE_HIDDEN) { previewBehavior.state = BottomSheetBehavior.STATE_HIDDEN } - + if (verifyScheduledTime()) { sendStatus(preview) } else { showScheduleView() } } - + private fun onStatusPreviewReady(status: Status) { enableButtons(true) previewView.setupWithStatus(status) @@ -1060,7 +1060,6 @@ class ComposeActivity : BaseActivity(), private fun initiateMediaPicking() { val intent = Intent(Intent.ACTION_GET_CONTENT) - intent.addCategory(Intent.CATEGORY_OPENABLE) if(!viewModel.hasNoAttachmentLimits) { val mimeTypes = arrayOf("image/*", "video/*", "audio/*") @@ -1068,6 +1067,7 @@ class ComposeActivity : BaseActivity(), } intent.type = "*/*" intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true) + intent.addCategory(Intent.CATEGORY_OPENABLE) startActivityForResult(intent, MEDIA_PICK_RESULT) } diff --git a/husky/app/src/main/java/com/keylesspalace/tusky/fragment/ViewMediaFragment.kt b/husky/app/src/main/java/com/keylesspalace/tusky/fragment/ViewMediaFragment.kt index 9b51f28..2c4ec25 100644 --- a/husky/app/src/main/java/com/keylesspalace/tusky/fragment/ViewMediaFragment.kt +++ b/husky/app/src/main/java/com/keylesspalace/tusky/fragment/ViewMediaFragment.kt @@ -21,6 +21,7 @@ import com.keylesspalace.tusky.ViewMediaActivity import com.keylesspalace.tusky.entity.Attachment abstract class ViewMediaFragment : BaseFragment() { + private var toolbarVisibiltyDisposable: Function0? = null abstract fun setupMediaView( diff --git a/husky/app/src/main/java/com/keylesspalace/tusky/fragment/ViewVideoFragment.kt b/husky/app/src/main/java/com/keylesspalace/tusky/fragment/ViewVideoFragment.kt index 6f3c8ab..812c1e8 100644 --- a/husky/app/src/main/java/com/keylesspalace/tusky/fragment/ViewVideoFragment.kt +++ b/husky/app/src/main/java/com/keylesspalace/tusky/fragment/ViewVideoFragment.kt @@ -18,6 +18,7 @@ package com.keylesspalace.tusky.fragment import android.animation.Animator import android.animation.AnimatorListenerAdapter import android.annotation.SuppressLint +import android.net.Uri import android.os.Bundle import android.os.Handler import android.os.Looper @@ -26,182 +27,219 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.MediaController +import com.google.android.exoplayer2.MediaItem +import com.google.android.exoplayer2.PlaybackException +import com.google.android.exoplayer2.Player +import com.google.android.exoplayer2.SimpleExoPlayer +import com.google.android.exoplayer2.trackselection.DefaultTrackSelector import com.keylesspalace.tusky.R import com.keylesspalace.tusky.ViewMediaActivity import com.keylesspalace.tusky.entity.Attachment -import com.keylesspalace.tusky.util.hide import com.keylesspalace.tusky.util.visible -import com.keylesspalace.tusky.view.ExposedPlayPauseVideoView -import kotlinx.android.synthetic.main.activity_view_media.* -import kotlinx.android.synthetic.main.fragment_view_video.* +import kotlinx.android.synthetic.main.activity_view_media.toolbar +import kotlinx.android.synthetic.main.fragment_view_video.mediaDescription +import kotlinx.android.synthetic.main.fragment_view_video.progressBar +import kotlinx.android.synthetic.main.fragment_view_video.videoView +import timber.log.Timber class ViewVideoFragment : ViewMediaFragment() { - private lateinit var toolbar: View - private val handler = Handler(Looper.getMainLooper()) - private val hideToolbar = Runnable { - // Hoist toolbar hiding to activity so it can track state across different fragments - // This is explicitly stored as runnable so that we pass it to the handler later for cancellation - mediaActivity.onPhotoTap() - mediaController.hide() - } - private lateinit var mediaActivity: ViewMediaActivity - private val TOOLBAR_HIDE_DELAY_MS = 3000L - private lateinit var mediaController : MediaController - private var isAudio = false - override fun setUserVisibleHint(isVisibleToUser: Boolean) { - // Start/pause/resume video playback as fragment is shown/hidden - super.setUserVisibleHint(isVisibleToUser) - if (videoView == null) { - return - } + private lateinit var toolbar: View + private val handler = Handler(Looper.getMainLooper()) + private val hideToolbar = Runnable { + // Hoist toolbar hiding to activity so it can track state across different fragments + // This is explicitly stored as runnable so that we pass it to the handler later for cancellation + mediaActivity.onPhotoTap() + mediaController.hide() + } + private lateinit var mediaActivity: ViewMediaActivity + private val TOOLBAR_HIDE_DELAY_MS = 3000L + private lateinit var mediaController: MediaController + private var isAudio = false - if (isVisibleToUser) { - if (mediaActivity.isToolbarVisible) { - handler.postDelayed(hideToolbar, TOOLBAR_HIDE_DELAY_MS) - } - videoView.start() - } else { - handler.removeCallbacks(hideToolbar) - videoView.pause() - mediaController.hide() - } - } + private var exoPlayer: SimpleExoPlayer? = null + private val playbackStateListener: Player.Listener = playbackStateListener() + private var playWhenReady = true + private var currentWindow = 0 + private var playbackPosition = 0L - @SuppressLint("ClickableViewAccessibility") - override fun setupMediaView( - url: String, - previewUrl: String?, - description: String?, - showingDescription: Boolean - ) { - mediaDescription.text = description - mediaDescription.visible(showingDescription) + override fun setUserVisibleHint(isVisibleToUser: Boolean) { + // Start/pause/resume video playback as fragment is shown/hidden + super.setUserVisibleHint(isVisibleToUser) - videoView.transitionName = url - videoView.setVideoPath(url) - mediaController = object : MediaController(mediaActivity) { - override fun show(timeout: Int) { - // We're doing manual auto-close management. - // Also, take focus back from the pause button so we can use the back button. - super.show(0) - mediaController.requestFocus() - } + if(videoView == null) { + return + } - override fun dispatchKeyEvent(event: KeyEvent?): Boolean { - if (event?.keyCode == KeyEvent.KEYCODE_BACK) { - if (event.action == KeyEvent.ACTION_UP) { - hide() - activity?.supportFinishAfterTransition() - } - return true - } - return super.dispatchKeyEvent(event) - } - } + if(isVisibleToUser) { + if(mediaActivity.isToolbarVisible) { + handler.postDelayed(hideToolbar, TOOLBAR_HIDE_DELAY_MS) + } + exoPlayer?.play() + } else { + handler.removeCallbacks(hideToolbar) + exoPlayer?.pause() + mediaController.hide() + } + } - mediaController.setMediaPlayer(videoView) - videoView.setMediaController(mediaController) - videoView.requestFocus() - videoView.setPlayPauseListener(object: ExposedPlayPauseVideoView.PlayPauseListener { - override fun onPause() { - handler.removeCallbacks(hideToolbar) - } - override fun onPlay() { - // Audio doesn't cause the controller to show automatically, - // and we only want to hide the toolbar if it's a video. - if (isAudio) { - mediaController.show() - } else { - hideToolbarAfterDelay(TOOLBAR_HIDE_DELAY_MS) - } - } - }) - videoView.setOnPreparedListener { mp -> - val containerWidth = videoContainer.measuredWidth.toFloat() - val containerHeight = videoContainer.measuredHeight.toFloat() - val videoWidth = mp.videoWidth.toFloat() - val videoHeight = mp.videoHeight.toFloat() + @SuppressLint("ClickableViewAccessibility") + override fun setupMediaView( + url: String, + previewUrl: String?, + description: String?, + showingDescription: Boolean + ) { + mediaDescription.text = description + mediaDescription.visible(showingDescription) - if(containerWidth/containerHeight > videoWidth/videoHeight) { - videoView.layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT - videoView.layoutParams.width = ViewGroup.LayoutParams.WRAP_CONTENT - } else { - videoView.layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT - videoView.layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT - } + videoView.transitionName = url + mediaController = object : MediaController(mediaActivity) { + override fun show(timeout: Int) { + // We're doing manual auto-close management. + // Also, take focus back from the pause button so we can use the back button. + super.show(0) + mediaController.requestFocus() + } - // Wait until the media is loaded before accepting taps as we don't want toolbar to - // be hidden until then. - videoView.setOnTouchListener { _, _ -> - mediaActivity.onPhotoTap() - false - } + override fun dispatchKeyEvent(event: KeyEvent?): Boolean { + if(event?.keyCode == KeyEvent.KEYCODE_BACK) { + if(event.action == KeyEvent.ACTION_UP) { + hide() + activity?.supportFinishAfterTransition() + } + return true + } + return super.dispatchKeyEvent(event) + } + } - progressBar.hide() - mp.isLooping = true - if (arguments!!.getBoolean(ARG_START_POSTPONED_TRANSITION)) { - videoView.start() - } - } + val trackSelector = DefaultTrackSelector(requireActivity()).apply { + setParameters(buildUponParameters().setMaxVideoSizeSd()) + } - if (arguments!!.getBoolean(ARG_START_POSTPONED_TRANSITION)) { - mediaActivity.onBringUp() - } - } + exoPlayer = SimpleExoPlayer.Builder(requireActivity()) + .setTrackSelector(trackSelector) + .build() + .also { player -> + videoView.player = player - private fun hideToolbarAfterDelay(delayMilliseconds: Long) { - handler.postDelayed(hideToolbar, delayMilliseconds) - } + val mediaItem = MediaItem.Builder() + .setUri(Uri.parse(url)) + .build() + player.setMediaItem(mediaItem) - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { - toolbar = activity!!.toolbar - mediaActivity = activity as ViewMediaActivity - return inflater.inflate(R.layout.fragment_view_video, container, false) - } + player.addListener(playbackStateListener) + player.seekTo(currentWindow, playbackPosition) + player.playWhenReady = playWhenReady - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - val attachment = arguments?.getParcelable(ARG_ATTACHMENT) - val url: String + player.prepare() + } - if (attachment == null) { - throw IllegalArgumentException("attachment has to be set") - } - url = attachment.url - isAudio = attachment.type == Attachment.Type.AUDIO - finalizeViewSetup(url, attachment.previewUrl, attachment.description) - } + videoView.requestFocus() - override fun onToolbarVisibilityChange(visible: Boolean) { - if (videoView == null || mediaDescription == null || !userVisibleHint) { - return - } + if(arguments!!.getBoolean(ARG_START_POSTPONED_TRANSITION)) { + mediaActivity.onBringUp() + } + } - isDescriptionVisible = showingDescription && visible - val alpha = if (isDescriptionVisible) 1.0f else 0.0f - if (isDescriptionVisible) { - // If to be visible, need to make visible immediately and animate alpha - mediaDescription.alpha = 0.0f - mediaDescription.visible(isDescriptionVisible) - } + private fun hideToolbarAfterDelay(delayMilliseconds: Long) { + handler.postDelayed(hideToolbar, delayMilliseconds) + } - mediaDescription.animate().alpha(alpha) - .setListener(object : AnimatorListenerAdapter() { - override fun onAnimationEnd(animation: Animator) { - mediaDescription?.visible(isDescriptionVisible) - animation.removeListener(this) - } - }) - .start() + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + toolbar = activity!!.toolbar + mediaActivity = activity as ViewMediaActivity + return inflater.inflate(R.layout.fragment_view_video, container, false) + } - if (visible && videoView.isPlaying && !isAudio) { - hideToolbarAfterDelay(TOOLBAR_HIDE_DELAY_MS) - } else { - handler.removeCallbacks(hideToolbar) - } - } + override fun onStart() { + super.onStart() - override fun onTransitionEnd() { - } + val attachment = arguments?.getParcelable(ARG_ATTACHMENT) + ?: throw IllegalArgumentException("attachment has to be set") + + isAudio = (attachment.type == Attachment.Type.AUDIO) + finalizeViewSetup(attachment.url, attachment.previewUrl, attachment.description) + } + + override fun onToolbarVisibilityChange(visible: Boolean) { + if(videoView == null || mediaDescription == null || !userVisibleHint) { + return + } + + isDescriptionVisible = showingDescription && visible + val alpha = if(isDescriptionVisible) 1.0f else 0.0f + if(isDescriptionVisible) { + // If to be visible, need to make visible immediately and animate alpha + mediaDescription.alpha = 0.0f + mediaDescription.visible(isDescriptionVisible) + } + + mediaDescription.animate().alpha(alpha) + .setListener(object : AnimatorListenerAdapter() { + override fun onAnimationEnd(animation: Animator) { + mediaDescription?.visible(isDescriptionVisible) + animation.removeListener(this) + } + }) + .start() + + if(visible && (videoView.player?.isPlaying == true) && !isAudio) { + hideToolbarAfterDelay(TOOLBAR_HIDE_DELAY_MS) + } else { + handler.removeCallbacks(hideToolbar) + } + } + + override fun onTransitionEnd() { + } + + override fun onPause() { + super.onPause() + + releasePlayer() + } + + override fun onStop() { + super.onStop() + + releasePlayer() + } + + private fun releasePlayer() { + exoPlayer?.run { + playbackPosition = this.currentPosition + currentWindow = this.currentWindowIndex + playWhenReady = this.playWhenReady + removeListener(playbackStateListener) + release() + } + exoPlayer = null + } + + private fun playbackStateListener() = object : Player.Listener { + + override fun onPlaybackStateChanged(playbackState: Int) { + when(playbackState) { + Player.STATE_BUFFERING -> { + progressBar.visibility = View.VISIBLE + } + Player.STATE_READY, + Player.STATE_ENDED -> { + progressBar.visibility = View.GONE + } + else -> { + } + } + } + + override fun onPlayerError(error: PlaybackException) { + Timber.e(error.errorCodeName) + } + } } diff --git a/husky/app/src/main/res/layout/fragment_view_video.xml b/husky/app/src/main/res/layout/fragment_view_video.xml index 180481c..fac0534 100644 --- a/husky/app/src/main/res/layout/fragment_view_video.xml +++ b/husky/app/src/main/res/layout/fragment_view_video.xml @@ -1,44 +1,44 @@ + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:id="@+id/videoContainer" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:clickable="true" + android:focusable="true"> - + - + - + - \ No newline at end of file + diff --git a/husky/buildSrc/src/main/kotlin/AppLibs.kt b/husky/buildSrc/src/main/kotlin/AppLibs.kt index 9e66fd8..78359a8 100644 --- a/husky/buildSrc/src/main/kotlin/AppLibs.kt +++ b/husky/buildSrc/src/main/kotlin/AppLibs.kt @@ -1,44 +1,72 @@ object ApplicationLibs { private object Versions { + const val androidImageCropper = "2.8.0" const val appcompat = "1.2.0" + const val autodispose = "1.4.0" + const val bigImageViewer = "1.7.0" + const val browser = "1.3.0" + const val cardView = "1.0.0" + const val conscryptAndroid = "2.5.1" const val constraintlayout = "2.1.0" const val coreKtx = "1.3.2" const val dagger = "2.30.1" + const val emoji = "1.1.0" + const val exifInterface = "1.3.2" + const val exoplayer = "2.15.0" + const val filemojiCompat = "1.0.17" + const val flexbox = "2.0.1" + const val fragmentKtx = "1.2.5" const val glide = "4.11.0" + const val glideImage = "1.8.0" const val lifecycle = "2.2.0" + const val markdownEdit = "1.0.0" const val materialDesign = "1.4.0" const val materialDrawer = "8.2.0" + const val materialDrawerTypeface = "3.0.1.4.original-kotlin@aar" + const val pagingRuntimeKtx = "2.1.2" + const val preferenceKtx = "1.1.1" const val okhttpVersion = "4.9.0" + const val recyclerView = "1.1.0" const val retrofit = "2.9.0" const val room = "2.2.5" + const val rxAndroid = "2.1.1" + const val rxJava = "2.2.20" + const val rxKotlin = "2.4.0" + const val shareTarget = "1.0.0" const val simplestack = "2.6.2" const val simplestackExt = "2.2.2" + const val sparkButton = "4.1.0" + const val swipeRefreshLayout = "1.1.0" const val timber = "4.7.1" + const val viewpager2 = "1.0.0" + const val workRuntime = "2.4.0" } object AndroidX { const val appCompat = "androidx.appcompat:appcompat:${Versions.appcompat}" - const val browser = "androidx.browser:browser:1.3.0" - const val cardView = "androidx.cardview:cardview:1.0.0" + const val browser = "androidx.browser:browser:${Versions.browser}" + const val cardView = "androidx.cardview:cardview:${Versions.cardView}" const val constraintLayout = "androidx.constraintlayout:constraintlayout:${Versions.constraintlayout}" const val coreKtx = "androidx.core:core-ktx:${Versions.coreKtx}" - const val exifInterface = "androidx.exifinterface:exifinterface:1.3.2" - const val emoji = "androidx.emoji:emoji:1.1.0" - const val emojiAppCompat = "androidx.emoji:emoji-appcompat:1.1.0" - const val emojiBundled = "androidx.emoji:emoji-bundled:1.1.0" - const val fragmentKtx = "androidx.fragment:fragment-ktx:1.2.5" - const val pagingRuntimeKtx = "androidx.paging:paging-runtime-ktx:2.1.2" - const val preferenceKtx = "androidx.preference:preference-ktx:1.1.1" - const val recyclerView = "androidx.recyclerview:recyclerview:1.1.0" + const val emoji = "androidx.emoji:emoji:${Versions.emoji}" + const val emojiAppCompat = "androidx.emoji:emoji-appcompat:${Versions.emoji}" + const val emojiBundled = "androidx.emoji:emoji-bundled:${Versions.emoji}" + const val exifInterface = "androidx.exifinterface:exifinterface:${Versions.exifInterface}" + const val fragmentKtx = "androidx.fragment:fragment-ktx:${Versions.fragmentKtx}" + const val pagingRuntimeKtx = + "androidx.paging:paging-runtime-ktx:${Versions.pagingRuntimeKtx}" + const val preferenceKtx = "androidx.preference:preference-ktx:${Versions.preferenceKtx}" + const val recyclerView = "androidx.recyclerview:recyclerview:${Versions.recyclerView}" const val roomCompiler = "androidx.room:room-compiler:${Versions.room}" const val roomRuntime = "androidx.room:room-runtime:${Versions.room}" const val roomRxJava = "androidx.room:room-rxjava2:${Versions.room}" - const val shareTarget = "androidx.sharetarget:sharetarget:1.0.0" - const val swipeRefreshLayout = "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0" - const val viewpager2 = "androidx.viewpager2:viewpager2:1.0.0" - const val workRuntime = "androidx.work:work-runtime:2.4.0" + const val shareTarget = "androidx.sharetarget:sharetarget:${Versions.shareTarget}" + const val swipeRefreshLayout = + "androidx.swiperefreshlayout:swiperefreshlayout:${Versions.swipeRefreshLayout}" + const val viewpager2 = "androidx.viewpager2:viewpager2:${Versions.viewpager2}" + const val workRuntime = "androidx.work:work-runtime:${Versions.workRuntime}" object Lifecycle { const val liveDataKtx = @@ -65,7 +93,8 @@ object ApplicationLibs { } object Google { - const val flexBox = "com.google.android:flexbox:2.0.1" + const val flexbox = "com.google.android:flexbox:${Versions.flexbox}" + const val exoplayer = "com.google.android.exoplayer:exoplayer:${Versions.exoplayer}" const val materialDesign = "com.google.android.material:material:${Versions.materialDesign}" } @@ -76,9 +105,9 @@ object ApplicationLibs { } object RxJava { - const val rxAndroid = "io.reactivex.rxjava2:rxandroid:2.1.1" - const val rxJava = "io.reactivex.rxjava2:rxjava:2.2.20" - const val rxKotlin = "io.reactivex.rxjava2:rxkotlin:2.4.0" + const val rxAndroid = "io.reactivex.rxjava2:rxandroid:${Versions.rxAndroid}" + const val rxJava = "io.reactivex.rxjava2:rxjava:${Versions.rxJava}" + const val rxKotlin = "io.reactivex.rxjava2:rxkotlin:${Versions.rxKotlin}" } object SimpleStack { @@ -98,21 +127,23 @@ object ApplicationLibs { const val okhttpBrotli = "com.squareup.okhttp3:okhttp-brotli:${Versions.okhttpVersion}" } - const val androidImageCropper = "com.theartofdev.edmodo:android-image-cropper:2.8.0" - const val autodispose = "com.uber.autodispose:autodispose:1.4.0" + const val androidImageCropper = + "com.theartofdev.edmodo:android-image-cropper:${Versions.androidImageCropper}" + const val autodispose = "com.uber.autodispose:autodispose:${Versions.autodispose}" const val autodisposeAndroidArchComp = - "com.uber.autodispose:autodispose-android-archcomponents:1.4.0" - const val bigImageViewer = "com.github.piasy:BigImageViewer:1.7.0" - const val conscryptAndroid = "org.conscrypt:conscrypt-android:2.5.1" - const val filemojiCompat = "de.c1710:filemojicompat:1.0.17" - const val glideImage = "com.github.piasy:GlideImageLoader:1.8.0" - const val glideImageViewFactory = "com.github.piasy:GlideImageViewFactory:1.8.0" - const val markdownEdit = "com.github.Tunous:MarkdownEdit:1.0.0" + "com.uber.autodispose:autodispose-android-archcomponents:${Versions.autodispose}" + const val bigImageViewer = "com.github.piasy:BigImageViewer:${Versions.bigImageViewer}" + const val conscryptAndroid = "org.conscrypt:conscrypt-android:${Versions.conscryptAndroid}" + const val filemojiCompat = "de.c1710:filemojicompat:${Versions.filemojiCompat}" + const val glideImage = "com.github.piasy:GlideImageLoader:${Versions.glideImage}" + const val glideImageViewFactory = + "com.github.piasy:GlideImageViewFactory:${Versions.glideImage}" + const val markdownEdit = "com.github.Tunous:MarkdownEdit:${Versions.markdownEdit}" const val materialDrawer = "com.mikepenz:materialdrawer:${Versions.materialDrawer}" const val materialDrawerIconics = "com.mikepenz:materialdrawer-iconics:${Versions.materialDrawer}" const val materialDrawerTypeface = - "com.mikepenz:google-material-typeface:3.0.1.4.original-kotlin@aar" - const val sparkButton = "com.github.connyduck:sparkbutton:4.1.0" + "com.mikepenz:google-material-typeface:${Versions.materialDrawerTypeface}" + const val sparkButton = "com.github.connyduck:sparkbutton:${Versions.sparkButton}" const val timber = "com.jakewharton.timber:timber:${Versions.timber}" } diff --git a/husky/gradlew b/husky/gradlew old mode 100755 new mode 100644