initial
Some checks failed
Build Android App / build (push) Failing after 2m15s

This commit is contained in:
ImBenji
2026-01-01 07:45:17 +00:00
parent fa45fb0a4f
commit 02d9d82575
12 changed files with 700 additions and 230 deletions

View File

@@ -26,6 +26,9 @@ jobs:
distribution: "zulu"
java-version: "17"
- name: Install jq
run: apt-get update && apt-get install -y jq
- name: Setup Flutter
uses: subosito/flutter-action@v2
with:

View File

@@ -1,4 +1,5 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:label="quotegen_client"
android:name="${applicationName}"

View File

@@ -34,14 +34,25 @@ PODS:
- DKImagePickerController/PhotoGallery
- Flutter
- Flutter (1.0.0)
- path_provider_foundation (0.0.1):
- Flutter
- FlutterMacOS
- SDWebImage (5.21.1):
- SDWebImage/Core (= 5.21.1)
- SDWebImage/Core (5.21.1)
- share_plus (0.0.1):
- Flutter
- shared_preferences_foundation (0.0.1):
- Flutter
- FlutterMacOS
- SwiftyGif (5.4.5)
DEPENDENCIES:
- file_picker (from `.symlinks/plugins/file_picker/ios`)
- Flutter (from `Flutter`)
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
- share_plus (from `.symlinks/plugins/share_plus/ios`)
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
SPEC REPOS:
trunk:
@@ -55,13 +66,22 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/file_picker/ios"
Flutter:
:path: Flutter
path_provider_foundation:
:path: ".symlinks/plugins/path_provider_foundation/darwin"
share_plus:
:path: ".symlinks/plugins/share_plus/ios"
shared_preferences_foundation:
:path: ".symlinks/plugins/shared_preferences_foundation/darwin"
SPEC CHECKSUMS:
DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c
DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60
file_picker: b159e0c068aef54932bb15dc9fd1571818edaf49
Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467
path_provider_foundation: 0b743cbb62d8e47eab856f09262bb8c1ddcfe6ba
SDWebImage: f29024626962457f3470184232766516dee8dfea
share_plus: 8b6f8b3447e494cca5317c8c3073de39b3600d1f
shared_preferences_foundation: 5086985c1d43c5ba4d5e69a4e8083a389e2909e6
SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4
PODFILE CHECKSUM: 3c63482e143d1b91d2d2560aee9fb04ecc74ac7e

View File

@@ -1,4 +1,4 @@
import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
import 'package:go_router/go_router.dart';
import 'package:quotegen_client/pages/home/page.dart';
import 'package:shadcn_flutter/shadcn_flutter.dart';
@@ -16,6 +16,14 @@ class MyApp extends StatelessWidget {
return ShadcnApp.router(
title: 'Flutter Demo',
routerConfig: _router,
scaling: defaultTargetPlatform == TargetPlatform.android ? AdaptiveScaling.only(
sizeScaling: 1,
textScaling: 1.1,
radiusScaling: 1.1
) : null,
theme: ThemeData(
colorScheme: ColorSchemes.darkBlue,
),
);
}
}

View File

@@ -1,5 +1,6 @@
import 'dart:convert';
import 'dart:io';
import 'dart:math';
import 'dart:typed_data';
@@ -9,6 +10,10 @@ import 'package:go_router/go_router.dart';
import 'package:image/image.dart' as img;
import 'package:quotegen_client/services/quote_api.dart';
import 'package:shadcn_flutter/shadcn_flutter.dart';
import 'package:share_plus/share_plus.dart';
import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart' as path;
import 'package:shared_preferences/shared_preferences.dart';
class HomePage extends StatefulWidget {
@@ -36,6 +41,24 @@ class _HomePageState extends State<HomePage> {
Uint8List? postPreviewImage;
final TextEditingController _displayNameController = TextEditingController();
final TextEditingController _handleController = TextEditingController();
final TextEditingController _contentController = TextEditingController();
@override
void initState() {
super.initState();
_loadFormData();
}
@override
void dispose() {
_displayNameController.dispose();
_handleController.dispose();
_contentController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
@@ -43,252 +66,345 @@ class _HomePageState extends State<HomePage> {
double bottomPadding = MediaQuery.of(context).padding.bottom;
return Scaffold(
child: Column(
children: [
child: SingleChildScrollView(
child: Column(
children: [
Gap(max(topPadding, 14)),
Gap(max(topPadding, 14)),
AspectRatio(
aspectRatio: 1,
child: OutlinedContainer(
backgroundColor: Colors.black,
child: postPreviewImage == null ? Center(
child: CircularProgressIndicator(
color: Colors.white,
strokeWidth: 3,
AspectRatio(
aspectRatio: 1,
child: OutlinedContainer(
backgroundColor: Colors.black,
child: postPreviewImage == null ? Center(
child: CircularProgressIndicator(
color: Colors.white,
strokeWidth: 3,
),
) : Stack(
children: [
Image.memory(
postPreviewImage!,
fit: BoxFit.cover,
),
Align(
alignment: Alignment.bottomRight,
child: IconButton.secondary(
icon: Icon(
Icons.share,
),
onPressed: () async {
await shareImage();
}
)
).withPadding(
all: 12
)
],
),
) : Image.memory(
postPreviewImage!,
fit: BoxFit.cover,
),
)
).withPadding(
horizontal: 14
),
)
).withPadding(
horizontal: 14
),
Gap(14),
Gap(14),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Display Name"
).xSmall.semiBold,
Gap(6),
TextField(
placeholder: Text(
"e.g. John Doe"
),
onChanged: (value) {
setState(() {
formData["display_name"] = value;
});
onSubmit();
},
),
],
),
),
Gap(14),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Handle"
).xSmall.semiBold,
Gap(6),
TextField(
placeholder: Text(
"e.g. @johndoe"
),
onChanged: (value) {
setState(() {
formData["handle"] = value;
});
onSubmit();
},
),
],
),
),
],
),
Gap(10),
SizedBox(
height: 96,
child: Row(
Row(
children: [
Expanded(
child: Column(
children: [
SizedBox(
width: double.infinity,
child: OutlineButton(
child: Text("Select Avatar Image"),
onPressed: () async {
FilePickerResult? result = await FilePicker.platform.pickFiles(
type: FileType.image,
allowMultiple: false,
);
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Display Name"
).xSmall.semiBold,
if (result != null) {
Uint8List? imageBytes;
Gap(6),
// on web, bytes is availble directly
if (result.files.single.bytes != null) {
imageBytes = result.files.single.bytes!;
}
// on mobile (iOS/Android), need to raed from path
else if (result.files.single.path != null) {
File file = File(result.files.single.path!);
imageBytes = await file.readAsBytes();
}
if (imageBytes != null) {
// compression disabled for testing
// Uint8List? compressedBytes = await compressImage(imageBytes, maxWidth: 400);
if (!mounted) return;
setState(() {
formData["avatar_image"] = imageBytes;
});
onSubmit();
}
}
},
),
TextField(
controller: _displayNameController,
placeholder: Text(
"e.g. John Doe"
),
Gap(6),
SizedBox(
width: double.infinity,
child: OutlineButton(
child: Text("Select Post Image"),
onPressed: () async {
FilePickerResult? result = await FilePicker.platform.pickFiles(
type: FileType.image,
allowMultiple: false,
);
if (result != null) {
Uint8List? imageBytes;
// on web, bytes is availble directly
if (result.files.single.bytes != null) {
imageBytes = result.files.single.bytes!;
}
// on mobile (iOS/Android), need to raed from path
else if (result.files.single.path != null) {
File file = File(result.files.single.path!);
imageBytes = await file.readAsBytes();
}
if (imageBytes != null) {
if (!mounted) return;
setState(() {
formData["post_image"] = imageBytes;
});
onSubmit();
}
}
},
),
),
]
onChanged: (value) {
setState(() {
formData["display_name"] = value;
});
_saveFormData();
onSubmit();
},
),
],
),
),
Gap(10),
Gap(14),
AspectRatio(
aspectRatio: 1,
child: ClipRRect(
borderRadius: BorderRadius.circular(1000),
child: formData["avatar_image"] != null ? Image.memory(
formData["avatar_image"],
width: 50,
height: 50,
fit: BoxFit.cover,
) : OutlinedContainer(
borderRadius: BorderRadius.circular(1000),
child: Center(
child: Text(
formData["display_name"].isNotEmpty ? formData["display_name"][0].toUpperCase() : "P",
)
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Handle"
).xSmall.semiBold,
Gap(6),
TextField(
controller: _handleController,
placeholder: Text(
"e.g. @johndoe"
),
onChanged: (value) {
setState(() {
formData["handle"] = value;
});
_saveFormData();
onSubmit();
},
),
),
)
],
),
),
],
),
),
Gap(10),
Gap(10),
Text(
"Content"
).xSmall.semiBold,
SizedBox(
height: 132,
child: Row(
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
width: double.infinity,
child: OutlineButton(
child: Text("Select Avatar Image"),
onPressed: () async {
FilePickerResult? result = await FilePicker.platform.pickFiles(
type: FileType.image,
allowMultiple: false,
);
Gap(6),
if (result != null) {
Uint8List? imageBytes;
TextArea(
onChanged: (value) {
setState(() {
formData["content"] = value;
});
onSubmit();
},
),
// on web, bytes is availble directly
if (result.files.single.bytes != null) {
imageBytes = result.files.single.bytes!;
}
// on mobile (iOS/Android), need to raed from path
else if (result.files.single.path != null) {
File file = File(result.files.single.path!);
imageBytes = await file.readAsBytes();
}
Gap(10),
if (imageBytes != null) {
// downscale avatar image
Uint8List? resizedBytes = await compressImage(imageBytes, maxWidth: 400);
Text(
"Timestamp"
).xSmall.semiBold,
if (!mounted) return;
setState(() {
formData["avatar_image"] = resizedBytes ?? imageBytes;
});
_saveFormData();
onSubmit();
}
}
},
),
),
Gap(6),
Gap(8),
SizedBox(
width: double.infinity,
child: DatePicker(
value: DateTime.now(),
onChanged: (DateTime? date) {
Divider(),
Gap(6),
Text(
"Timestamp"
).xSmall.semiBold,
Gap(6),
SizedBox(
width: double.infinity,
child: DatePicker(
value: formData["timestamp"] > 0
? DateTime.fromMillisecondsSinceEpoch(formData["timestamp"])
: DateTime.now(),
onChanged: (DateTime? date) {
setState(() {
formData["timestamp"] = date!.millisecondsSinceEpoch;
});
_saveFormData();
onSubmit();
}
)
).withPadding(
right: 10
),
]
),
),
// Gap(10),
VerticalDivider().withPadding(
top: 54
),
Gap(10),
AspectRatio(
aspectRatio: 1,
child: ClipRRect(
borderRadius: BorderRadius.circular(1000),
child: formData["avatar_image"] != null ? Image.memory(
formData["avatar_image"],
width: 50,
height: 50,
fit: BoxFit.cover,
) : OutlinedContainer(
borderRadius: BorderRadius.circular(1000),
child: Center(
child: Text(
formData["display_name"].isNotEmpty ? formData["display_name"][0].toUpperCase() : "P",
)
),
),
)
),
],
),
),
Gap(10),
Text(
"Content"
).xSmall.semiBold,
Gap(6),
TextArea(
controller: _contentController,
onChanged: (value) {
setState(() {
formData["timestamp"] = date!.millisecondsSinceEpoch;
formData["content"] = value;
});
_saveFormData();
onSubmit();
}
)
),
},
),
],
).withPadding(
horizontal: 14
)
Gap(10),
],
Divider(),
Gap(10),
if (formData["post_image"] != null)...[
OutlinedContainer(
child: formData["post_image"] != null ? Image.memory(
formData["post_image"],
width: double.infinity,
// height: 200,
fit: BoxFit.cover,
) : Center(
child: Text(
"No Post Image Selected",
).small.semiBold,
),
),
Gap(10),
],
Row(
children: [
Expanded(
child: SizedBox(
width: double.infinity,
child: OutlineButton(
child: formData["post_image"] == null ? Text("Select Post Image") : Text("Change Post Image"),
onPressed: () async {
FilePickerResult? result = await FilePicker.platform.pickFiles(
type: FileType.image,
allowMultiple: false,
);
if (result != null) {
Uint8List? imageBytes;
// on web, bytes is availble directly
if (result.files.single.bytes != null) {
imageBytes = result.files.single.bytes!;
}
// on mobile (iOS/Android), need to raed from path
else if (result.files.single.path != null) {
File file = File(result.files.single.path!);
imageBytes = await file.readAsBytes();
}
if (imageBytes != null) {
if (!mounted) return;
setState(() {
formData["post_image"] = imageBytes;
});
_saveFormData();
onSubmit();
}
}
},
),
),
),
if (formData["post_image"] != null)...[
Gap(10),
IconButton.destructive(
icon: Icon(
Icons.delete,
),
onPressed: () {
if (!mounted) return;
setState(() {
formData["post_image"] = null;
});
_saveFormData();
onSubmit();
},
)
]
],
),
Gap(bottomPadding)
],
).withPadding(
horizontal: 14
)
],
),
),
);
}
// compress and resize image to reduce payload size
// resize image to reduce payload size without comression
Future<Uint8List?> compressImage(Uint8List bytes, {int maxWidth = 800, int quality = 85}) async {
try {
img.Image? image = img.decodeImage(bytes);
@@ -299,10 +415,10 @@ class _HomePageState extends State<HomePage> {
image = img.copyResize(image, width: maxWidth);
}
// encode as JPEG with compression
return Uint8List.fromList(img.encodeJpg(image, quality: quality));
// encode as PNG (lossles, no compression)
return Uint8List.fromList(img.encodePng(image));
} catch (e) {
print("Error compresing image: $e");
print("Error resizng image: $e");
return null;
}
}
@@ -345,4 +461,104 @@ class _HomePageState extends State<HomePage> {
});
}
Future<void> shareImage() async {
if (postPreviewImage == null) {
print("No image to share");
return;
}
try {
// get temporary directry
final tempDir = await getTemporaryDirectory();
// create a unique filename with timestmp
final fileName = "quote_${DateTime.now().millisecondsSinceEpoch}.png";
final filePath = path.join(tempDir.path, fileName);
// write the image bytes to a temporry file
final file = File(filePath);
await file.writeAsBytes(postPreviewImage!);
// Share the file using the systm share dialog
final result = await Share.shareXFiles(
[XFile(filePath)],
text: "Check out this quote!",
);
// optinal: log share result
if (result.status == ShareResultStatus.success) {
print("Share succesful");
}
} catch (e) {
print("Error sharin image: $e");
}
}
// load form data from shared preferences
Future<void> _loadFormData() async {
try {
final prefs = await SharedPreferences.getInstance();
setState(() {
// load text fields
formData["display_name"] = prefs.getString("display_name") ?? "";
formData["handle"] = prefs.getString("handle") ?? "";
formData["content"] = prefs.getString("content") ?? "";
formData["timestamp"] = prefs.getInt("timestamp") ?? 0;
// load images from base64
String? avatarBase64 = prefs.getString("avatar_image");
if (avatarBase64 != null && avatarBase64.isNotEmpty) {
formData["avatar_image"] = base64Decode(avatarBase64);
}
String? postBase64 = prefs.getString("post_image");
if (postBase64 != null && postBase64.isNotEmpty) {
formData["post_image"] = base64Decode(postBase64);
}
// update controllers
_displayNameController.text = formData["display_name"];
_handleController.text = formData["handle"];
_contentController.text = formData["content"];
});
// regenerate preview if we have data
if (formData["display_name"].isNotEmpty || formData["content"].isNotEmpty) {
onSubmit();
}
} catch (e) {
print("Error loading form data: $e");
}
}
// save form data to shared preferences
Future<void> _saveFormData() async {
try {
final prefs = await SharedPreferences.getInstance();
// save text felds
await prefs.setString("display_name", formData["display_name"]);
await prefs.setString("handle", formData["handle"]);
await prefs.setString("content", formData["content"]);
await prefs.setInt("timestamp", formData["timestamp"]);
// save images as base64
if (formData["avatar_image"] != null) {
String avatarBase64 = base64Encode(formData["avatar_image"]);
await prefs.setString("avatar_image", avatarBase64);
}
if (formData["post_image"] != null) {
String postBase64 = base64Encode(formData["post_image"]);
await prefs.setString("post_image", postBase64);
}
} catch (e) {
print("Error savin form data: $e");
}
}
}

View File

@@ -6,6 +6,10 @@
#include "generated_plugin_registrant.h"
#include <url_launcher_linux/url_launcher_plugin.h>
void fl_register_plugins(FlPluginRegistry* registry) {
g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin");
url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar);
}

View File

@@ -3,6 +3,7 @@
#
list(APPEND FLUTTER_PLUGIN_LIST
url_launcher_linux
)
list(APPEND FLUTTER_FFI_PLUGIN_LIST

View File

@@ -6,7 +6,13 @@ import FlutterMacOS
import Foundation
import file_picker
import path_provider_foundation
import share_plus
import shared_preferences_foundation
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin"))
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
}

View File

@@ -137,6 +137,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.4"
file:
dependency: transitive
description:
name: file
sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4
url: "https://pub.dev"
source: hosted
version: "7.0.1"
file_picker:
dependency: "direct main"
description:
@@ -145,6 +153,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "8.3.7"
fixnum:
dependency: transitive
description:
name: fixnum
sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be
url: "https://pub.dev"
source: hosted
version: "1.1.1"
flutter:
dependency: "direct main"
description: flutter
@@ -296,6 +312,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.17.0"
mime:
dependency: transitive
description:
name: mime
sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6"
url: "https://pub.dev"
source: hosted
version: "2.0.0"
path:
dependency: transitive
description:
@@ -304,6 +328,54 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.9.1"
path_provider:
dependency: "direct main"
description:
name: path_provider
sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd"
url: "https://pub.dev"
source: hosted
version: "2.1.5"
path_provider_android:
dependency: transitive
description:
name: path_provider_android
sha256: f2c65e21139ce2c3dad46922be8272bb5963516045659e71bb16e151c93b580e
url: "https://pub.dev"
source: hosted
version: "2.2.22"
path_provider_foundation:
dependency: transitive
description:
name: path_provider_foundation
sha256: "6d13aece7b3f5c5a9731eaf553ff9dcbc2eff41087fd2df587fd0fed9a3eb0c4"
url: "https://pub.dev"
source: hosted
version: "2.5.1"
path_provider_linux:
dependency: transitive
description:
name: path_provider_linux
sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279
url: "https://pub.dev"
source: hosted
version: "2.2.1"
path_provider_platform_interface:
dependency: transitive
description:
name: path_provider_platform_interface
sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334"
url: "https://pub.dev"
source: hosted
version: "2.1.2"
path_provider_windows:
dependency: transitive
description:
name: path_provider_windows
sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7
url: "https://pub.dev"
source: hosted
version: "2.3.0"
petitparser:
dependency: transitive
description:
@@ -320,6 +392,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.0.4"
platform:
dependency: transitive
description:
name: platform
sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984"
url: "https://pub.dev"
source: hosted
version: "3.1.6"
plugin_platform_interface:
dependency: transitive
description:
@@ -360,6 +440,78 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.0.47"
share_plus:
dependency: "direct main"
description:
name: share_plus
sha256: fce43200aa03ea87b91ce4c3ac79f0cecd52e2a7a56c7a4185023c271fbfa6da
url: "https://pub.dev"
source: hosted
version: "10.1.4"
share_plus_platform_interface:
dependency: transitive
description:
name: share_plus_platform_interface
sha256: cc012a23fc2d479854e6c80150696c4a5f5bb62cb89af4de1c505cf78d0a5d0b
url: "https://pub.dev"
source: hosted
version: "5.0.2"
shared_preferences:
dependency: "direct main"
description:
name: shared_preferences
sha256: "2939ae520c9024cb197fc20dee269cd8cdbf564c8b5746374ec6cacdc5169e64"
url: "https://pub.dev"
source: hosted
version: "2.5.4"
shared_preferences_android:
dependency: transitive
description:
name: shared_preferences_android
sha256: "83af5c682796c0f7719c2bbf74792d113e40ae97981b8f266fa84574573556bc"
url: "https://pub.dev"
source: hosted
version: "2.4.18"
shared_preferences_foundation:
dependency: transitive
description:
name: shared_preferences_foundation
sha256: "4e7eaffc2b17ba398759f1151415869a34771ba11ebbccd1b0145472a619a64f"
url: "https://pub.dev"
source: hosted
version: "2.5.6"
shared_preferences_linux:
dependency: transitive
description:
name: shared_preferences_linux
sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f"
url: "https://pub.dev"
source: hosted
version: "2.4.1"
shared_preferences_platform_interface:
dependency: transitive
description:
name: shared_preferences_platform_interface
sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80"
url: "https://pub.dev"
source: hosted
version: "2.4.1"
shared_preferences_web:
dependency: transitive
description:
name: shared_preferences_web
sha256: c49bd060261c9a3f0ff445892695d6212ff603ef3115edbb448509d407600019
url: "https://pub.dev"
source: hosted
version: "2.4.3"
shared_preferences_windows:
dependency: transitive
description:
name: shared_preferences_windows
sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1"
url: "https://pub.dev"
source: hosted
version: "2.4.1"
skeletonizer:
dependency: transitive
description:
@@ -429,6 +581,46 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.4.0"
url_launcher_linux:
dependency: transitive
description:
name: url_launcher_linux
sha256: d5e14138b3bc193a0f63c10a53c94b91d399df0512b1f29b94a043db7482384a
url: "https://pub.dev"
source: hosted
version: "3.2.2"
url_launcher_platform_interface:
dependency: transitive
description:
name: url_launcher_platform_interface
sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029"
url: "https://pub.dev"
source: hosted
version: "2.3.2"
url_launcher_web:
dependency: transitive
description:
name: url_launcher_web
sha256: "4bd2b7b4dc4d4d0b94e5babfffbca8eac1a126c7f3d6ecbc1a11013faa3abba2"
url: "https://pub.dev"
source: hosted
version: "2.4.1"
url_launcher_windows:
dependency: transitive
description:
name: url_launcher_windows
sha256: "712c70ab1b99744ff066053cbe3e80c73332b38d46e5e945c98689b2e66fc15f"
url: "https://pub.dev"
source: hosted
version: "3.1.5"
uuid:
dependency: transitive
description:
name: uuid
sha256: a11b666489b1954e01d992f3d601b1804a33937b5a8fe677bd26b8a9f96f96e8
url: "https://pub.dev"
source: hosted
version: "4.5.2"
vector_math:
dependency: transitive
description:
@@ -461,6 +653,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "5.15.0"
xdg_directories:
dependency: transitive
description:
name: xdg_directories
sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
xml:
dependency: transitive
description:

View File

@@ -35,6 +35,9 @@ dependencies:
http: ^1.2.2
file_picker: ^8.1.6
image: ^4.3.0
share_plus: ^10.1.4
path_provider: ^2.1.5
shared_preferences: ^2.3.4
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.

View File

@@ -6,6 +6,12 @@
#include "generated_plugin_registrant.h"
#include <share_plus/share_plus_windows_plugin_c_api.h>
#include <url_launcher_windows/url_launcher_windows.h>
void RegisterPlugins(flutter::PluginRegistry* registry) {
SharePlusWindowsPluginCApiRegisterWithRegistrar(
registry->GetRegistrarForPlugin("SharePlusWindowsPluginCApi"));
UrlLauncherWindowsRegisterWithRegistrar(
registry->GetRegistrarForPlugin("UrlLauncherWindows"));
}

View File

@@ -3,6 +3,8 @@
#
list(APPEND FLUTTER_PLUGIN_LIST
share_plus
url_launcher_windows
)
list(APPEND FLUTTER_FFI_PLUGIN_LIST