🐛 Fix share via image errored
This commit is contained in:
parent
115cb4adc1
commit
1c510d63fe
@ -22,12 +22,14 @@ class AttachmentItem extends StatelessWidget {
|
|||||||
final SnAttachment? data;
|
final SnAttachment? data;
|
||||||
final String? heroTag;
|
final String? heroTag;
|
||||||
final BoxFit fit;
|
final BoxFit fit;
|
||||||
|
final FilterQuality? filterQuality;
|
||||||
|
|
||||||
const AttachmentItem({
|
const AttachmentItem({
|
||||||
super.key,
|
super.key,
|
||||||
this.fit = BoxFit.cover,
|
this.fit = BoxFit.cover,
|
||||||
required this.data,
|
required this.data,
|
||||||
required this.heroTag,
|
required this.heroTag,
|
||||||
|
this.filterQuality,
|
||||||
});
|
});
|
||||||
|
|
||||||
Widget _buildContent(BuildContext context) {
|
Widget _buildContent(BuildContext context) {
|
||||||
@ -47,6 +49,7 @@ class AttachmentItem extends StatelessWidget {
|
|||||||
sn.getAttachmentUrl(data!.rid),
|
sn.getAttachmentUrl(data!.rid),
|
||||||
key: Key('attachment-${data!.rid}-$tag'),
|
key: Key('attachment-${data!.rid}-$tag'),
|
||||||
fit: fit,
|
fit: fit,
|
||||||
|
filterQuality: filterQuality,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
case 'video':
|
case 'video':
|
||||||
@ -83,13 +86,16 @@ class _AttachmentItemSensitiveBlur extends StatefulWidget {
|
|||||||
final Widget child;
|
final Widget child;
|
||||||
final bool isCompact;
|
final bool isCompact;
|
||||||
|
|
||||||
const _AttachmentItemSensitiveBlur({required this.child, this.isCompact = false});
|
const _AttachmentItemSensitiveBlur(
|
||||||
|
{required this.child, this.isCompact = false});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<_AttachmentItemSensitiveBlur> createState() => _AttachmentItemSensitiveBlurState();
|
State<_AttachmentItemSensitiveBlur> createState() =>
|
||||||
|
_AttachmentItemSensitiveBlurState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _AttachmentItemSensitiveBlurState extends State<_AttachmentItemSensitiveBlur> {
|
class _AttachmentItemSensitiveBlurState
|
||||||
|
extends State<_AttachmentItemSensitiveBlur> {
|
||||||
bool _doesShow = false;
|
bool _doesShow = false;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -124,10 +130,15 @@ class _AttachmentItemSensitiveBlurState extends State<_AttachmentItemSensitiveBl
|
|||||||
Text(
|
Text(
|
||||||
'sensitiveContentDescription',
|
'sensitiveContentDescription',
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
).tr().fontSize(14).textColor(Colors.white.withOpacity(0.8)),
|
)
|
||||||
|
.tr()
|
||||||
|
.fontSize(14)
|
||||||
|
.textColor(Colors.white.withOpacity(0.8)),
|
||||||
if (!widget.isCompact) const Gap(16),
|
if (!widget.isCompact) const Gap(16),
|
||||||
InkWell(
|
InkWell(
|
||||||
child: Text('sensitiveContentReveal').tr().textColor(Colors.white),
|
child: Text('sensitiveContentReveal')
|
||||||
|
.tr()
|
||||||
|
.textColor(Colors.white),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
setState(() => _doesShow = !_doesShow);
|
setState(() => _doesShow = !_doesShow);
|
||||||
},
|
},
|
||||||
@ -137,7 +148,9 @@ class _AttachmentItemSensitiveBlurState extends State<_AttachmentItemSensitiveBl
|
|||||||
).center(),
|
).center(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
).opacity(_doesShow ? 0 : 1, animate: true).animate(const Duration(milliseconds: 300), Curves.easeInOut),
|
)
|
||||||
|
.opacity(_doesShow ? 0 : 1, animate: true)
|
||||||
|
.animate(const Duration(milliseconds: 300), Curves.easeInOut),
|
||||||
if (_doesShow)
|
if (_doesShow)
|
||||||
Positioned(
|
Positioned(
|
||||||
top: 0,
|
top: 0,
|
||||||
@ -174,10 +187,12 @@ class _AttachmentItemContentVideo extends StatefulWidget {
|
|||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<_AttachmentItemContentVideo> createState() => _AttachmentItemContentVideoState();
|
State<_AttachmentItemContentVideo> createState() =>
|
||||||
|
_AttachmentItemContentVideoState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _AttachmentItemContentVideoState extends State<_AttachmentItemContentVideo> {
|
class _AttachmentItemContentVideoState
|
||||||
|
extends State<_AttachmentItemContentVideo> {
|
||||||
bool _showContent = false;
|
bool _showContent = false;
|
||||||
bool _showOriginal = false;
|
bool _showOriginal = false;
|
||||||
|
|
||||||
@ -188,7 +203,9 @@ class _AttachmentItemContentVideoState extends State<_AttachmentItemContentVideo
|
|||||||
setState(() => _showContent = true);
|
setState(() => _showContent = true);
|
||||||
MediaKit.ensureInitialized();
|
MediaKit.ensureInitialized();
|
||||||
final sn = context.read<SnNetworkProvider>();
|
final sn = context.read<SnNetworkProvider>();
|
||||||
final url = _showOriginal ? sn.getAttachmentUrl(widget.data.rid) : sn.getAttachmentUrl(widget.data.compressed!.rid);
|
final url = _showOriginal
|
||||||
|
? sn.getAttachmentUrl(widget.data.rid)
|
||||||
|
: sn.getAttachmentUrl(widget.data.compressed!.rid);
|
||||||
_videoPlayer = Player();
|
_videoPlayer = Player();
|
||||||
_videoController = VideoController(_videoPlayer!);
|
_videoController = VideoController(_videoPlayer!);
|
||||||
_videoPlayer!.open(Media(url), play: !widget.isAutoload);
|
_videoPlayer!.open(Media(url), play: !widget.isAutoload);
|
||||||
@ -201,7 +218,9 @@ class _AttachmentItemContentVideoState extends State<_AttachmentItemContentVideo
|
|||||||
final sn = context.read<SnNetworkProvider>();
|
final sn = context.read<SnNetworkProvider>();
|
||||||
_videoPlayer?.open(
|
_videoPlayer?.open(
|
||||||
Media(
|
Media(
|
||||||
_showOriginal ? sn.getAttachmentUrl(widget.data.rid) : sn.getAttachmentUrl(widget.data.compressed!.rid),
|
_showOriginal
|
||||||
|
? sn.getAttachmentUrl(widget.data.rid)
|
||||||
|
: sn.getAttachmentUrl(widget.data.compressed!.rid),
|
||||||
),
|
),
|
||||||
play: true,
|
play: true,
|
||||||
);
|
);
|
||||||
@ -283,7 +302,9 @@ class _AttachmentItemContentVideoState extends State<_AttachmentItemContentVideo
|
|||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
Duration(
|
Duration(
|
||||||
milliseconds: (widget.data.data['duration'] ?? 0).toInt() * 1000,
|
milliseconds:
|
||||||
|
(widget.data.data['duration'] ?? 0).toInt() *
|
||||||
|
1000,
|
||||||
).toString(),
|
).toString(),
|
||||||
style: GoogleFonts.robotoMono(
|
style: GoogleFonts.robotoMono(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
@ -346,7 +367,9 @@ class _AttachmentItemContentVideoState extends State<_AttachmentItemContentVideo
|
|||||||
MaterialDesktopCustomButton(
|
MaterialDesktopCustomButton(
|
||||||
iconSize: 24,
|
iconSize: 24,
|
||||||
onPressed: _toggleOriginal,
|
onPressed: _toggleOriginal,
|
||||||
icon: _showOriginal ? const Icon(Symbols.high_quality, size: 24) : const Icon(Symbols.sd, size: 24),
|
icon: _showOriginal
|
||||||
|
? const Icon(Symbols.high_quality, size: 24)
|
||||||
|
: const Icon(Symbols.sd, size: 24),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -354,8 +377,9 @@ class _AttachmentItemContentVideoState extends State<_AttachmentItemContentVideo
|
|||||||
child: Video(
|
child: Video(
|
||||||
controller: _videoController!,
|
controller: _videoController!,
|
||||||
aspectRatio: ratio,
|
aspectRatio: ratio,
|
||||||
controls:
|
controls: !kIsWeb && (Platform.isAndroid || Platform.isIOS)
|
||||||
!kIsWeb && (Platform.isAndroid || Platform.isIOS) ? MaterialVideoControls : MaterialDesktopVideoControls,
|
? MaterialVideoControls
|
||||||
|
: MaterialDesktopVideoControls,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -378,10 +402,12 @@ class _AttachmentItemContentAudio extends StatefulWidget {
|
|||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<_AttachmentItemContentAudio> createState() => _AttachmentItemContentAudioState();
|
State<_AttachmentItemContentAudio> createState() =>
|
||||||
|
_AttachmentItemContentAudioState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _AttachmentItemContentAudioState extends State<_AttachmentItemContentAudio> {
|
class _AttachmentItemContentAudioState
|
||||||
|
extends State<_AttachmentItemContentAudio> {
|
||||||
bool _showContent = false;
|
bool _showContent = false;
|
||||||
|
|
||||||
double? _draggingValue;
|
double? _draggingValue;
|
||||||
@ -552,8 +578,12 @@ class _AttachmentItemContentAudioState extends State<_AttachmentItemContentAudio
|
|||||||
overlayShape: SliderComponentShape.noOverlay,
|
overlayShape: SliderComponentShape.noOverlay,
|
||||||
),
|
),
|
||||||
child: Slider(
|
child: Slider(
|
||||||
secondaryTrackValue: _bufferedPosition.inMilliseconds.abs().toDouble(),
|
secondaryTrackValue: _bufferedPosition
|
||||||
value: _draggingValue?.abs() ?? _position.inMilliseconds.toDouble().abs(),
|
.inMilliseconds
|
||||||
|
.abs()
|
||||||
|
.toDouble(),
|
||||||
|
value: _draggingValue?.abs() ??
|
||||||
|
_position.inMilliseconds.toDouble().abs(),
|
||||||
min: 0,
|
min: 0,
|
||||||
max: math
|
max: math
|
||||||
.max(
|
.max(
|
||||||
@ -593,7 +623,9 @@ class _AttachmentItemContentAudioState extends State<_AttachmentItemContentAudio
|
|||||||
),
|
),
|
||||||
const Gap(16),
|
const Gap(16),
|
||||||
IconButton.filled(
|
IconButton.filled(
|
||||||
icon: _isPlaying ? const Icon(Symbols.pause) : const Icon(Symbols.play_arrow),
|
icon: _isPlaying
|
||||||
|
? const Icon(Symbols.pause)
|
||||||
|
: const Icon(Symbols.play_arrow),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
_audioPlayer!.playOrPause();
|
_audioPlayer!.playOrPause();
|
||||||
},
|
},
|
||||||
|
@ -21,6 +21,7 @@ class AttachmentList extends StatefulWidget {
|
|||||||
final double? minWidth;
|
final double? minWidth;
|
||||||
final double? maxWidth;
|
final double? maxWidth;
|
||||||
final EdgeInsets? padding;
|
final EdgeInsets? padding;
|
||||||
|
final FilterQuality? filterQuality;
|
||||||
|
|
||||||
const AttachmentList({
|
const AttachmentList({
|
||||||
super.key,
|
super.key,
|
||||||
@ -33,23 +34,27 @@ class AttachmentList extends StatefulWidget {
|
|||||||
this.minWidth,
|
this.minWidth,
|
||||||
this.maxWidth,
|
this.maxWidth,
|
||||||
this.padding,
|
this.padding,
|
||||||
|
this.filterQuality,
|
||||||
});
|
});
|
||||||
|
|
||||||
static const BorderRadius kDefaultRadius = BorderRadius.all(Radius.circular(8));
|
static const BorderRadius kDefaultRadius =
|
||||||
|
BorderRadius.all(Radius.circular(8));
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<AttachmentList> createState() => _AttachmentListState();
|
State<AttachmentList> createState() => _AttachmentListState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _AttachmentListState extends State<AttachmentList> {
|
class _AttachmentListState extends State<AttachmentList> {
|
||||||
late final List<String> heroTags = List.generate(widget.data.length, (_) => const Uuid().v4());
|
late final List<String> heroTags =
|
||||||
|
List.generate(widget.data.length, (_) => const Uuid().v4());
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return LayoutBuilder(
|
return LayoutBuilder(
|
||||||
builder: (context, layoutConstraints) {
|
builder: (context, layoutConstraints) {
|
||||||
final borderSide =
|
final borderSide = widget.bordered
|
||||||
widget.bordered ? BorderSide(width: 1, color: Theme.of(context).dividerColor) : BorderSide.none;
|
? BorderSide(width: 1, color: Theme.of(context).dividerColor)
|
||||||
|
: BorderSide.none;
|
||||||
final backgroundColor = Theme.of(context).colorScheme.surfaceContainer;
|
final backgroundColor = Theme.of(context).colorScheme.surfaceContainer;
|
||||||
final constraints = BoxConstraints(
|
final constraints = BoxConstraints(
|
||||||
minWidth: widget.minWidth ?? 80,
|
minWidth: widget.minWidth ?? 80,
|
||||||
@ -58,13 +63,13 @@ class _AttachmentListState extends State<AttachmentList> {
|
|||||||
|
|
||||||
if (widget.data.isEmpty) return const SizedBox.shrink();
|
if (widget.data.isEmpty) return const SizedBox.shrink();
|
||||||
if (widget.data.length == 1) {
|
if (widget.data.length == 1) {
|
||||||
final singleAspectRatio =
|
final singleAspectRatio = widget.data[0]?.data['ratio']?.toDouble() ??
|
||||||
widget.data[0]?.data['ratio']?.toDouble() ??
|
|
||||||
switch (widget.data[0]?.mimetype.split('/').firstOrNull) {
|
switch (widget.data[0]?.mimetype.split('/').firstOrNull) {
|
||||||
'audio' => 16 / 9,
|
'audio' => 16 / 9,
|
||||||
'video' => 16 / 9,
|
'video' => 16 / 9,
|
||||||
_ => 1,
|
_ => 1,
|
||||||
}.toDouble();
|
}
|
||||||
|
.toDouble();
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
padding: widget.padding ?? EdgeInsets.zero,
|
padding: widget.padding ?? EdgeInsets.zero,
|
||||||
@ -80,12 +85,18 @@ class _AttachmentListState extends State<AttachmentList> {
|
|||||||
),
|
),
|
||||||
child: ClipRRect(
|
child: ClipRRect(
|
||||||
borderRadius: AttachmentList.kDefaultRadius,
|
borderRadius: AttachmentList.kDefaultRadius,
|
||||||
child: AttachmentItem(data: widget.data[0], heroTag: heroTags[0], fit: widget.fit),
|
child: AttachmentItem(
|
||||||
|
data: widget.data[0],
|
||||||
|
heroTag: heroTags[0],
|
||||||
|
fit: widget.fit,
|
||||||
|
filterQuality: widget.filterQuality,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
if (widget.data.firstOrNull?.mediaType != SnMediaType.image) return;
|
if (widget.data.firstOrNull?.mediaType != SnMediaType.image)
|
||||||
|
return;
|
||||||
context.pushTransparentRoute(
|
context.pushTransparentRoute(
|
||||||
AttachmentZoomView(
|
AttachmentZoomView(
|
||||||
data: widget.data.where((ele) => ele != null).cast(),
|
data: widget.data.where((ele) => ele != null).cast(),
|
||||||
@ -100,8 +111,10 @@ class _AttachmentListState extends State<AttachmentList> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
final fullOfImage =
|
final fullOfImage = widget.data
|
||||||
widget.data.where((ele) => ele?.mediaType == SnMediaType.image).length == widget.data.length;
|
.where((ele) => ele?.mediaType == SnMediaType.image)
|
||||||
|
.length ==
|
||||||
|
widget.data.length;
|
||||||
|
|
||||||
if (widget.gridded && fullOfImage) {
|
if (widget.gridded && fullOfImage) {
|
||||||
return Container(
|
return Container(
|
||||||
@ -117,29 +130,36 @@ class _AttachmentListState extends State<AttachmentList> {
|
|||||||
crossAxisCount: math.min(widget.data.length, 2),
|
crossAxisCount: math.min(widget.data.length, 2),
|
||||||
crossAxisSpacing: 4,
|
crossAxisSpacing: 4,
|
||||||
mainAxisSpacing: 4,
|
mainAxisSpacing: 4,
|
||||||
children:
|
children: widget.data
|
||||||
widget.data
|
.mapIndexed(
|
||||||
.mapIndexed(
|
(idx, ele) => GestureDetector(
|
||||||
(idx, ele) => GestureDetector(
|
child: Container(
|
||||||
child: Container(
|
constraints: constraints,
|
||||||
constraints: constraints,
|
child: AttachmentItem(
|
||||||
child: AttachmentItem(data: ele, heroTag: heroTags[idx], fit: BoxFit.cover),
|
data: ele,
|
||||||
),
|
heroTag: heroTags[idx],
|
||||||
onTap: () {
|
fit: BoxFit.cover,
|
||||||
if (widget.data[idx]!.mediaType != SnMediaType.image) return;
|
filterQuality: widget.filterQuality,
|
||||||
context.pushTransparentRoute(
|
|
||||||
AttachmentZoomView(
|
|
||||||
data: widget.data.where((ele) => ele != null).cast(),
|
|
||||||
initialIndex: idx,
|
|
||||||
heroTags: heroTags,
|
|
||||||
),
|
|
||||||
backgroundColor: Colors.black.withOpacity(0.7),
|
|
||||||
rootNavigator: true,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
)
|
),
|
||||||
.toList(),
|
onTap: () {
|
||||||
|
if (widget.data[idx]!.mediaType != SnMediaType.image)
|
||||||
|
return;
|
||||||
|
context.pushTransparentRoute(
|
||||||
|
AttachmentZoomView(
|
||||||
|
data: widget.data
|
||||||
|
.where((ele) => ele != null)
|
||||||
|
.cast(),
|
||||||
|
initialIndex: idx,
|
||||||
|
heroTags: heroTags,
|
||||||
|
),
|
||||||
|
backgroundColor: Colors.black.withOpacity(0.7),
|
||||||
|
rootNavigator: true,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.toList(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -156,22 +176,26 @@ class _AttachmentListState extends State<AttachmentList> {
|
|||||||
child: ClipRRect(
|
child: ClipRRect(
|
||||||
borderRadius: AttachmentList.kDefaultRadius,
|
borderRadius: AttachmentList.kDefaultRadius,
|
||||||
child: Column(
|
child: Column(
|
||||||
children:
|
children: widget.data
|
||||||
widget.data
|
.mapIndexed(
|
||||||
.mapIndexed(
|
(idx, ele) => GestureDetector(
|
||||||
(idx, ele) => GestureDetector(
|
child: AspectRatio(
|
||||||
child: AspectRatio(
|
aspectRatio: ele?.data['ratio']?.toDouble() ?? 1,
|
||||||
aspectRatio: ele?.data['ratio']?.toDouble() ?? 1,
|
child: Container(
|
||||||
child: Container(
|
constraints: constraints,
|
||||||
constraints: constraints,
|
child: AttachmentItem(
|
||||||
child: AttachmentItem(data: ele, heroTag: heroTags[idx], fit: BoxFit.cover),
|
data: ele,
|
||||||
),
|
heroTag: heroTags[idx],
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
filterQuality: widget.filterQuality,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
),
|
||||||
.expand((ele) => [ele, const Divider(height: 1)])
|
),
|
||||||
.toList()
|
)
|
||||||
..removeLast(),
|
.expand((ele) => [ele, const Divider(height: 1)])
|
||||||
|
.toList()
|
||||||
|
..removeLast(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -189,16 +213,22 @@ class _AttachmentListState extends State<AttachmentList> {
|
|||||||
itemCount: widget.data.length,
|
itemCount: widget.data.length,
|
||||||
itemBuilder: (context, idx) {
|
itemBuilder: (context, idx) {
|
||||||
return Container(
|
return Container(
|
||||||
constraints: constraints.copyWith(maxWidth: widget.maxWidth),
|
constraints:
|
||||||
|
constraints.copyWith(maxWidth: widget.maxWidth),
|
||||||
child: AspectRatio(
|
child: AspectRatio(
|
||||||
aspectRatio: (widget.data[idx]?.data['ratio'] ?? 1).toDouble(),
|
aspectRatio:
|
||||||
|
(widget.data[idx]?.data['ratio'] ?? 1).toDouble(),
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
if (widget.data[idx]?.mediaType != SnMediaType.image) return;
|
if (widget.data[idx]?.mediaType != SnMediaType.image)
|
||||||
|
return;
|
||||||
context.pushTransparentRoute(
|
context.pushTransparentRoute(
|
||||||
AttachmentZoomView(
|
AttachmentZoomView(
|
||||||
data:
|
data: widget.data
|
||||||
widget.data.where((ele) => ele != null && ele.mediaType == SnMediaType.image).cast(),
|
.where((ele) =>
|
||||||
|
ele != null &&
|
||||||
|
ele.mediaType == SnMediaType.image)
|
||||||
|
.cast(),
|
||||||
initialIndex: idx,
|
initialIndex: idx,
|
||||||
heroTags: heroTags,
|
heroTags: heroTags,
|
||||||
),
|
),
|
||||||
@ -212,18 +242,25 @@ class _AttachmentListState extends State<AttachmentList> {
|
|||||||
Container(
|
Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: backgroundColor,
|
color: backgroundColor,
|
||||||
border: Border(top: borderSide, bottom: borderSide),
|
border:
|
||||||
|
Border(top: borderSide, bottom: borderSide),
|
||||||
borderRadius: AttachmentList.kDefaultRadius,
|
borderRadius: AttachmentList.kDefaultRadius,
|
||||||
),
|
),
|
||||||
child: ClipRRect(
|
child: ClipRRect(
|
||||||
borderRadius: AttachmentList.kDefaultRadius,
|
borderRadius: AttachmentList.kDefaultRadius,
|
||||||
child: AttachmentItem(data: widget.data[idx], heroTag: heroTags[idx]),
|
child: AttachmentItem(
|
||||||
|
data: widget.data[idx],
|
||||||
|
heroTag: heroTags[idx],
|
||||||
|
filterQuality: widget.filterQuality,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Positioned(
|
Positioned(
|
||||||
right: 8,
|
right: 8,
|
||||||
bottom: 8,
|
bottom: 8,
|
||||||
child: Chip(label: Text('${idx + 1}/${widget.data.length}')),
|
child: Chip(
|
||||||
|
label:
|
||||||
|
Text('${idx + 1}/${widget.data.length}')),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -245,5 +282,6 @@ class _AttachmentListState extends State<AttachmentList> {
|
|||||||
|
|
||||||
class _AttachmentListScrollBehavior extends MaterialScrollBehavior {
|
class _AttachmentListScrollBehavior extends MaterialScrollBehavior {
|
||||||
@override
|
@override
|
||||||
Set<PointerDeviceKind> get dragDevices => {PointerDeviceKind.touch, PointerDeviceKind.mouse};
|
Set<PointerDeviceKind> get dragDevices =>
|
||||||
|
{PointerDeviceKind.touch, PointerDeviceKind.mouse};
|
||||||
}
|
}
|
||||||
|
@ -149,7 +149,6 @@ class PostItem extends StatelessWidget {
|
|||||||
|
|
||||||
void _doShareViaPicture(BuildContext context) async {
|
void _doShareViaPicture(BuildContext context) async {
|
||||||
final box = context.findRenderObject() as RenderBox?;
|
final box = context.findRenderObject() as RenderBox?;
|
||||||
context.showSnackbar('postSharingViaPicture'.tr());
|
|
||||||
|
|
||||||
final controller = ScreenshotController();
|
final controller = ScreenshotController();
|
||||||
final capturedImage = await controller.captureFromLongWidget(
|
final capturedImage = await controller.captureFromLongWidget(
|
||||||
@ -160,9 +159,9 @@ class PostItem extends StatelessWidget {
|
|||||||
child: Material(
|
child: Material(
|
||||||
child: MultiProvider(
|
child: MultiProvider(
|
||||||
providers: [
|
providers: [
|
||||||
|
// Create a copy of environments
|
||||||
Provider<SnNetworkProvider>(create: (_) => context.read()),
|
Provider<SnNetworkProvider>(create: (_) => context.read()),
|
||||||
ChangeNotifierProvider<ConfigProvider>(
|
Provider<UserDirectoryProvider>(create: (_) => context.read()),
|
||||||
create: (_) => context.read()),
|
|
||||||
],
|
],
|
||||||
child: ResponsiveBreakpoints.builder(
|
child: ResponsiveBreakpoints.builder(
|
||||||
breakpoints: ResponsiveBreakpoints.of(context).breakpoints,
|
breakpoints: ResponsiveBreakpoints.of(context).breakpoints,
|
||||||
@ -507,6 +506,8 @@ class PostShareImageWidget extends StatelessWidget {
|
|||||||
StyledWidget(AttachmentList(
|
StyledWidget(AttachmentList(
|
||||||
data: data.preload!.attachments!,
|
data: data.preload!.attachments!,
|
||||||
columned: true,
|
columned: true,
|
||||||
|
fit: BoxFit.contain,
|
||||||
|
filterQuality: FilterQuality.high,
|
||||||
)).padding(horizontal: 16, bottom: 8),
|
)).padding(horizontal: 16, bottom: 8),
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
@ -34,11 +34,14 @@ class UniversalImage extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final devicePixelRatio = MediaQuery.of(context).devicePixelRatio;
|
final devicePixelRatio = MediaQuery.of(context).devicePixelRatio;
|
||||||
final double? resizeHeight = cacheHeight != null ? (cacheHeight! * devicePixelRatio) : null;
|
final double? resizeHeight =
|
||||||
final double? resizeWidth = cacheWidth != null ? (cacheWidth! * devicePixelRatio) : null;
|
cacheHeight != null ? (cacheHeight! * devicePixelRatio) : null;
|
||||||
|
final double? resizeWidth =
|
||||||
|
cacheWidth != null ? (cacheWidth! * devicePixelRatio) : null;
|
||||||
|
|
||||||
return Image(
|
return Image(
|
||||||
filterQuality: filterQuality ?? context.read<ConfigProvider>().imageQuality,
|
filterQuality:
|
||||||
|
filterQuality ?? context.read<ConfigProvider>().imageQuality,
|
||||||
image: kIsWeb
|
image: kIsWeb
|
||||||
? UniversalImage.provider(url)
|
? UniversalImage.provider(url)
|
||||||
: ResizeImage(
|
: ResizeImage(
|
||||||
@ -52,7 +55,8 @@ class UniversalImage extends StatelessWidget {
|
|||||||
fit: fit,
|
fit: fit,
|
||||||
loadingBuilder: noProgressIndicator
|
loadingBuilder: noProgressIndicator
|
||||||
? null
|
? null
|
||||||
: (BuildContext context, Widget child, ImageChunkEvent? loadingProgress) {
|
: (BuildContext context, Widget child,
|
||||||
|
ImageChunkEvent? loadingProgress) {
|
||||||
if (loadingProgress == null) return child;
|
if (loadingProgress == null) return child;
|
||||||
return Container(
|
return Container(
|
||||||
constraints: BoxConstraints(maxHeight: 80),
|
constraints: BoxConstraints(maxHeight: 80),
|
||||||
@ -61,12 +65,15 @@ class UniversalImage extends StatelessWidget {
|
|||||||
tween: Tween(
|
tween: Tween(
|
||||||
begin: 0,
|
begin: 0,
|
||||||
end: loadingProgress.expectedTotalBytes != null
|
end: loadingProgress.expectedTotalBytes != null
|
||||||
? loadingProgress.cumulativeBytesLoaded / loadingProgress.expectedTotalBytes!
|
? loadingProgress.cumulativeBytesLoaded /
|
||||||
|
loadingProgress.expectedTotalBytes!
|
||||||
: 0,
|
: 0,
|
||||||
),
|
),
|
||||||
duration: const Duration(milliseconds: 300),
|
duration: const Duration(milliseconds: 300),
|
||||||
builder: (context, value, _) => CircularProgressIndicator(
|
builder: (context, value, _) => CircularProgressIndicator(
|
||||||
value: loadingProgress.expectedTotalBytes != null ? value.toDouble() : null,
|
value: loadingProgress.expectedTotalBytes != null
|
||||||
|
? value.toDouble()
|
||||||
|
: null,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -114,6 +121,7 @@ class AutoResizeUniversalImage extends StatelessWidget {
|
|||||||
final BoxFit? fit;
|
final BoxFit? fit;
|
||||||
final bool noProgressIndicator;
|
final bool noProgressIndicator;
|
||||||
final bool noErrorWidget;
|
final bool noErrorWidget;
|
||||||
|
final FilterQuality? filterQuality;
|
||||||
|
|
||||||
const AutoResizeUniversalImage(
|
const AutoResizeUniversalImage(
|
||||||
this.url, {
|
this.url, {
|
||||||
@ -123,6 +131,7 @@ class AutoResizeUniversalImage extends StatelessWidget {
|
|||||||
this.fit,
|
this.fit,
|
||||||
this.noProgressIndicator = false,
|
this.noProgressIndicator = false,
|
||||||
this.noErrorWidget = false,
|
this.noErrorWidget = false,
|
||||||
|
this.filterQuality,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -137,6 +146,7 @@ class AutoResizeUniversalImage extends StatelessWidget {
|
|||||||
noErrorWidget: noErrorWidget,
|
noErrorWidget: noErrorWidget,
|
||||||
cacheHeight: constraints.maxHeight,
|
cacheHeight: constraints.maxHeight,
|
||||||
cacheWidth: constraints.maxWidth,
|
cacheWidth: constraints.maxWidth,
|
||||||
|
filterQuality: filterQuality,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user