Files
sendico/frontend/pweb/lib/pages/settings/widgets/image.dart
2025-11-13 15:06:15 +03:00

113 lines
3.6 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter_settings_ui/flutter_settings_ui.dart';
import 'package:image_picker/image_picker.dart';
import 'package:pweb/utils/error/snackbar.dart';
import 'package:pweb/generated/i18n/app_localizations.dart';
class ImageTile extends AbstractSettingsTile {
final String? imageUrl;
final double? maxWidth;
final double? maxHeight;
final String? imageUpdateError;
final Future<void> Function(XFile?) onUpdate;
final String? title;
final String? description;
final Widget? imagePreview;
final double previewWidth;
final double previewHeight;
const ImageTile({
super.key,
required this.imageUrl,
this.maxWidth,
this.maxHeight,
this.imageUpdateError,
required this.onUpdate,
this.title,
this.description,
this.imagePreview,
this.previewHeight = 40.0,
this.previewWidth = 40.0,
});
Future<void> _pickImage(BuildContext context) async {
final picker = ImagePicker();
final locs = AppLocalizations.of(context)!;
final sm = ScaffoldMessenger.of(context);
final picked = await picker.pickImage(
source: ImageSource.gallery,
maxWidth: maxWidth,
maxHeight: maxHeight,
);
if (picked == null) return;
try {
await onUpdate(picked);
if (imageUrl != null) {
CachedNetworkImage.evictFromCache(imageUrl!);
}
} catch (e) {
notifyUserOfErrorX(
scaffoldMessenger: sm,
errorSituation: imageUpdateError ?? locs.settingsImageUpdateError,
exception: e,
appLocalizations: locs,
);
}
}
@override
Widget build(BuildContext context) => SettingsTile.navigation(
leading: imagePreview ??
ClipRRect(
borderRadius: BorderRadius.circular(0.1 * (previewWidth < previewHeight ? previewWidth : previewHeight)),
child: imageUrl != null
? CachedNetworkImage(
imageUrl: imageUrl!,
width: previewWidth,
height: previewHeight,
fit: BoxFit.cover,
progressIndicatorBuilder: (ctx, url, downloadProgress) {
// compute 10% of the smaller image dimension, but no more than 40px
final baseSize = min(previewWidth, previewHeight) * 0.1;
final indicatorSize = baseSize.clamp(0.0, 40.0);
return Center(
child: SizedBox(
width: indicatorSize,
height: indicatorSize,
child: CircularProgressIndicator(
value: downloadProgress.progress, // from 0.0 to 1.0
strokeWidth: max(indicatorSize * 0.1, 2.0), // 10% of size, but at least 2px so its visible
),
),
);
},
errorWidget: (ctx, url, err) => const Icon(Icons.error),
)
: Container(
width: previewWidth,
height: previewHeight,
color: Theme.of(context).colorScheme.surfaceContainerHighest,
child: Icon(
Icons.image_not_supported,
size: previewWidth * 0.6,
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
),
),
title: Text(title ?? AppLocalizations.of(context)!.settingsImageTitle),
description: Text(description ?? AppLocalizations.of(context)!.settingsImageHint),
onPressed: (_) => _pickImage(context),
);
}