wonders/lib/ui/common/modals/fullscreen_url_img_viewer.dart

96 lines
2.8 KiB
Dart
Raw Normal View History

2022-08-29 20:38:28 -06:00
import 'package:wonders/common_libs.dart';
import 'package:wonders/ui/common/utils/app_haptics.dart';
class FullscreenUrlImgViewer extends StatefulWidget {
const FullscreenUrlImgViewer({Key? key, required this.urls, this.index = 0}) : super(key: key);
final List<String> urls;
final int index;
static const double imageScale = 2.5;
2022-08-29 20:38:28 -06:00
@override
State<FullscreenUrlImgViewer> createState() => _FullscreenUrlImgViewerState();
}
2022-12-07 10:14:14 -07:00
class _FullscreenUrlImgViewerState extends State<FullscreenUrlImgViewer> with StatefulPropsMixin {
2022-08-29 20:38:28 -06:00
final _isZoomed = ValueNotifier(false);
2022-12-07 10:14:14 -07:00
late final _pages = PageControllerProp(this, initialPage: widget.index);
2022-08-29 20:38:28 -06:00
2022-12-07 10:14:14 -07:00
void _handleBackPressed() => Navigator.pop(context, _pages.page.round());
2022-08-29 20:38:28 -06:00
@override
Widget build(BuildContext context) {
Widget content = ListenableBuilder(
listenable: _isZoomed,
2022-08-29 20:38:28 -06:00
builder: (_, __) {
final bool enableSwipe = !_isZoomed.value && widget.urls.length > 1;
return PageView.builder(
physics: enableSwipe ? PageScrollPhysics() : NeverScrollableScrollPhysics(),
2022-12-07 10:14:14 -07:00
controller: _pages.controller,
2022-08-29 20:38:28 -06:00
itemCount: widget.urls.length,
itemBuilder: (_, index) => _Viewer(widget.urls[index], _isZoomed),
onPageChanged: (_) => AppHaptics.lightImpact(),
);
},
);
content = Semantics(
label: $strings.fullscreenImageViewerSemanticFull,
container: true,
image: true,
child: ExcludeSemantics(child: content),
);
return Container(
color: $styles.colors.black,
child: Stack(
children: [
Positioned.fill(child: content),
BackBtn.close(onPressed: _handleBackPressed).safe(),
],
),
);
}
}
class _Viewer extends StatefulWidget {
const _Viewer(this.url, this.isZoomed, {Key? key}) : super(key: key);
final String url;
final ValueNotifier<bool> isZoomed;
@override
State<_Viewer> createState() => _ViewerState();
}
2022-12-07 10:14:14 -07:00
class _ViewerState extends State<_Viewer> with StatefulPropsMixin {
late final _transformation = TransformationControllerProp(this);
2022-08-29 20:38:28 -06:00
/// Reset zoom level to 1 on double-tap
2022-12-07 10:14:14 -07:00
void _handleDoubleTap() => _transformation.controller.value = Matrix4.identity();
2022-08-29 20:38:28 -06:00
@override
Widget build(BuildContext context) {
return GestureDetector(
onDoubleTap: _handleDoubleTap,
child: InteractiveViewer(
2022-12-07 10:14:14 -07:00
transformationController: _transformation.controller,
onInteractionEnd: (_) => widget.isZoomed.value = _transformation.matrix.getMaxScaleOnAxis() > 1,
2022-08-29 20:38:28 -06:00
minScale: 1,
maxScale: 5,
child: Hero(
tag: widget.url,
child: AppImage(
image: NetworkImage(
widget.url,
),
2022-08-29 20:38:28 -06:00
fit: BoxFit.contain,
scale: FullscreenUrlImgViewer.imageScale,
progress: true,
2022-08-29 20:38:28 -06:00
),
),
),
);
}
}