mirror of
https://github.com/immich-app/immich
synced 2025-11-14 17:36:12 +00:00
chore(mobile): small visual fix and update (#17547)
* chore(mobile): small visual fix and update * update * update * remove design placeholder
This commit is contained in:
parent
1f18fe31f0
commit
ab2a7006f9
11 changed files with 168 additions and 39 deletions
|
|
@ -22,7 +22,6 @@ import 'package:immich_mobile/entities/album.entity.dart';
|
|||
import 'package:immich_mobile/entities/asset.entity.dart';
|
||||
import 'package:immich_mobile/providers/asset.provider.dart';
|
||||
import 'package:immich_mobile/providers/user.provider.dart';
|
||||
import 'package:immich_mobile/widgets/common/immich_loading_indicator.dart';
|
||||
import 'package:immich_mobile/widgets/common/immich_toast.dart';
|
||||
import 'package:immich_mobile/utils/immich_loading_overlay.dart';
|
||||
import 'package:immich_mobile/utils/selection_handlers.dart';
|
||||
|
|
@ -59,7 +58,7 @@ class MultiselectGrid extends HookConsumerWidget {
|
|||
final bool editEnabled;
|
||||
final Widget? emptyIndicator;
|
||||
Widget buildDefaultLoadingIndicator() =>
|
||||
const Center(child: ImmichLoadingIndicator());
|
||||
const Center(child: CircularProgressIndicator());
|
||||
|
||||
Widget buildEmptyIndicator() =>
|
||||
emptyIndicator ?? Center(child: const Text("no_assets_to_show").tr());
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:immich_mobile/widgets/common/immich_logo.dart';
|
||||
|
||||
class ImmichLoadingIndicator extends StatelessWidget {
|
||||
class ImmichLoadingIndicator extends HookWidget {
|
||||
final double? borderRadius;
|
||||
|
||||
const ImmichLoadingIndicator({
|
||||
|
|
@ -11,18 +12,109 @@ class ImmichLoadingIndicator extends StatelessWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final logoAnimationController = useAnimationController(
|
||||
duration: const Duration(seconds: 6),
|
||||
)
|
||||
..reverse()
|
||||
..repeat();
|
||||
|
||||
final borderAnimationController = useAnimationController(
|
||||
duration: const Duration(seconds: 6),
|
||||
)..repeat();
|
||||
|
||||
return Container(
|
||||
height: 60,
|
||||
width: 60,
|
||||
height: 80,
|
||||
width: 80,
|
||||
decoration: BoxDecoration(
|
||||
color: context.primaryColor.withAlpha(200),
|
||||
borderRadius: BorderRadius.circular(borderRadius ?? 10),
|
||||
color: Colors.transparent,
|
||||
borderRadius: BorderRadius.circular(borderRadius ?? 50),
|
||||
backgroundBlendMode: BlendMode.luminosity,
|
||||
),
|
||||
padding: const EdgeInsets.all(15),
|
||||
child: const CircularProgressIndicator(
|
||||
color: Colors.white,
|
||||
strokeWidth: 3,
|
||||
child: AnimatedBuilder(
|
||||
animation: borderAnimationController,
|
||||
builder: (context, child) {
|
||||
return CustomPaint(
|
||||
painter: GradientBorderPainter(
|
||||
animation: borderAnimationController.value,
|
||||
strokeWidth: 3,
|
||||
),
|
||||
child: child,
|
||||
);
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(15),
|
||||
child: RotationTransition(
|
||||
turns: logoAnimationController,
|
||||
child: const ImmichLogo(
|
||||
heroTag: 'logo',
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class GradientBorderPainter extends CustomPainter {
|
||||
final double animation;
|
||||
final double strokeWidth;
|
||||
final double opacity = 0.7;
|
||||
final colors = [
|
||||
const Color(0xFFFA2921),
|
||||
const Color(0xFFED79B5),
|
||||
const Color(0xFFFFB400),
|
||||
const Color(0xFF1E83F7),
|
||||
const Color(0xFF18C249),
|
||||
];
|
||||
|
||||
GradientBorderPainter({
|
||||
required this.animation,
|
||||
required this.strokeWidth,
|
||||
});
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
final center = Offset(size.width / 2, size.height / 2);
|
||||
final radius = min(size.width, size.height) / 2 - strokeWidth / 2;
|
||||
|
||||
// Create a sweep gradient that covers the entire circle
|
||||
final Rect rect = Rect.fromCircle(center: center, radius: radius);
|
||||
|
||||
// Create a paint with the gradient
|
||||
final paint = Paint()
|
||||
..style = PaintingStyle.stroke
|
||||
..strokeWidth = strokeWidth;
|
||||
|
||||
// Create a gradient that smoothly transitions between colors
|
||||
final shader = SweepGradient(
|
||||
// Use a fixed starting point and let matrix transformation handle rotation
|
||||
startAngle: 0,
|
||||
endAngle: 2 * 3.14159,
|
||||
colors: [
|
||||
// Repeat colors to ensure smooth transitions
|
||||
...colors.map((c) => c.withValues(alpha: opacity)),
|
||||
colors.first.withValues(alpha: opacity),
|
||||
],
|
||||
// Add evenly distributed stops
|
||||
stops: List.generate(
|
||||
colors.length + 1,
|
||||
(index) => index / colors.length,
|
||||
),
|
||||
tileMode: TileMode.clamp,
|
||||
// Use transformations to rotate the gradient
|
||||
transform: GradientRotation(-animation * 2 * 3.14159),
|
||||
).createShader(rect);
|
||||
|
||||
paint.shader = shader;
|
||||
|
||||
// Draw the circular border
|
||||
canvas.drawCircle(center, radius, paint);
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(GradientBorderPainter oldDelegate) {
|
||||
return animation != oldDelegate.animation;
|
||||
}
|
||||
|
||||
double min(double a, double b) => a < b ? a : b;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -303,7 +303,7 @@ class LoginForm extends HookConsumerWidget {
|
|||
),
|
||||
onPressed: () => context.pushRoute(const SettingsRoute()),
|
||||
icon: const Icon(Icons.settings_rounded),
|
||||
label: const SizedBox.shrink(),
|
||||
label: const Text(""),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 1),
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ import 'package:immich_mobile/widgets/settings/settings_button_list_tile.dart';
|
|||
import 'package:immich_mobile/widgets/settings/settings_sub_page_scaffold.dart';
|
||||
import 'package:immich_mobile/widgets/settings/settings_switch_list_tile.dart';
|
||||
import 'package:immich_mobile/utils/hooks/app_settings_update_hook.dart';
|
||||
import 'package:immich_mobile/widgets/common/immich_loading_indicator.dart';
|
||||
|
||||
class BackupSettings extends HookConsumerWidget {
|
||||
const BackupSettings({
|
||||
|
|
@ -59,7 +58,7 @@ class BackupSettings extends HookConsumerWidget {
|
|||
? const Column(
|
||||
children: [
|
||||
SizedBox(height: 20),
|
||||
Center(child: ImmichLoadingIndicator()),
|
||||
Center(child: CircularProgressIndicator()),
|
||||
SizedBox(height: 20),
|
||||
],
|
||||
)
|
||||
|
|
@ -83,9 +82,7 @@ class BackupSettings extends HookConsumerWidget {
|
|||
),
|
||||
buttonText: 'sync_albums'.tr(),
|
||||
child: isAlbumSyncInProgress.value
|
||||
? const CircularProgressIndicator.adaptive(
|
||||
strokeWidth: 2,
|
||||
)
|
||||
? const CircularProgressIndicator()
|
||||
: ElevatedButton(
|
||||
onPressed: syncAlbums,
|
||||
child: Text('sync'.tr()),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue