mirror of
https://github.com/AeThex-Corporation/AeThex-OS.git
synced 2026-04-18 06:17:21 +00:00
- ModuleManager: Central tracking for installed marketplace modules - DataAnalyzerWidget: Real-time CPU/RAM/Battery/Storage widget (unlocked by Data Analyzer module) - BottomNavBar: Navigation bar for Projects/Chat/Marketplace/Settings - RootShell: Real root command execution utility - TerminalActivity: Full root shell with neofetch, sysinfo, real Linux commands - Terminal Pro module: Adds aliases (ll, la, h), command history - ArcadeActivity + SnakeGame: Pixel Arcade module unlocks retro games - fade_in/fade_out animations for smooth transitions
244 lines
9.9 KiB
Java
244 lines
9.9 KiB
Java
package com.aethex.os;
|
|
|
|
import android.animation.Animator;
|
|
import android.animation.AnimatorListenerAdapter;
|
|
import android.animation.ObjectAnimator;
|
|
import android.animation.ValueAnimator;
|
|
import android.app.Activity;
|
|
import android.graphics.Color;
|
|
import android.graphics.Typeface;
|
|
import android.graphics.drawable.GradientDrawable;
|
|
import android.os.Handler;
|
|
import android.os.Looper;
|
|
import android.util.TypedValue;
|
|
import android.view.Gravity;
|
|
import android.view.View;
|
|
import android.view.ViewGroup;
|
|
import android.view.animation.AccelerateDecelerateInterpolator;
|
|
import android.view.animation.LinearInterpolator;
|
|
import android.widget.FrameLayout;
|
|
import android.widget.LinearLayout;
|
|
import android.widget.TextView;
|
|
|
|
import androidx.core.content.res.ResourcesCompat;
|
|
|
|
/**
|
|
* Fullscreen overlay animation for clearance switching.
|
|
* Shows a cinematic 5-step animation: fade-in → spinner → text → progress line → fade-out.
|
|
*/
|
|
public class ClearanceSwitchOverlay {
|
|
|
|
public interface Callback {
|
|
void onSwitchComplete();
|
|
}
|
|
|
|
private static final String OVERLAY_TAG = "clearance_switch_overlay";
|
|
|
|
/**
|
|
* Shows the clearance switch overlay animation.
|
|
*
|
|
* @param activity The current activity
|
|
* @param targetMode The clearance mode being switched to (ThemeManager.CLEARANCE_CORP or CLEARANCE_FOUNDATION)
|
|
* @param callback Called when animation completes and theme should be applied
|
|
*/
|
|
public static void show(Activity activity, String targetMode, Callback callback) {
|
|
if (activity == null || activity.isFinishing() || activity.isDestroyed()) {
|
|
if (callback != null) callback.onSwitchComplete();
|
|
return;
|
|
}
|
|
|
|
activity.runOnUiThread(() -> {
|
|
// Remove any existing overlay
|
|
FrameLayout decorView = (FrameLayout) activity.getWindow().getDecorView();
|
|
View existing = decorView.findViewWithTag(OVERLAY_TAG);
|
|
if (existing != null) {
|
|
decorView.removeView(existing);
|
|
}
|
|
|
|
// Build the overlay
|
|
FrameLayout overlay = createOverlay(activity, targetMode);
|
|
decorView.addView(overlay);
|
|
|
|
// Run the 5-step animation
|
|
runAnimation(activity, overlay, targetMode, callback);
|
|
});
|
|
}
|
|
|
|
private static FrameLayout createOverlay(Activity activity, String targetMode) {
|
|
int bgColor = ThemeManager.getSwitchOverlayBackground(targetMode);
|
|
int spinnerColor = ThemeManager.getSwitchSpinnerColor(targetMode);
|
|
String label = ThemeManager.getSwitchLabel(targetMode);
|
|
|
|
FrameLayout overlay = new FrameLayout(activity);
|
|
overlay.setTag(OVERLAY_TAG);
|
|
overlay.setLayoutParams(new FrameLayout.LayoutParams(
|
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
|
ViewGroup.LayoutParams.MATCH_PARENT));
|
|
overlay.setBackgroundColor(bgColor);
|
|
overlay.setAlpha(0f);
|
|
overlay.setClickable(true); // Block touches below
|
|
|
|
// Center content container
|
|
LinearLayout center = new LinearLayout(activity);
|
|
center.setOrientation(LinearLayout.VERTICAL);
|
|
center.setGravity(Gravity.CENTER);
|
|
FrameLayout.LayoutParams centerParams = new FrameLayout.LayoutParams(
|
|
ViewGroup.LayoutParams.WRAP_CONTENT,
|
|
ViewGroup.LayoutParams.WRAP_CONTENT);
|
|
centerParams.gravity = Gravity.CENTER;
|
|
center.setLayoutParams(centerParams);
|
|
|
|
// Spinner ring (circular border)
|
|
View spinner = new View(activity);
|
|
int spinnerSize = dpToPx(activity, 48);
|
|
LinearLayout.LayoutParams spinnerParams = new LinearLayout.LayoutParams(spinnerSize, spinnerSize);
|
|
spinnerParams.gravity = Gravity.CENTER_HORIZONTAL;
|
|
spinner.setLayoutParams(spinnerParams);
|
|
|
|
GradientDrawable spinnerBg = new GradientDrawable();
|
|
spinnerBg.setShape(GradientDrawable.OVAL);
|
|
spinnerBg.setColor(Color.TRANSPARENT);
|
|
spinnerBg.setStroke(dpToPx(activity, 3), spinnerColor);
|
|
spinner.setBackground(spinnerBg);
|
|
spinner.setAlpha(0f);
|
|
spinner.setTag("switch_spinner");
|
|
center.addView(spinner);
|
|
|
|
// Label text
|
|
TextView labelView = new TextView(activity);
|
|
labelView.setText(label);
|
|
labelView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14);
|
|
labelView.setTextColor(Color.argb((int) (255 * 0.8f), 255, 255, 255));
|
|
labelView.setLetterSpacing(0.2f);
|
|
|
|
try {
|
|
Typeface font = ResourcesCompat.getFont(activity, R.font.source_code_pro);
|
|
if (font != null) labelView.setTypeface(font, Typeface.BOLD);
|
|
} catch (Exception ignored) {
|
|
labelView.setTypeface(Typeface.MONOSPACE, Typeface.BOLD);
|
|
}
|
|
|
|
LinearLayout.LayoutParams labelParams = new LinearLayout.LayoutParams(
|
|
ViewGroup.LayoutParams.WRAP_CONTENT,
|
|
ViewGroup.LayoutParams.WRAP_CONTENT);
|
|
labelParams.gravity = Gravity.CENTER_HORIZONTAL;
|
|
labelParams.topMargin = dpToPx(activity, 20);
|
|
labelView.setLayoutParams(labelParams);
|
|
labelView.setAlpha(0f);
|
|
labelView.setTag("switch_label");
|
|
center.addView(labelView);
|
|
|
|
// Sub-label (mode name)
|
|
TextView subLabel = new TextView(activity);
|
|
String modeName = ThemeManager.CLEARANCE_CORP.equals(targetMode)
|
|
? "CORP CLEARANCE" : "FOUNDATION CLEARANCE";
|
|
subLabel.setText(modeName);
|
|
subLabel.setTextSize(TypedValue.COMPLEX_UNIT_SP, 10);
|
|
subLabel.setTextColor(spinnerColor);
|
|
|
|
try {
|
|
Typeface font = ResourcesCompat.getFont(activity, R.font.source_code_pro);
|
|
if (font != null) subLabel.setTypeface(font);
|
|
} catch (Exception ignored) {
|
|
subLabel.setTypeface(Typeface.MONOSPACE);
|
|
}
|
|
|
|
LinearLayout.LayoutParams subParams = new LinearLayout.LayoutParams(
|
|
ViewGroup.LayoutParams.WRAP_CONTENT,
|
|
ViewGroup.LayoutParams.WRAP_CONTENT);
|
|
subParams.gravity = Gravity.CENTER_HORIZONTAL;
|
|
subParams.topMargin = dpToPx(activity, 6);
|
|
subLabel.setLayoutParams(subParams);
|
|
subLabel.setAlpha(0f);
|
|
subLabel.setTag("switch_sub_label");
|
|
center.addView(subLabel);
|
|
|
|
overlay.addView(center);
|
|
|
|
// Bottom progress line
|
|
View progressLine = new View(activity);
|
|
int lineHeight = dpToPx(activity, 2);
|
|
FrameLayout.LayoutParams lineParams = new FrameLayout.LayoutParams(0, lineHeight);
|
|
lineParams.gravity = Gravity.BOTTOM;
|
|
progressLine.setLayoutParams(lineParams);
|
|
progressLine.setBackgroundColor(spinnerColor);
|
|
progressLine.setTag("switch_progress");
|
|
overlay.addView(progressLine);
|
|
|
|
return overlay;
|
|
}
|
|
|
|
private static void runAnimation(Activity activity, FrameLayout overlay,
|
|
String targetMode, Callback callback) {
|
|
Handler handler = new Handler(Looper.getMainLooper());
|
|
int spinnerColor = ThemeManager.getSwitchSpinnerColor(targetMode);
|
|
|
|
View spinner = overlay.findViewWithTag("switch_spinner");
|
|
View label = overlay.findViewWithTag("switch_label");
|
|
View subLabel = overlay.findViewWithTag("switch_sub_label");
|
|
View progress = overlay.findViewWithTag("switch_progress");
|
|
|
|
// Play switch sound
|
|
SoundManager.getInstance().play(SoundManager.Sound.SWITCH);
|
|
|
|
// Step 1: Fade in overlay (200ms)
|
|
overlay.animate().alpha(1f).setDuration(200).withEndAction(() -> {
|
|
|
|
// Step 2: Show spinner + spin (400ms)
|
|
spinner.setAlpha(1f);
|
|
spinner.setScaleX(0.5f);
|
|
spinner.setScaleY(0.5f);
|
|
spinner.animate().scaleX(1f).scaleY(1f).setDuration(300)
|
|
.setInterpolator(new AccelerateDecelerateInterpolator()).start();
|
|
|
|
ObjectAnimator rotation = ObjectAnimator.ofFloat(spinner, "rotation", 0f, 360f);
|
|
rotation.setDuration(800);
|
|
rotation.setRepeatCount(1);
|
|
rotation.setInterpolator(new LinearInterpolator());
|
|
rotation.start();
|
|
|
|
handler.postDelayed(() -> {
|
|
// Step 3: Show text (300ms)
|
|
label.animate().alpha(1f).setDuration(200).start();
|
|
subLabel.animate().alpha(1f).setDuration(200).setStartDelay(100).start();
|
|
|
|
handler.postDelayed(() -> {
|
|
// Step 4: Progress line sweeps across (600ms)
|
|
int screenWidth = activity.getWindow().getDecorView().getWidth();
|
|
ValueAnimator lineAnim = ValueAnimator.ofInt(0, screenWidth);
|
|
lineAnim.setDuration(600);
|
|
lineAnim.setInterpolator(new AccelerateDecelerateInterpolator());
|
|
lineAnim.addUpdateListener(anim -> {
|
|
int val = (int) anim.getAnimatedValue();
|
|
ViewGroup.LayoutParams lp = progress.getLayoutParams();
|
|
lp.width = val;
|
|
progress.setLayoutParams(lp);
|
|
});
|
|
lineAnim.start();
|
|
|
|
handler.postDelayed(() -> {
|
|
// Step 5: Fade out (300ms)
|
|
overlay.animate().alpha(0f).setDuration(300).withEndAction(() -> {
|
|
// Remove overlay
|
|
FrameLayout decorView = (FrameLayout) activity.getWindow().getDecorView();
|
|
decorView.removeView(overlay);
|
|
|
|
// Invoke callback
|
|
if (callback != null) {
|
|
callback.onSwitchComplete();
|
|
}
|
|
}).start();
|
|
}, 650);
|
|
|
|
}, 350);
|
|
}, 500);
|
|
|
|
}).start();
|
|
}
|
|
|
|
private static int dpToPx(Activity activity, float dp) {
|
|
return Math.round(TypedValue.applyDimension(
|
|
TypedValue.COMPLEX_UNIT_DIP, dp,
|
|
activity.getResources().getDisplayMetrics()));
|
|
}
|
|
}
|