mirror of
https://github.com/FBukovina/Atoll.git
synced 2026-10-27 15:14:33 +00:00
113 lines
4.2 KiB
Swift
113 lines
4.2 KiB
Swift
/*
|
|
* Atoll (DynamicIsland)
|
|
* Copyright (C) 2024-2026 Atoll Contributors
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
import SwiftUI
|
|
import Lottie
|
|
import LottieUI
|
|
import Defaults
|
|
|
|
struct IdleAnimationView: View {
|
|
@Default(.selectedIdleAnimation) var selectedAnimation
|
|
@Default(.animationTransformOverrides) var overrides
|
|
|
|
var body: some View {
|
|
Group {
|
|
if let animation = selectedAnimation {
|
|
AnimationContentView(animation: animation)
|
|
.id("\(animation.id)-\(overrides[animation.id.uuidString]?.hashValue ?? 0)") // Force recreation when override changes
|
|
} else {
|
|
// Fallback to original face if nothing selected
|
|
MinimalFaceFeatures(height: 20, width: 30)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Internal view that renders the actual animation content
|
|
private struct AnimationContentView: View {
|
|
let animation: CustomIdleAnimation
|
|
|
|
var body: some View {
|
|
let config = animation.getTransformConfig()
|
|
|
|
// Debug logging
|
|
let _ = print("🎨 [IdleAnimationView] Rendering animation: \(animation.name)")
|
|
let _ = print("🎨 [IdleAnimationView] Config: scale=\(config.scale), offset=(\(config.offsetX), \(config.offsetY)), opacity=\(config.opacity)")
|
|
|
|
switch animation.source {
|
|
case .lottieFile(let url):
|
|
LottieView(state: LUStateData(
|
|
type: .loadedFrom(url),
|
|
speed: animation.speed,
|
|
loopMode: config.loopMode.lottieLoopMode
|
|
))
|
|
.id(animation.id) // Force reload when animation changes
|
|
.frame(
|
|
width: config.cropWidth * config.scale,
|
|
height: config.cropHeight * config.scale
|
|
)
|
|
.offset(x: config.offsetX, y: config.offsetY)
|
|
.rotationEffect(.degrees(config.rotation))
|
|
.opacity(config.opacity)
|
|
.padding(.bottom, config.paddingBottom)
|
|
.frame(width: config.expandWithAnimation ? nil : 30, height: 20)
|
|
.clipped()
|
|
|
|
case .lottieURL(let url):
|
|
LottieView(state: LUStateData(
|
|
type: .loadedFrom(url),
|
|
speed: animation.speed,
|
|
loopMode: config.loopMode.lottieLoopMode
|
|
))
|
|
.id(animation.id) // Force reload when animation changes
|
|
.frame(
|
|
width: config.cropWidth * config.scale,
|
|
height: config.cropHeight * config.scale
|
|
)
|
|
.offset(x: config.offsetX, y: config.offsetY)
|
|
.rotationEffect(.degrees(config.rotation))
|
|
.opacity(config.opacity)
|
|
.padding(.bottom, config.paddingBottom)
|
|
.frame(width: config.expandWithAnimation ? nil : 30, height: 20)
|
|
.clipped()
|
|
|
|
case .builtInFace:
|
|
// Apply transforms to built-in face too!
|
|
MinimalFaceFeatures(height: 20, width: 30)
|
|
.frame(
|
|
width: config.cropWidth * config.scale,
|
|
height: config.cropHeight * config.scale
|
|
)
|
|
.offset(x: config.offsetX, y: config.offsetY)
|
|
.rotationEffect(.degrees(config.rotation))
|
|
.opacity(config.opacity)
|
|
.padding(.bottom, config.paddingBottom)
|
|
.frame(width: config.expandWithAnimation ? nil : 30, height: 20)
|
|
.clipped()
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: - Preview
|
|
#Preview {
|
|
ZStack {
|
|
Color.black
|
|
IdleAnimationView()
|
|
}
|
|
.frame(width: 100, height: 50)
|
|
}
|