mirror of
https://github.com/twonlyapp/twonly-app.git
synced 2026-01-15 12:48:41 +00:00
switch back to old camera plugin #28
This commit is contained in:
parent
644e5125d8
commit
9c027bd924
7 changed files with 393 additions and 457 deletions
|
|
@ -1,3 +1,4 @@
|
|||
import 'package:camera/camera.dart';
|
||||
import 'package:twonly/src/database/twonly_database.dart';
|
||||
import 'package:twonly/src/providers/api_provider.dart';
|
||||
|
||||
|
|
@ -5,3 +6,5 @@ late ApiProvider apiProvider;
|
|||
|
||||
// uses for background notification
|
||||
late TwonlyDatabase twonlyDatabase;
|
||||
|
||||
List<CameraDescription> gCameras = <CameraDescription>[];
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import 'package:camera/camera.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:twonly/globals.dart';
|
||||
|
|
@ -37,6 +38,8 @@ void main() async {
|
|||
await initMediaStorage();
|
||||
await initFCMService();
|
||||
|
||||
gCameras = await availableCameras();
|
||||
|
||||
apiProvider = ApiProvider();
|
||||
twonlyDatabase = TwonlyDatabase();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,194 +1,108 @@
|
|||
import 'package:camerawesome/camerawesome_plugin.dart';
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:camera/camera.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class ZoomSelector extends StatefulWidget {
|
||||
final CameraState state;
|
||||
class CameraZoomButtons extends StatefulWidget {
|
||||
const CameraZoomButtons(
|
||||
{super.key,
|
||||
required this.controller,
|
||||
required this.updateScaleFactor,
|
||||
required this.scaleFactor});
|
||||
|
||||
const ZoomSelector({
|
||||
super.key,
|
||||
required this.state,
|
||||
});
|
||||
final CameraController controller;
|
||||
final double scaleFactor;
|
||||
final Function updateScaleFactor;
|
||||
|
||||
@override
|
||||
State<ZoomSelector> createState() => _ZoomSelectorState();
|
||||
State<CameraZoomButtons> createState() => _CameraZoomButtonsState();
|
||||
}
|
||||
|
||||
class _ZoomSelectorState extends State<ZoomSelector> {
|
||||
double? minZoom;
|
||||
double? maxZoom;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
initAsync();
|
||||
}
|
||||
|
||||
initAsync() async {
|
||||
minZoom = await CamerawesomePlugin.getMinZoom();
|
||||
maxZoom = await CamerawesomePlugin.getMaxZoom();
|
||||
String beautifulZoomScale(double scale) {
|
||||
var tmp = scale.toStringAsFixed(1);
|
||||
if (tmp[0] == "0") {
|
||||
tmp = tmp.substring(1, tmp.length);
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
class _CameraZoomButtonsState extends State<CameraZoomButtons> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return StreamBuilder<SensorConfig>(
|
||||
stream: widget.state.sensorConfig$,
|
||||
builder: (context, sensorConfigSnapshot) {
|
||||
initAsync();
|
||||
if (sensorConfigSnapshot.data == null ||
|
||||
minZoom == null ||
|
||||
maxZoom == null) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
var zoomButtonStyle = TextButton.styleFrom(
|
||||
padding: EdgeInsets.zero,
|
||||
foregroundColor: Colors.white,
|
||||
minimumSize: Size(40, 40),
|
||||
alignment: Alignment.center,
|
||||
tapTargetSize: MaterialTapTargetSize.shrinkWrap);
|
||||
|
||||
return StreamBuilder<double>(
|
||||
stream: sensorConfigSnapshot.requireData.zoom$,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasData) {
|
||||
return _ZoomIndicatorLayout(
|
||||
zoom: snapshot.requireData,
|
||||
min: minZoom!,
|
||||
max: maxZoom!,
|
||||
sensorConfig: widget.state.sensorConfig,
|
||||
);
|
||||
} else {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _ZoomIndicatorLayout extends StatelessWidget {
|
||||
final double zoom;
|
||||
final double min;
|
||||
final double max;
|
||||
final SensorConfig sensorConfig;
|
||||
|
||||
const _ZoomIndicatorLayout({
|
||||
required this.zoom,
|
||||
required this.min,
|
||||
required this.max,
|
||||
required this.sensorConfig,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final displayZoom = (max - min) * zoom + min;
|
||||
if (min == 1.0) {
|
||||
return Container();
|
||||
}
|
||||
|
||||
return Row(
|
||||
final zoomTextStyle = TextStyle(fontSize: 13);
|
||||
return Center(
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(40.0),
|
||||
child: Container(
|
||||
color: const Color.fromARGB(90, 0, 0, 0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
// Show 3 dots for zooming: min, 1.0X and max zoom. The closer one shows
|
||||
// text, the other ones a dot.
|
||||
_ZoomIndicator(
|
||||
normalValue: 0.0,
|
||||
zoom: zoom,
|
||||
selected: displayZoom < 1.0,
|
||||
min: min,
|
||||
max: max,
|
||||
sensorConfig: sensorConfig,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||
child: _ZoomIndicator(
|
||||
normalValue: 0.5,
|
||||
zoom: zoom,
|
||||
selected: !(displayZoom < 1.0 || displayZoom == max),
|
||||
min: min,
|
||||
max: max,
|
||||
sensorConfig: sensorConfig,
|
||||
),
|
||||
),
|
||||
_ZoomIndicator(
|
||||
normalValue: 1.0,
|
||||
zoom: zoom,
|
||||
selected: displayZoom == max,
|
||||
min: min,
|
||||
max: max,
|
||||
sensorConfig: sensorConfig,
|
||||
),
|
||||
],
|
||||
TextButton(
|
||||
style: zoomButtonStyle,
|
||||
onPressed: () async {
|
||||
var level = await widget.controller.getMinZoomLevel();
|
||||
widget.updateScaleFactor(level);
|
||||
},
|
||||
child: FutureBuilder(
|
||||
future: widget.controller.getMinZoomLevel(),
|
||||
builder: (context, snap) {
|
||||
if (snap.hasData) {
|
||||
var minLevel =
|
||||
beautifulZoomScale(snap.data!.toDouble());
|
||||
var currentLevel =
|
||||
beautifulZoomScale(widget.scaleFactor);
|
||||
return Text(
|
||||
widget.scaleFactor < 1
|
||||
? "${currentLevel}x"
|
||||
: "${minLevel}x",
|
||||
style: zoomTextStyle,
|
||||
);
|
||||
} else {
|
||||
return Text("");
|
||||
}
|
||||
}
|
||||
|
||||
class _ZoomIndicator extends StatelessWidget {
|
||||
final double zoom;
|
||||
final double min;
|
||||
final double max;
|
||||
final double normalValue;
|
||||
final SensorConfig sensorConfig;
|
||||
final bool selected;
|
||||
|
||||
const _ZoomIndicator({
|
||||
required this.zoom,
|
||||
required this.min,
|
||||
required this.max,
|
||||
required this.normalValue,
|
||||
required this.sensorConfig,
|
||||
required this.selected,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final baseTheme = AwesomeThemeProvider.of(context).theme;
|
||||
final baseButtonTheme = baseTheme.buttonTheme;
|
||||
final displayZoom = (max - min) * zoom + min;
|
||||
Widget content = AnimatedSwitcher(
|
||||
duration: const Duration(milliseconds: 100),
|
||||
transitionBuilder: (child, anim) {
|
||||
return ScaleTransition(scale: anim, child: child);
|
||||
}),
|
||||
),
|
||||
TextButton(
|
||||
style: zoomButtonStyle,
|
||||
onPressed: () {
|
||||
widget.updateScaleFactor(1.0);
|
||||
},
|
||||
child: selected
|
||||
? AwesomeBouncingWidget(
|
||||
key: ValueKey("zoomIndicator_${normalValue}_selected"),
|
||||
onTap: () {
|
||||
sensorConfig.setZoom(normalValue);
|
||||
},
|
||||
child: Container(
|
||||
color: Colors.transparent,
|
||||
padding: const EdgeInsets.all(0.0),
|
||||
child: AwesomeCircleWidget(
|
||||
theme: baseTheme,
|
||||
child: Text(
|
||||
"${displayZoom.toStringAsFixed(1)}X",
|
||||
style: const TextStyle(color: Colors.white, fontSize: 12),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
: AwesomeBouncingWidget(
|
||||
key: ValueKey("zoomIndicator_${normalValue}_unselected"),
|
||||
onTap: () {
|
||||
sensorConfig.setZoom(normalValue);
|
||||
(widget.scaleFactor >= 1 && widget.scaleFactor < 2)
|
||||
? "${beautifulZoomScale(widget.scaleFactor)}x"
|
||||
: "1.0x",
|
||||
style: zoomTextStyle,
|
||||
)),
|
||||
TextButton(
|
||||
style: zoomButtonStyle,
|
||||
onPressed: () async {
|
||||
var level = min(await widget.controller.getMaxZoomLevel(), 2)
|
||||
.toDouble();
|
||||
widget.updateScaleFactor(level);
|
||||
},
|
||||
child: Container(
|
||||
color: Colors.transparent,
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: AwesomeCircleWidget(
|
||||
theme: baseTheme.copyWith(
|
||||
buttonTheme: baseButtonTheme.copyWith(
|
||||
backgroundColor: baseButtonTheme.foregroundColor,
|
||||
padding: EdgeInsets.zero,
|
||||
),
|
||||
),
|
||||
child: const SizedBox(width: 6, height: 6),
|
||||
child: FutureBuilder(
|
||||
future: widget.controller.getMaxZoomLevel(),
|
||||
builder: (context, snap) {
|
||||
if (snap.hasData) {
|
||||
var maxLevel = min((snap.data?.toInt())!, 2);
|
||||
return Text("${maxLevel}x", style: zoomTextStyle);
|
||||
} else {
|
||||
return Text("");
|
||||
}
|
||||
}),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
// Same width for each dot to keep them in their position
|
||||
return SizedBox(
|
||||
width: 56,
|
||||
child: Center(
|
||||
child: content,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import 'dart:io';
|
||||
import 'dart:ui';
|
||||
import 'dart:typed_data';
|
||||
import 'package:camera/camera.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:camerawesome/camerawesome_plugin.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:screenshot/screenshot.dart';
|
||||
import 'package:twonly/globals.dart';
|
||||
import 'package:twonly/src/components/zoom_selector.dart';
|
||||
import 'package:twonly/src/utils/misc.dart';
|
||||
import 'package:twonly/src/components/image_editor/action_button.dart';
|
||||
|
|
@ -48,13 +48,77 @@ class CameraPreviewView extends StatefulWidget {
|
|||
}
|
||||
|
||||
class _CameraPreviewViewState extends State<CameraPreviewView> {
|
||||
double _lastZoom = 1;
|
||||
double _basePanY = 0;
|
||||
double scaleFactor = 1;
|
||||
bool sharePreviewIsShown = false;
|
||||
bool isFlashOn = false;
|
||||
bool showSelfieFlash = false;
|
||||
int cameraId = 0;
|
||||
bool isZoomAble = false;
|
||||
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
|
||||
|
||||
late CameraController controller;
|
||||
ScreenshotController screenshotController = ScreenshotController();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
selectCamera(0, init: true);
|
||||
}
|
||||
|
||||
void selectCamera(int sCameraId, {bool init = false}) {
|
||||
if (sCameraId > gCameras.length) return;
|
||||
setState(() {
|
||||
isZoomAble = false;
|
||||
});
|
||||
controller = CameraController(gCameras[sCameraId], ResolutionPreset.high);
|
||||
controller.initialize().then((_) async {
|
||||
if (!mounted) {
|
||||
return;
|
||||
}
|
||||
controller.setFlashMode(isFlashOn ? FlashMode.always : FlashMode.off);
|
||||
|
||||
isZoomAble = await controller.getMinZoomLevel() !=
|
||||
await controller.getMaxZoomLevel();
|
||||
setState(() {});
|
||||
}).catchError((Object e) {
|
||||
if (e is CameraException) {
|
||||
switch (e.code) {
|
||||
case 'CameraAccessDenied':
|
||||
// Handle access errors here.
|
||||
break;
|
||||
default:
|
||||
// Handle other errors here.
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
setState(() {
|
||||
cameraId = sCameraId;
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> updateScaleFactor(double newScale) async {
|
||||
var minFactor = await controller.getMinZoomLevel();
|
||||
var maxFactor = await controller.getMaxZoomLevel();
|
||||
if (newScale < minFactor) {
|
||||
newScale = minFactor;
|
||||
}
|
||||
if (newScale > maxFactor) {
|
||||
newScale = maxFactor;
|
||||
}
|
||||
|
||||
await controller.setZoomLevel(newScale);
|
||||
setState(() {
|
||||
scaleFactor = newScale;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MediaViewSizing(
|
||||
|
|
@ -62,117 +126,57 @@ class _CameraPreviewViewState extends State<CameraPreviewView> {
|
|||
children: [
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(22),
|
||||
child: CameraAwesomeBuilder.custom(
|
||||
previewAlignment: Alignment.topLeft,
|
||||
sensorConfig: SensorConfig.single(
|
||||
aspectRatio: CameraAspectRatios.ratio_16_9,
|
||||
zoom: 0.5,
|
||||
),
|
||||
previewFit: CameraPreviewFit.contain,
|
||||
progressIndicator: Container(),
|
||||
onMediaCaptureEvent: (event) {
|
||||
switch ((event.status, event.isPicture, event.isVideo)) {
|
||||
case (MediaCaptureStatus.capturing, true, false):
|
||||
debugPrint('Capturing picture...');
|
||||
case (MediaCaptureStatus.success, true, false):
|
||||
event.captureRequest.when(
|
||||
single: (single) async {
|
||||
final imageBytes = await single.file?.readAsBytes();
|
||||
if (imageBytes == null || !context.mounted) return;
|
||||
debugPrint("Delete ${single.path!}");
|
||||
File(single.path!).delete();
|
||||
setState(() {
|
||||
sharePreviewIsShown = true;
|
||||
});
|
||||
await Navigator.push(
|
||||
context,
|
||||
PageRouteBuilder(
|
||||
opaque: false,
|
||||
pageBuilder: (context, a1, a2) =>
|
||||
ShareImageEditorView(imageBytes: imageBytes),
|
||||
transitionsBuilder: (context, animation,
|
||||
secondaryAnimation, child) {
|
||||
return child;
|
||||
},
|
||||
transitionDuration: Duration.zero,
|
||||
reverseTransitionDuration: Duration.zero,
|
||||
),
|
||||
);
|
||||
if (context.mounted) {
|
||||
setState(() {
|
||||
sharePreviewIsShown = false;
|
||||
});
|
||||
}
|
||||
},
|
||||
multiple: (multiple) {
|
||||
multiple.fileBySensor.forEach((key, value) {
|
||||
debugPrint(
|
||||
'multiple image taken: $key ${value?.path}');
|
||||
});
|
||||
},
|
||||
);
|
||||
case (MediaCaptureStatus.failure, true, false):
|
||||
debugPrint('Failed to capture picture: ${event.exception}');
|
||||
case (MediaCaptureStatus.capturing, false, true):
|
||||
debugPrint('Capturing video...');
|
||||
case (MediaCaptureStatus.success, false, true):
|
||||
event.captureRequest.when(
|
||||
single: (single) {
|
||||
debugPrint('Video saved: ${single.file?.path}');
|
||||
},
|
||||
multiple: (multiple) {
|
||||
multiple.fileBySensor.forEach((key, value) {
|
||||
debugPrint(
|
||||
'multiple video taken: $key ${value?.path}');
|
||||
});
|
||||
},
|
||||
);
|
||||
case (MediaCaptureStatus.failure, false, true):
|
||||
debugPrint('Failed to capture video: ${event.exception}');
|
||||
default:
|
||||
debugPrint('Unknown event: $event');
|
||||
}
|
||||
},
|
||||
builder: (cameraState, preview) {
|
||||
return Stack(
|
||||
child: Stack(
|
||||
children: [
|
||||
(controller.value.isInitialized)
|
||||
? Positioned.fill(
|
||||
child: Screenshot(
|
||||
controller: screenshotController,
|
||||
child: AspectRatio(
|
||||
aspectRatio: 9 / 16,
|
||||
child: ClipRect(
|
||||
child: FittedBox(
|
||||
fit: BoxFit.cover,
|
||||
child: SizedBox(
|
||||
width: controller.value.previewSize!.height,
|
||||
height: controller.value.previewSize!.width,
|
||||
child: CameraPreview(controller),
|
||||
),
|
||||
),
|
||||
),
|
||||
)),
|
||||
)
|
||||
: Container(),
|
||||
Positioned.fill(
|
||||
child: GestureDetector(
|
||||
onPanStart: (details) async {
|
||||
if (cameraState.sensorConfig.sensors.first.position ==
|
||||
SensorPosition.front) {
|
||||
return;
|
||||
}
|
||||
setState(() {
|
||||
_basePanY = details.localPosition.dy;
|
||||
});
|
||||
// if (cameraState.sensorConfig.sensors.first.position ==
|
||||
// SensorPosition.front) {
|
||||
// return;
|
||||
// }
|
||||
// setState(() {
|
||||
// _basePanY = details.localPosition.dy;
|
||||
// });
|
||||
},
|
||||
onPanUpdate: (details) async {
|
||||
if (cameraState.sensorConfig.sensors.first.position ==
|
||||
SensorPosition.front) {
|
||||
return;
|
||||
}
|
||||
var diff = _basePanY - details.localPosition.dy;
|
||||
if (diff > 200) diff = 200;
|
||||
if (diff < 0) diff = 0;
|
||||
var tmp = (diff / 200 * 50).toInt() / 50;
|
||||
if (tmp != _lastZoom) {
|
||||
cameraState.sensorConfig.setZoom(tmp);
|
||||
setState(() {
|
||||
(tmp);
|
||||
_lastZoom = tmp;
|
||||
});
|
||||
}
|
||||
// if (cameraState.sensorConfig.sensors.first.position ==
|
||||
// SensorPosition.front) {
|
||||
// return;
|
||||
// }
|
||||
// var diff = _basePanY - details.localPosition.dy;
|
||||
// if (diff > 200) diff = 200;
|
||||
// if (diff < 0) diff = 0;
|
||||
// var tmp = (diff / 200 * 50).toInt() / 50;
|
||||
// if (tmp != _lastZoom) {
|
||||
// cameraState.sensorConfig.setZoom(tmp);
|
||||
// setState(() {
|
||||
// (tmp);
|
||||
// _lastZoom = tmp;
|
||||
// });
|
||||
// }
|
||||
},
|
||||
onDoubleTap: () async {
|
||||
bool isFront =
|
||||
cameraState.sensorConfig.sensors.first.position ==
|
||||
SensorPosition.front;
|
||||
cameraState.switchCameraSensor(
|
||||
aspectRatio: CameraAspectRatios.ratio_16_9,
|
||||
flash: isFlashOn ? FlashMode.on : FlashMode.none,
|
||||
zoom: isFront ? 0.5 : 0,
|
||||
);
|
||||
selectCamera((cameraId + 1) % 2);
|
||||
},
|
||||
),
|
||||
),
|
||||
|
|
@ -192,13 +196,7 @@ class _CameraPreviewViewState extends State<CameraPreviewView> {
|
|||
tooltipText:
|
||||
context.lang.switchFrontAndBackCamera,
|
||||
onPressed: () async {
|
||||
cameraState.switchCameraSensor(
|
||||
aspectRatio:
|
||||
CameraAspectRatios.ratio_16_9,
|
||||
flash: isFlashOn
|
||||
? FlashMode.on
|
||||
: FlashMode.none,
|
||||
);
|
||||
selectCamera((cameraId + 1) % 2);
|
||||
},
|
||||
),
|
||||
ActionButton(
|
||||
|
|
@ -206,16 +204,13 @@ class _CameraPreviewViewState extends State<CameraPreviewView> {
|
|||
tooltipText: context.lang.toggleFlashLight,
|
||||
color: isFlashOn
|
||||
? const Color.fromARGB(255, 255, 230, 0)
|
||||
: const Color.fromARGB(
|
||||
158, 255, 255, 255),
|
||||
: const Color.fromARGB(158, 255, 255, 255),
|
||||
onPressed: () async {
|
||||
if (isFlashOn) {
|
||||
cameraState.sensorConfig
|
||||
.setFlashMode(FlashMode.none);
|
||||
controller.setFlashMode(FlashMode.off);
|
||||
isFlashOn = false;
|
||||
} else {
|
||||
cameraState.sensorConfig
|
||||
.setFlashMode(FlashMode.on);
|
||||
controller.setFlashMode(FlashMode.always);
|
||||
isFlashOn = true;
|
||||
}
|
||||
setState(() {});
|
||||
|
|
@ -235,24 +230,71 @@ class _CameraPreviewViewState extends State<CameraPreviewView> {
|
|||
alignment: Alignment.bottomCenter,
|
||||
child: Column(
|
||||
children: [
|
||||
ZoomSelector(state: cameraState),
|
||||
if (controller.value.isInitialized &&
|
||||
isZoomAble &&
|
||||
controller.description.lensDirection !=
|
||||
CameraLensDirection.front)
|
||||
SizedBox(
|
||||
width: 150,
|
||||
child: CameraZoomButtons(
|
||||
key: widget.key,
|
||||
scaleFactor: scaleFactor,
|
||||
updateScaleFactor: updateScaleFactor,
|
||||
controller: controller,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 30),
|
||||
GestureDetector(
|
||||
onTap: () async {
|
||||
if (cameraState.sensorConfig.flashMode ==
|
||||
FlashMode.on &&
|
||||
cameraState.sensorConfig.sensors.first
|
||||
.position ==
|
||||
SensorPosition.front) {
|
||||
if (isFlashOn) {
|
||||
if (controller.description.lensDirection ==
|
||||
CameraLensDirection.front) {
|
||||
setState(() {
|
||||
showSelfieFlash = true;
|
||||
});
|
||||
await Future.delayed(
|
||||
Duration(milliseconds: 500));
|
||||
} else {
|
||||
controller.setFlashMode(FlashMode.torch);
|
||||
}
|
||||
cameraState.when(
|
||||
onPhotoMode: (picState) =>
|
||||
picState.takePhoto());
|
||||
await Future.delayed(
|
||||
Duration(milliseconds: 1000));
|
||||
}
|
||||
|
||||
await controller.pausePreview();
|
||||
if (!context.mounted) return;
|
||||
|
||||
controller.setFlashMode(
|
||||
isFlashOn ? FlashMode.always : FlashMode.off);
|
||||
|
||||
Future<Uint8List?> imageBytes =
|
||||
screenshotController.capture(pixelRatio: 1);
|
||||
|
||||
setState(() {
|
||||
sharePreviewIsShown = true;
|
||||
});
|
||||
await Navigator.push(
|
||||
context,
|
||||
PageRouteBuilder(
|
||||
opaque: false,
|
||||
pageBuilder: (context, a1, a2) =>
|
||||
ShareImageEditorView(
|
||||
imageBytes: imageBytes),
|
||||
transitionsBuilder: (context, animation,
|
||||
secondaryAnimation, child) {
|
||||
return child;
|
||||
},
|
||||
transitionDuration: Duration.zero,
|
||||
reverseTransitionDuration: Duration.zero,
|
||||
),
|
||||
);
|
||||
// does not work??
|
||||
//await controller.resumePreview();
|
||||
selectCamera(0);
|
||||
if (context.mounted) {
|
||||
setState(() {
|
||||
sharePreviewIsShown = false;
|
||||
});
|
||||
}
|
||||
|
||||
setState(() {
|
||||
showSelfieFlash = false;
|
||||
});
|
||||
|
|
@ -280,19 +322,6 @@ class _CameraPreviewViewState extends State<CameraPreviewView> {
|
|||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
saveConfig: SaveConfig.photoAndVideo(
|
||||
photoPathBuilder: (sensors) async {
|
||||
final Directory extDir = await getTemporaryDirectory();
|
||||
final testDir = await Directory(
|
||||
'${extDir.path}/images',
|
||||
).create(recursive: true);
|
||||
final String filePath =
|
||||
'${testDir.path}/${DateTime.now().millisecondsSinceEpoch}.jpg';
|
||||
return SingleCaptureRequest(filePath, sensors.first);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
if (showSelfieFlash)
|
||||
|
|
@ -304,18 +333,6 @@ class _CameraPreviewViewState extends State<CameraPreviewView> {
|
|||
),
|
||||
),
|
||||
),
|
||||
if (sharePreviewIsShown)
|
||||
Positioned.fill(
|
||||
child: BackdropFilter(
|
||||
filter: ImageFilter.blur(
|
||||
sigmaX: 100.0,
|
||||
sigmaY: 100.0,
|
||||
),
|
||||
child: Center(
|
||||
child: CircularProgressIndicator(),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ List<Layer> removedLayers = [];
|
|||
|
||||
class ShareImageEditorView extends StatefulWidget {
|
||||
const ShareImageEditorView({super.key, required this.imageBytes});
|
||||
final Uint8List imageBytes;
|
||||
final Future<Uint8List?> imageBytes;
|
||||
@override
|
||||
State<ShareImageEditorView> createState() => _ShareImageEditorView();
|
||||
}
|
||||
|
|
@ -223,8 +223,9 @@ class _ShareImageEditorView extends State<ShareImageEditorView> {
|
|||
return image;
|
||||
}
|
||||
|
||||
Future<void> loadImage(dynamic imageFile) async {
|
||||
await currentImage.load(imageFile);
|
||||
Future<void> loadImage(Future<Uint8List?> imageFile) async {
|
||||
Uint8List? imageBytes = await imageFile;
|
||||
await currentImage.load(imageBytes);
|
||||
|
||||
layers.clear();
|
||||
|
||||
|
|
|
|||
64
pubspec.lock
64
pubspec.lock
|
|
@ -129,22 +129,46 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "8.9.3"
|
||||
camerawesome:
|
||||
camera:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: camerawesome
|
||||
sha256: "3619d5605fb14ab72c815532c1d9f635512c75df07b5a742b60a9a4b03b6081e"
|
||||
name: camera
|
||||
sha256: "413d2b34fe28496c35c69ede5b232fb9dd5ca2c3a4cb606b14efc1c7546cc8cb"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
carousel_slider:
|
||||
version: "0.11.1"
|
||||
camera_android_camerax:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: carousel_slider
|
||||
sha256: "7b006ec356205054af5beaef62e2221160ea36b90fb70a35e4deacd49d0349ae"
|
||||
name: camera_android_camerax
|
||||
sha256: "13784f539c7f104766bff84e4479a70f03b29d78b208278be45c939250d9d7f5"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.0.0"
|
||||
version: "0.6.14+1"
|
||||
camera_avfoundation:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: camera_avfoundation
|
||||
sha256: "3057ada0b30402e3a9b6dffec365c9736a36edbf04abaecc67c4309eadc86b49"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.9.18+9"
|
||||
camera_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: camera_platform_interface
|
||||
sha256: "953e7baed3a7c8fae92f7200afeb2be503ff1a17c3b4e4ed7b76f008c2810a31"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.9.0"
|
||||
camera_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: camera_web
|
||||
sha256: "595f28c89d1fb62d77c73c633193755b781c6d2e0ebcd8dc25b763b514e6ba8f"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.3.5"
|
||||
characters:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
@ -201,14 +225,6 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.19.0"
|
||||
colorfilter_generator:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: colorfilter_generator
|
||||
sha256: ccc2995e440b1d828d55d99150e7cad64624f3cb4a1e235000de3f93cf10d35c
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.0.8"
|
||||
connectivity_plus:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
|
@ -869,14 +885,6 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.11.1"
|
||||
matrix2d:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: matrix2d
|
||||
sha256: "188718dd3bc2a31e372cfd0791b0f77f4f13ea76164147342cc378d9132949e7"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.4"
|
||||
meta:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
@ -1173,14 +1181,6 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.2"
|
||||
rxdart:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: rxdart
|
||||
sha256: "5c3004a4a8dbb94bd4bf5412a4def4acdaa12e12f269737a5751369e12d1a962"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.28.0"
|
||||
screenshot:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
|
|
|||
|
|
@ -10,9 +10,6 @@ environment:
|
|||
sdk: ^3.6.0
|
||||
|
||||
dependencies:
|
||||
camerawesome: ^2.1.0
|
||||
# camerawesome:
|
||||
# path: ../CamerAwesome
|
||||
collection: ^1.18.0
|
||||
connectivity_plus: ^6.1.2
|
||||
drift: ^2.25.1
|
||||
|
|
@ -54,6 +51,7 @@ dependencies:
|
|||
screenshot: ^3.0.0
|
||||
url_launcher: ^6.3.1
|
||||
web_socket_channel: ^3.0.1
|
||||
camera: ^0.11.1
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
|
|
|||
Loading…
Reference in a new issue