mirror of
https://github.com/recloudstream/cloudstream.git
synced 2025-05-17 19:25:55 +08:00
refactor: convert monkey activity 🐒 into a fragment monke 🦍 (#1576)
* Turn monkey activity 🐒 into a fragment monke 🦍
This commit is contained in:
@ -196,11 +196,6 @@
|
|||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
|
||||||
android:name=".ui.EasterEggMonkeActivity"
|
|
||||||
android:exported="false"
|
|
||||||
android:noHistory="true" />
|
|
||||||
|
|
||||||
<receiver
|
<receiver
|
||||||
android:name=".receivers.VideoDownloadRestartReceiver"
|
android:name=".receivers.VideoDownloadRestartReceiver"
|
||||||
android:enabled="false"
|
android:enabled="false"
|
||||||
|
@ -1,97 +0,0 @@
|
|||||||
// https://github.com/googlecodelabs/android-kotlin-animation-property-animation/tree/master/begin
|
|
||||||
|
|
||||||
package com.lagradost.cloudstream3.ui
|
|
||||||
|
|
||||||
import android.animation.Animator
|
|
||||||
import android.animation.AnimatorListenerAdapter
|
|
||||||
import android.animation.AnimatorSet
|
|
||||||
import android.animation.ObjectAnimator
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.os.Handler
|
|
||||||
import android.view.View
|
|
||||||
import android.view.animation.AccelerateInterpolator
|
|
||||||
import android.view.animation.LinearInterpolator
|
|
||||||
import android.widget.FrameLayout
|
|
||||||
import androidx.activity.ComponentActivity
|
|
||||||
import androidx.appcompat.widget.AppCompatImageView
|
|
||||||
import androidx.core.view.isVisible
|
|
||||||
import com.lagradost.cloudstream3.R
|
|
||||||
import com.lagradost.cloudstream3.databinding.ActivityEasterEggMonkeBinding
|
|
||||||
|
|
||||||
class EasterEggMonkeActivity : ComponentActivity() {
|
|
||||||
|
|
||||||
lateinit var binding : ActivityEasterEggMonkeBinding
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
|
|
||||||
binding = ActivityEasterEggMonkeBinding.inflate(layoutInflater)
|
|
||||||
setContentView(binding.root)
|
|
||||||
|
|
||||||
val handler = Handler(mainLooper)
|
|
||||||
lateinit var runnable: Runnable
|
|
||||||
runnable = Runnable {
|
|
||||||
shower()
|
|
||||||
handler.postDelayed(runnable, 300)
|
|
||||||
}
|
|
||||||
handler.postDelayed(runnable, 1000)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun shower() {
|
|
||||||
|
|
||||||
val containerW = binding.frame.width
|
|
||||||
val containerH = binding.frame.height
|
|
||||||
var starW: Float = binding.monke.width.toFloat()
|
|
||||||
var starH: Float = binding.monke.height.toFloat()
|
|
||||||
|
|
||||||
val newStar = AppCompatImageView(this)
|
|
||||||
val idx = (monkeys.size * Math.random()).toInt()
|
|
||||||
newStar.setImageResource(monkeys[idx])
|
|
||||||
newStar.isVisible = true
|
|
||||||
newStar.layoutParams = FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT,
|
|
||||||
FrameLayout.LayoutParams.WRAP_CONTENT)
|
|
||||||
binding.frame.addView(newStar)
|
|
||||||
|
|
||||||
newStar.scaleX += Math.random().toFloat() * 1.5f
|
|
||||||
newStar.scaleY = newStar.scaleX
|
|
||||||
starW *= newStar.scaleX
|
|
||||||
starH *= newStar.scaleY
|
|
||||||
|
|
||||||
newStar.translationX = Math.random().toFloat() * containerW - starW / 2
|
|
||||||
|
|
||||||
val mover = ObjectAnimator.ofFloat(newStar, View.TRANSLATION_Y, -starH, containerH + starH)
|
|
||||||
mover.interpolator = AccelerateInterpolator(1f)
|
|
||||||
|
|
||||||
val rotator = ObjectAnimator.ofFloat(newStar, View.ROTATION,
|
|
||||||
(Math.random() * 1080).toFloat())
|
|
||||||
rotator.interpolator = LinearInterpolator()
|
|
||||||
|
|
||||||
val set = AnimatorSet()
|
|
||||||
set.playTogether(mover, rotator)
|
|
||||||
set.duration = (Math.random() * 1500 + 2500).toLong()
|
|
||||||
|
|
||||||
set.addListener(object : AnimatorListenerAdapter() {
|
|
||||||
override fun onAnimationEnd(animation: Animator) {
|
|
||||||
binding.frame.removeView(newStar)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
set.start()
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
val monkeys = listOf(
|
|
||||||
R.drawable.monke_benene,
|
|
||||||
R.drawable.monke_burrito,
|
|
||||||
R.drawable.monke_coco,
|
|
||||||
R.drawable.monke_cookie,
|
|
||||||
R.drawable.monke_flusdered,
|
|
||||||
R.drawable.monke_funny,
|
|
||||||
R.drawable.monke_like,
|
|
||||||
R.drawable.monke_party,
|
|
||||||
R.drawable.monke_sob,
|
|
||||||
R.drawable.monke_drink,
|
|
||||||
R.drawable.benene,
|
|
||||||
R.drawable.ic_launcher_foreground
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,189 @@
|
|||||||
|
package com.lagradost.cloudstream3.ui
|
||||||
|
|
||||||
|
import android.animation.Animator
|
||||||
|
import android.animation.AnimatorListenerAdapter
|
||||||
|
import android.animation.ObjectAnimator
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.MotionEvent
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.view.animation.AccelerateInterpolator
|
||||||
|
import android.view.animation.LinearInterpolator
|
||||||
|
import android.widget.FrameLayout
|
||||||
|
import android.widget.ImageView
|
||||||
|
import androidx.core.view.isVisible
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import com.lagradost.cloudstream3.R
|
||||||
|
import com.lagradost.cloudstream3.databinding.FragmentEasterEggMonkeBinding
|
||||||
|
import com.lagradost.cloudstream3.utils.UIHelper.hideSystemUI
|
||||||
|
import com.lagradost.cloudstream3.utils.UIHelper.showSystemUI
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.isActive
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlin.random.Random
|
||||||
|
|
||||||
|
class EasterEggMonkeFragment : Fragment() {
|
||||||
|
|
||||||
|
private var _binding: FragmentEasterEggMonkeBinding? = null
|
||||||
|
private val binding get() = _binding!!
|
||||||
|
|
||||||
|
// planet of monks
|
||||||
|
private val monkeys: List<Int> = listOf(
|
||||||
|
R.drawable.monke_benene,
|
||||||
|
R.drawable.monke_burrito,
|
||||||
|
R.drawable.monke_coco,
|
||||||
|
R.drawable.monke_cookie,
|
||||||
|
R.drawable.monke_flusdered,
|
||||||
|
R.drawable.monke_funny,
|
||||||
|
R.drawable.monke_like,
|
||||||
|
R.drawable.monke_party,
|
||||||
|
R.drawable.monke_sob,
|
||||||
|
R.drawable.monke_drink,
|
||||||
|
R.drawable.benene,
|
||||||
|
R.drawable.ic_launcher_foreground,
|
||||||
|
R.drawable.quick_novel_icon,
|
||||||
|
)
|
||||||
|
|
||||||
|
private val activeMonkeys = mutableListOf<ImageView>()
|
||||||
|
private var spawningJob: Job? = null
|
||||||
|
|
||||||
|
override fun onCreateView(
|
||||||
|
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
|
||||||
|
): View {
|
||||||
|
_binding = FragmentEasterEggMonkeBinding.inflate(layoutInflater)
|
||||||
|
return binding.root
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
|
activity?.hideSystemUI()
|
||||||
|
spawningJob = lifecycleScope.launch {
|
||||||
|
delay(1000)
|
||||||
|
while (isActive) {
|
||||||
|
spawnMonkey()
|
||||||
|
delay(500)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun spawnMonkey() {
|
||||||
|
val newMonkey = ImageView(context ?: return).apply {
|
||||||
|
setImageResource(monkeys.random())
|
||||||
|
isVisible = true
|
||||||
|
}
|
||||||
|
|
||||||
|
val initialScale = Random.nextFloat() * 1.5f + 0.5f
|
||||||
|
newMonkey.scaleX = initialScale
|
||||||
|
newMonkey.scaleY = initialScale
|
||||||
|
|
||||||
|
newMonkey.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED)
|
||||||
|
val monkeyW = newMonkey.measuredWidth * initialScale
|
||||||
|
val monkeyH = newMonkey.measuredHeight * initialScale
|
||||||
|
|
||||||
|
newMonkey.x = Random.nextFloat() * (binding.frame.width.toFloat() - monkeyW)
|
||||||
|
newMonkey.y = Random.nextFloat() * (binding.frame.height.toFloat() - monkeyH)
|
||||||
|
|
||||||
|
binding.frame.addView(newMonkey, FrameLayout.LayoutParams(
|
||||||
|
FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT
|
||||||
|
))
|
||||||
|
|
||||||
|
activeMonkeys.add(newMonkey)
|
||||||
|
|
||||||
|
newMonkey.alpha = 0f
|
||||||
|
ObjectAnimator.ofFloat(newMonkey, View.ALPHA, 0f, 1f).apply {
|
||||||
|
duration = Random.nextLong(1000, 2500)
|
||||||
|
interpolator = AccelerateInterpolator()
|
||||||
|
start()
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("ClickableViewAccessibility")
|
||||||
|
newMonkey.setOnTouchListener { view, event -> handleTouch(view, event) }
|
||||||
|
|
||||||
|
startFloatingAnimation(newMonkey)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun startFloatingAnimation(monkey: ImageView) {
|
||||||
|
val floatUpAnimator = ObjectAnimator.ofFloat(
|
||||||
|
monkey, View.TRANSLATION_Y, monkey.y, -monkey.height.toFloat()
|
||||||
|
).apply {
|
||||||
|
duration = Random.nextLong(8000, 15000)
|
||||||
|
interpolator = LinearInterpolator()
|
||||||
|
}
|
||||||
|
|
||||||
|
floatUpAnimator.addListener(object : AnimatorListenerAdapter() {
|
||||||
|
override fun onAnimationEnd(animation: Animator) {
|
||||||
|
// necessary check because binding becomes null but monkes are still moving until onDestroy()
|
||||||
|
if (_binding != null) {
|
||||||
|
binding.frame.removeView(monkey)
|
||||||
|
activeMonkeys.remove(monkey)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
floatUpAnimator.start()
|
||||||
|
monkey.tag = floatUpAnimator
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleTouch(view: View, event: MotionEvent): Boolean {
|
||||||
|
val monkey = view as ImageView
|
||||||
|
when (event.action) {
|
||||||
|
MotionEvent.ACTION_DOWN -> {
|
||||||
|
(monkey.tag as? ObjectAnimator)?.pause()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
MotionEvent.ACTION_MOVE -> {
|
||||||
|
// Update both X and Y positions properly
|
||||||
|
monkey.x = event.rawX - monkey.width / 2
|
||||||
|
monkey.y = event.rawY - monkey.height / 2
|
||||||
|
|
||||||
|
// Check if monkey touches the screen edge
|
||||||
|
if (isTouchingEdge(monkey)) {
|
||||||
|
removeMonkey(monkey)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
|
||||||
|
if (isTouchingEdge(monkey)) {
|
||||||
|
removeMonkey(monkey)
|
||||||
|
} else {
|
||||||
|
startFloatingAnimation(monkey)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isTouchingEdge(monkey: ImageView): Boolean {
|
||||||
|
return monkey.x <= 0 || monkey.x + monkey.width >= binding.frame.width ||
|
||||||
|
monkey.y <= 0 || monkey.y + monkey.height >= binding.frame.height
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun removeMonkey(monkey: ImageView) {
|
||||||
|
// Fade out and remove the monkey
|
||||||
|
ObjectAnimator.ofFloat(monkey, View.ALPHA, 1f, 0f).apply {
|
||||||
|
duration = 300
|
||||||
|
addListener(object : AnimatorListenerAdapter() {
|
||||||
|
override fun onAnimationEnd(animation: Animator) {
|
||||||
|
binding.frame.removeView(monkey)
|
||||||
|
activeMonkeys.remove(monkey)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
start()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroyView() {
|
||||||
|
super.onDestroyView()
|
||||||
|
activity?.showSystemUI()
|
||||||
|
spawningJob?.cancel()
|
||||||
|
_binding = null
|
||||||
|
}
|
||||||
|
}
|
@ -391,7 +391,7 @@ class SettingsGeneral : PreferenceFragmentCompat() {
|
|||||||
try {
|
try {
|
||||||
beneneCount++
|
beneneCount++
|
||||||
if (beneneCount%20 == 0) {
|
if (beneneCount%20 == 0) {
|
||||||
activity?.navigate(R.id.easterEggMonkeActivity)
|
activity?.navigate(R.id.action_navigation_settings_general_to_easterEggMonkeFragment)
|
||||||
}
|
}
|
||||||
settingsManager.edit().putInt(
|
settingsManager.edit().putInt(
|
||||||
getString(R.string.benene_count),
|
getString(R.string.benene_count),
|
||||||
|
@ -1,47 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!--
|
|
||||||
~ Copyright (C) 2019 The Android Open Source Project
|
|
||||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
~ you may not use this file except in compliance with the License.
|
|
||||||
~ You may obtain a copy of the License at
|
|
||||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
~ Unless required by applicable law or agreed to in writing, software
|
|
||||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
~ See the License for the specific language governing permissions and
|
|
||||||
~ limitations under the License.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
tools:context=".MainActivity">
|
|
||||||
|
|
||||||
<FrameLayout
|
|
||||||
android:id="@+id/frame"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="0dp"
|
|
||||||
android:background="@color/black"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
|
||||||
app:layout_constraintVertical_bias="0.0">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/monke"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center"
|
|
||||||
android:scaleX="3"
|
|
||||||
android:scaleY="3"
|
|
||||||
android:visibility="gone"
|
|
||||||
app:srcCompat="@drawable/monke_benene"
|
|
||||||
tools:visibility="visible" />
|
|
||||||
|
|
||||||
</FrameLayout>
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
15
app/src/main/res/layout/fragment_easter_egg_monke.xml
Normal file
15
app/src/main/res/layout/fragment_easter_egg_monke.xml
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/frame">
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
|
android:id="@+id/monke"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
</FrameLayout>
|
@ -184,7 +184,15 @@
|
|||||||
app:enterAnim="@anim/enter_anim"
|
app:enterAnim="@anim/enter_anim"
|
||||||
app:exitAnim="@anim/exit_anim"
|
app:exitAnim="@anim/exit_anim"
|
||||||
app:popEnterAnim="@anim/enter_anim"
|
app:popEnterAnim="@anim/enter_anim"
|
||||||
app:popExitAnim="@anim/exit_anim" />
|
app:popExitAnim="@anim/exit_anim" >
|
||||||
|
<action
|
||||||
|
android:id="@+id/action_navigation_settings_general_to_easterEggMonkeFragment"
|
||||||
|
app:destination="@id/easterEggMonkeFragment"
|
||||||
|
app:enterAnim="@anim/go_right"
|
||||||
|
app:exitAnim="@anim/go_left"
|
||||||
|
app:popEnterAnim="@anim/go_right"
|
||||||
|
app:popExitAnim="@anim/go_left" />
|
||||||
|
</fragment>
|
||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/navigation_settings_extensions"
|
android:id="@+id/navigation_settings_extensions"
|
||||||
@ -668,10 +676,9 @@
|
|||||||
android:label="AccountSelectActivity"
|
android:label="AccountSelectActivity"
|
||||||
tools:layout="@layout/activity_account_select" />
|
tools:layout="@layout/activity_account_select" />
|
||||||
|
|
||||||
<activity
|
<fragment
|
||||||
android:id="@+id/easterEggMonkeActivity"
|
android:id="@+id/easterEggMonkeFragment"
|
||||||
android:name="com.lagradost.cloudstream3.ui.EasterEggMonkeActivity"
|
android:name="com.lagradost.cloudstream3.ui.EasterEggMonkeFragment"
|
||||||
android:label="EasterEggMonkeActivity"
|
tools:layout="@layout/fragment_easter_egg_monke"
|
||||||
tools:layout="@layout/activity_easter_egg_monke" />
|
android:label="EasterEggMonkeFragment" />
|
||||||
|
|
||||||
</navigation>
|
</navigation>
|
||||||
|
Reference in New Issue
Block a user