diff --git a/mastodon/build.gradle b/mastodon/build.gradle index 41c7c8b3..ca3c8a78 100644 --- a/mastodon/build.gradle +++ b/mastodon/build.gradle @@ -9,8 +9,8 @@ android { applicationId "org.joinmastodon.android" minSdk 23 targetSdk 33 - versionCode 52 - versionName "1.2.1" + versionCode 53 + versionName "1.2.2" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" resConfigs "ar-rSA", "be-rBY", "bn-rBD", "bs-rBA", "ca-rES", "cs-rCZ", "da-rDK", "de-rDE", "el-rGR", "es-rES", "eu-rES", "fa-rIR", "fi-rFI", "fil-rPH", "fr-rFR", "ga-rIE", "gd-rGB", "gl-rES", "hi-rIN", "hr-rHR", "hu-rHU", "hy-rAM", "ig-rNG", "in-rID", "is-rIS", "it-rIT", "iw-rIL", "ja-rJP", "kab", "ko-rKR", "my-rMM", "nl-rNL", "no-rNO", "oc-rFR", "pl-rPL", "pt-rBR", "pt-rPT", "ro-rRO", "ru-rRU", "si-rLK", "sl-rSI", "sv-rSE", "th-rTH", "tr-rTR", "uk-rUA", "ur-rIN", "vi-rVN", "zh-rCN", "zh-rTW" } diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/SplashFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/SplashFragment.java index 1855f566..6b609745 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/SplashFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/SplashFragment.java @@ -1,20 +1,13 @@ package org.joinmastodon.android.fragments; -import android.graphics.Canvas; -import android.graphics.Paint; import android.graphics.drawable.ColorDrawable; -import android.graphics.drawable.Drawable; import android.os.Bundle; -import android.text.SpannableString; -import android.text.style.ReplacementSpan; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver; import android.view.WindowInsets; import android.widget.Button; -import android.widget.LinearLayout; -import android.widget.TextView; import org.joinmastodon.android.MastodonApp; import org.joinmastodon.android.R; @@ -28,10 +21,7 @@ import org.joinmastodon.android.ui.utils.UiUtils; import org.joinmastodon.android.ui.views.SizeListenerFrameLayout; import org.parceler.Parcels; -import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.recyclerview.widget.RecyclerView; -import androidx.viewpager2.widget.ViewPager2; import me.grishka.appkit.Nav; import me.grishka.appkit.api.Callback; import me.grishka.appkit.api.ErrorResponse; @@ -74,11 +64,12 @@ public class SplashFragment extends AppKitFragment{ artContainer=contentView.findViewById(R.id.art_container); blueFill=contentView.findViewById(R.id.blue_fill); greenFill=contentView.findViewById(R.id.green_fill); - motionEffect.addViewEffect(new InterpolatingMotionEffect.ViewEffect(contentView.findViewById(R.id.art_clouds), V.dp(-5), V.dp(5), V.dp(-5), V.dp(5))); - motionEffect.addViewEffect(new InterpolatingMotionEffect.ViewEffect(contentView.findViewById(R.id.art_right_hill), V.dp(-15), V.dp(25), V.dp(-10), V.dp(10))); - motionEffect.addViewEffect(new InterpolatingMotionEffect.ViewEffect(contentView.findViewById(R.id.art_left_hill), V.dp(-25), V.dp(15), V.dp(-15), V.dp(15))); - motionEffect.addViewEffect(new InterpolatingMotionEffect.ViewEffect(contentView.findViewById(R.id.art_center_hill), V.dp(-14), V.dp(14), V.dp(-5), V.dp(25))); - motionEffect.addViewEffect(new InterpolatingMotionEffect.ViewEffect(contentView.findViewById(R.id.art_plane_elephant), V.dp(-20), V.dp(12), V.dp(-20), V.dp(12))); + motionEffect.addViewEffect(new InterpolatingMotionEffect.ViewEffect(artClouds, V.dp(-5), V.dp(5), V.dp(-5), V.dp(5))); + motionEffect.addViewEffect(new InterpolatingMotionEffect.ViewEffect(artRightHill, V.dp(-15), V.dp(25), V.dp(-10), V.dp(10))); + motionEffect.addViewEffect(new InterpolatingMotionEffect.ViewEffect(artLeftHill, V.dp(-25), V.dp(15), V.dp(-15), V.dp(15))); + motionEffect.addViewEffect(new InterpolatingMotionEffect.ViewEffect(artCenterHill, V.dp(-14), V.dp(14), V.dp(-5), V.dp(25))); + motionEffect.addViewEffect(new InterpolatingMotionEffect.ViewEffect(artPlaneElephant, V.dp(-20), V.dp(12), V.dp(-20), V.dp(12))); + artContainer.setOnTouchListener(motionEffect); contentView.setSizeListener(new SizeListenerFrameLayout.OnSizeChangedListener(){ @Override diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/InterpolatingMotionEffect.java b/mastodon/src/main/java/org/joinmastodon/android/ui/InterpolatingMotionEffect.java index 1302aa65..4221d1c2 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/ui/InterpolatingMotionEffect.java +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/InterpolatingMotionEffect.java @@ -1,17 +1,25 @@ package org.joinmastodon.android.ui; +import android.annotation.SuppressLint; import android.content.Context; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; +import android.view.MotionEvent; import android.view.Surface; import android.view.View; import android.view.WindowManager; +import android.view.animation.PathInterpolator; import java.util.ArrayList; -public class InterpolatingMotionEffect implements SensorEventListener{ +import androidx.dynamicanimation.animation.DynamicAnimation; +import androidx.dynamicanimation.animation.FloatValueHolder; +import androidx.dynamicanimation.animation.SpringAnimation; +import androidx.dynamicanimation.animation.SpringForce; + +public class InterpolatingMotionEffect implements SensorEventListener, View.OnTouchListener{ private SensorManager sm; private WindowManager wm; @@ -20,6 +28,34 @@ public class InterpolatingMotionEffect implements SensorEventListener{ private Sensor accelerometer; private boolean accelerometerEnabled; private ArrayList views=new ArrayList<>(); + private float pitch, roll; + private float touchDownX, touchDownY, touchAddX, touchAddY, touchAddLastAnimX, touchAddLastAnimY; + private PathInterpolator touchInterpolator=new PathInterpolator(0.5f, 1f, 0.89f, 1f); + private SpringAnimation touchSpringX, touchSpringY; + private FloatValueHolder touchSpringXHolder=new FloatValueHolder(){ + @Override + public float getValue(){ + return touchAddX; + } + + @Override + public void setValue(float value){ + touchAddX=value; + updateEffects(); + } + }; + private FloatValueHolder touchSpringYHolder=new FloatValueHolder(){ + @Override + public float getValue(){ + return touchAddY; + } + + @Override + public void setValue(float value){ + touchAddY=value; + updateEffects(); + } + }; public InterpolatingMotionEffect(Context context){ sm=context.getSystemService(SensorManager.class); @@ -50,8 +86,8 @@ public class InterpolatingMotionEffect implements SensorEventListener{ float z=event.values[2]/SensorManager.GRAVITY_EARTH; - float pitch=(float) (Math.atan2(x, Math.sqrt(y*y+z*z))/Math.PI*2.0); - float roll=(float) (Math.atan2(y, Math.sqrt(x*x+z*z))/Math.PI*2.0); + pitch=(float) (Math.atan2(x, Math.sqrt(y*y+z*z))/Math.PI*2.0); + roll=(float) (Math.atan2(y, Math.sqrt(x*x+z*z))/Math.PI*2.0); switch(rotation){ case Surface.ROTATION_0: @@ -88,9 +124,7 @@ public class InterpolatingMotionEffect implements SensorEventListener{ }else if(roll<-1f){ roll=-2f-roll; } - for(ViewEffect view:views){ - view.update(pitch, roll); - } + updateEffects(); } @Override @@ -110,6 +144,62 @@ public class InterpolatingMotionEffect implements SensorEventListener{ views.clear(); } + @SuppressLint("ClickableViewAccessibility") + @Override + public boolean onTouch(View v, MotionEvent ev){ + switch(ev.getAction()){ + case MotionEvent.ACTION_DOWN -> { + if(touchSpringX!=null){ + touchAddLastAnimX=touchAddX; + touchSpringX.cancel(); + touchSpringX=null; + }else{ + touchAddLastAnimX=0; + } + if(touchSpringY!=null){ + touchAddLastAnimY=touchAddY; + touchSpringY.cancel(); + touchSpringY=null; + }else{ + touchAddLastAnimY=0; + } + touchDownX=ev.getX(); + touchDownY=ev.getY(); + } + case MotionEvent.ACTION_MOVE -> { + touchAddX=touchInterpolator.getInterpolation(Math.min(1f, Math.abs((ev.getX()-touchDownX)/(v.getWidth()/2f)))); + touchAddY=touchInterpolator.getInterpolation(Math.min(1f, Math.abs((ev.getY()-touchDownY)/(v.getHeight()/2f)))); + if(ev.getX()>touchDownX) + touchAddX=-touchAddX; + if(ev.getY() { + touchSpringX=new SpringAnimation(touchSpringXHolder, 0f); + touchSpringX.setMinimumVisibleChange(0.01f); + touchSpringX.getSpring().setStiffness(SpringForce.STIFFNESS_LOW).setDampingRatio(0.85f); + touchSpringX.addEndListener((animation, canceled, value, velocity)->touchSpringX=null); + touchSpringX.start(); + touchSpringY=new SpringAnimation(touchSpringYHolder, 0f); + touchSpringY.setMinimumVisibleChange(0.01f); + touchSpringY.getSpring().setStiffness(SpringForce.STIFFNESS_LOW).setDampingRatio(0.85f); + touchSpringY.addEndListener((animation, canceled, value, velocity)->touchSpringY=null); + touchSpringY.start(); + updateEffects(); + } + } + return true; + } + + private void updateEffects(){ + for(ViewEffect view:views){ + view.update(Math.min(1f, Math.max(-1f, pitch+touchAddX)), Math.min(1f, Math.max(-1f, roll+touchAddY))); + } + } + public static class ViewEffect{ private View view; private float minX, maxX, minY, maxY;