There is a widget to copy and get images from clipboard? - javascript

Goal: Copy an image from HDD and get it(by pasting it) on my Flutter web app
What I tried:
Clipboard doesn't support image type.
Pasteboard works if I add images manually (from the app), but I need to add images from the desktop by copying it and for this it doesn't work. In particular the error is that image type is not supported.
Manually doing it using Javascript APIs and the result is the same of pasteboard.
I hope that my answer is clear. Thank you!
Example code using Pasteboard:
import 'package:flutter/material.dart';
import 'package:pasteboard/pasteboard.dart';
class TestPage extends StatefulWidget {
const TestPage({super.key});
#override
State<TestPage> createState() => _TestPageState();
}
class _TestPageState extends State<TestPage> {
#override
Widget build(BuildContext context) {
return Column(
children: [
Container(
width: 500,
height: 500,
color: Colors.red,
),
TextButton(
onPressed: () async {
// works if you copy text
var text = await Pasteboard.text;
print("text: $text");
// works if you copy text, returns null if you copy an image
var html = await Pasteboard.html;
print("text: $html");
// Returns always null
var image = await Pasteboard.image;
print(image);
},
child: const Text('Click me', style: TextStyle(fontSize: 20)),
),
],
);
}
}

Related

EditorJs warning "«blocks.stretchBlock()» is deprecated and will be removed in the next major release. Please use the «BlockAPI» instead."

I'm using EditorJs but it is giving me this warning in the console
«blocks.stretchBlock()» is deprecated and will be removed in the next major release. Please use the «BlockAPI» instead.
How can I use «BlockAPI» in EditorJs?
Here is my EditorJs init:
const editor = new EditorJS({
tools: {
header: Header,
list: List,
image: Image,
embed: {
class: Embed,
config: {
services: {
youtube: true
}
}
},
},
})
Block API is passed via constructor props in block prop. You have to get it from there and set it to your block's property.
It should look something like this:
class CustomBlock {
private data;
private block;
constructor({
data,
block
}) {
this.data = data;
this.block = block;
}
toggleStretched() {
this.block.stretched = !!this.data.stretched;
}
// Rest of the block implementation
}
It seems that the official docs aren't up-to-date, however I found this file with a description of Block API.

Unable to open tel, mailto, whatsapp links in a flutter webview?

I am a web developer and beginner to flutter. I created a Flutter web view application by watching a few tutorials and its working fine for iOS and Android. But when I click on '0123456789', mailto:'abc#gmail.com', WhatsApp link (https://wa.me/9712345678), it's going page Not Found. I want to open an external application for those conditions. How to handle this task in a flutter to support in iOS and Android? I used the flutter webview plugin to launch a url like:
And may i know where to add this following code to work ?
if (request.url.contains("mailto:")) {
_launchURL(request.url);
return NavigationDecision.prevent;
} else if (request.url.contains("tel:")) {
_launchURL(request.url);
return NavigationDecision.prevent;
} else if (request.url.contains("sms:")) {
_launchURL(request.url);
return NavigationDecision.prevent;
}
return NavigationDecision.navigate;
},
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_webview_plugin/flutter_webview_plugin.dart';
import 'package:flutter_offline/flutter_offline.dart';
import 'package:location/location.dart';
import 'package:url_launcher/url_launcher.dart';
_launchURL(url) async {
if (await canLaunch(url)) {
await launch(url);
} else {
throw 'Could not launch $url';
}
}
void main() => runApp(MyApp());
Color btnColor = Color(0xff03a9f3);
Color bgColor = Color(0xffe9f4fc);
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Qavenue',
home: OfflineBuilder(
connectivityBuilder: (
BuildContext context,
ConnectivityResult connectivity,
Widget child,
) {
final bool connected = connectivity != ConnectivityResult.none;
return Container(
child: connected
? MyHomePage()
: Center(
child: Image.asset(
'assets/offline_blue.gif',
fit: BoxFit.cover,
width: 200.0,
),
),
color: bgColor,
);
},
child: MyHomePage(),
),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String url = "https://example.xyz/";
final flutterWebviewPlugin = new FlutterWebviewPlugin();
StreamSubscription<WebViewStateChanged>
_onchanged; // here we checked the url state if it loaded or start Load or abort Load
#override
void initState() {
super.initState();
_onchanged =
flutterWebviewPlugin.onStateChanged.listen((WebViewStateChanged state) {
if (mounted) {
if (state.type == WebViewState.finishLoad) {
// if the full website page loaded`
print("loaded");
} else if (state.type == WebViewState.abortLoad) {
// if there is a problem with loading the url
print("there is a problem");
} else if (state.type == WebViewState.startLoad) {
// if the url started loading
print("start loading");
}
}
});
}
#override
void dispose() {
super.dispose();
flutterWebviewPlugin
.dispose(); // disposing the webview widget to avoid any leaks
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: WillPopScope(
onWillPop: () {
flutterWebviewPlugin.canGoBack().then((value) {
if (value) {
flutterWebviewPlugin.goBack();
} else {
exit(0);
}
});
},
child: WebviewScaffold(
url: url,
withJavascript: true,
withZoom: false,
hidden: true,
geolocationEnabled: true,
initialChild: Container(
color: Colors.white,
child: Center(
child: Image.asset('assets/icon/images/logo1.jpg'),
),
),
)),
);
}
}
One way to solve this is to import url_launcher_string.dart too. You will need it when you specify the links.
import 'package:url_launcher/url_launcher_string.dart';
Run flutter pub get and then inside your main app dart (e.g main.dart) you tell it how to handle the urls.
launchURL(url) async {
if (await canLaunchUrl(url)) {
await launchUrl(url);
} else {
throw 'Could not launch $url';
}
}
The above part of code could be anywhere. You could also put it inside another dart and import it. It'd be better of course if you put it inside your webview widget class and not just anywhere like you did, unless you need to use it somewhere else too.
Afterwards you specify inside the webview widget class how to handle the urls.
e.g inside the:
class WebViewApp extends StatefulWidget {
}
The 'NavigationDecision' part of code.
e.g:
NavigationDecision _interceptNavigation(NavigationRequest request) {
if (request.url.contains("mailto:")) {
launchUrlString('mailto:specify email address here');
return NavigationDecision.prevent;
} else if (request.url.contains("tel:")) {
launchUrlString('tel:specify telephone number here');
return NavigationDecision.prevent;
}
return NavigationDecision.navigate;
}
In the above part of code you define the "request" and then you tell it what to do with each request. So if you define 'NavigationRequest request' then you tell it what to do with each request. If you define 'NavigationRequest name' then you specify what to do with that name. e.g.
NavigationDecision _interceptNavigation(NavigationRequest name) {
if (name.url.contains("mailto:")) {
launchUrlString('mailto:specify email address here');
return NavigationDecision.prevent;
} else if (name.url.contains("tel:")) {
launchUrlString('tel:specify telephone number here');
return NavigationDecision.prevent;
}
return NavigationDecision.navigate;
}
You can add more urls of course by editing the name.url.contains line and adding more else if decisions. e.g. whatsapp, telegram, viber, and so on. Just like you did with the sms.
Do not forget to call for your navigation decision code when you need it.
Inside your override where you tell your webview what's the initial url, you call your navigation decision with the name you set to it. e.g:
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: WebView(
initialUrl: 'https:url', // Webview initial url here
javascriptMode: JavascriptMode.unrestricted, // Enable use of javascript
navigationDelegate: _interceptNavigation, // Call for your navigation decision
),
)
);
}
We named it '_interceptNavigation' so that's what we call for. And that's as far as understanding that part of code. I hope that helped you. I explained it step by step for beginners too.

Gatsby markdown frontmatter link becomes a relative file path after GraphQL static query

I am trying to store content for a button that will navigate the user to a different page in my markdown frontmatter, as it is to be editable through Netlify CMS.
When the GraphQL static query brings back data, my frontmatter has been converted into a relative file path rather than the intended page URL. This doesn't happen with page queries.
footer.md:
---
templateKey: footer
title: Some footer title
logo: /img/logo.svg
links:
- url: /prices/
text: Prices
- url: /privacy-policy/
text: Privacy policy
---
GraphQL static query:
const queryData = useStaticQuery(graphql`
query FooterComponent {
site {
siteMetadata {
title
}
}
markdownRemark(frontmatter: { templateKey: { eq: "footer" } }) {
frontmatter {
title
logo {
publicURL
}
links {
url
text
}
}
}
}
`);
Data that gets returned:
{
"title":"Some footer title",
"logo":{"publicURL":"/static/6731239d1e0c5fcdf0f825a8de82be10/logo.svg"},
"links":[
{"url":"../pages/prices","text":"Prices"},
{"url":"../pages/privacy-policy","text":"Privacy policy"}
]
}
You can see that the URL for the objects in the links array have been converted to relative file paths, rather than returning the actual link from the frontmatter as it is in the original markdown file.
How can I retrieve the actual link?
Reading your comment on the other answer, I think the issue is with fmImagesToRelative. It keeps track of all created nodes, then tries to match each frontmatter field value with all file node's path.
A quickfix would to 'preserve' those frontmatter fields before running fmImagesToRelative, then restore them afterward. So you would literally work around that function, like this:
exports.onCreateNode = ({ node }) => {
const isRemarkNode = node.internal.type === 'MarkdownRemark'
const originalFields = {}
if (isRemarkNode) {
Object.entries(node.frontmatter).forEach(([k, v]) => {
if (['links', 'some_other_field'].includes(k)) {
/* preserve */
originalFields[k] = v
/* remove the field to avoid unnecessary work */
delete node.frontmatter[k]
}
})
}
/* this function won't work without access to literally all nodes, hence why we leave it in the middle like this */
fmImagesToRelative(node)
if (isRemarkNode) {
/* restore */
node.frontmatter = {
...node.frontmatter,
...originalFields
}
}
}
Personally, I prefer to only modify fields that I know are files. With your example, I would rather declare that 'logo' is an image file, than excluding 'links'.
As a fellow NetlifyCMS user, I use createSchemaCustomization to modify known file fields... It's rather complicated (as with anything Gatsby), so I wrote a plugin to simplify this.
So my approach would look like this:
exports.createSchemaCustomization = ({ actions }) => {
actions.createTypes(`
type Frontmatter #infer {
logo: File #fileByAbsolutePath(path: "static")
}
type MarkdownRemark implements Node #infer {
frontmatter: Frontmatter
}
`)
}
In the example above, #fileByAbsolutePath is a field extension that takes logo value (i.e img/logo.png) & resolve it with static, so when you query your markdown file you'd get a File node pointing to root/static/img/logo.png.
It would be neat for fmImagesToRelative to have exclude/include arguments, though I'm not a fan of the blanket approach.

braintree into flutter web using JS got this error "options.selector or options.container must reference a valid DOM node"

Trying to implement Braintree payment gateway into flutter web.
Still no SDK for flutter web from Braintree. So trying to implement their javascript SDK.
Here is my js file
function payment(auth){
var button = document.querySelector('submit-button');
console.log(auth);
console.log(button);
braintree.dropin.create({
authorization: auth,
container: 'dropin-container'
}, function (createErr, instance) {
console.log(createErr);
console.log(instance);
button.addEventListener('click', function () {
instance.requestPaymentMethod(function (requestPaymentMethodErr, payload) {
// Submit payload.nonce to your server
return payload.nonce
});
});
});
}
Calling this js function from dart. Here is the complete dart code.
#JS()
library my_script;
import 'dart:html';
import 'dart:js_util';
import 'package:carbonbins/model/model.dart';
import 'package:carbonbins/pages/navigation.gr.dart';
import 'package:carbonbins/utils/image_helper.dart';
import 'package:flutter/material.dart';
import 'dart:ui' as ui;
import 'package:js/js.dart';
import 'package:js/js.dart' as js;
#JS()
external void initBraintree(auth);
#JS()
external String payment(auth);
class PaymentPage extends StatefulWidget {
final UserModel userModel;
PaymentPage({#required this.userModel});
#override
_PaymentPageState createState() => _PaymentPageState();
}
class _PaymentPageState extends State<PaymentPage> {
String auth = "sandbox_.....";
void getButton() {
var htmlL = """<div id="checkout-message"></div>
<div id="dropin-container"></div>
<button id="submit-button">Submit payment</button>""";
// ignore: undefined_prefixed_name
ui.platformViewRegistry.registerViewFactory(
'payment-container',
(int viewId) => DivElement()
..appendHtml(htmlL)
..style.border = 'none');
print(HtmlElementView(
viewType: "dropin-container",
));
}
void setupDropin() {
print(auth);
var status = payment(auth);
print("Status: $status");
}
#override
void initState() {
getButton();
setupDropin();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
width: MediaQuery.of(context).size.width,
child: Column(
children: <Widget>[
SizedBox(
height: 100,
),
Container(
width: 500.0,
height: 300.0,
child: HtmlElementView(
viewType: "payment-container",
),
)
],
),
),
);
}
When I run this code, I see only the submit button in the screen. Got this error from web console,
"options.selector or options.container must reference a valid DOM node."
How can I integrate the Braintree payment into the flutter web?
or any other international payment gateway that works in flutter web.
Technical Disclaimer: flutter-web is in beta and I would not recommend it to be used with any payment service. This might lead to critical issues and not advisable.
The HtmlElementView widget adds all its elements into shadowdom which is not directly accessible for the global javascript context. Check this issue here in github.
The solution would be to pass the DivElement reference to the external js function. For e.g. in your case
Create the div element out side the build method and hold a reference, like in initSate
DivElement paymentDiv;
#override
initState(){
// always call before rest of the logic.
super.initState();
var htmlL = """<div id="checkout-message"></div>
<div id="dropin-container"></div>
<button id="submit-button">Submit payment</button>""";
paymentDiv= DivElement()
..appendHtml(htmlL)
..style.border = 'none');
// remaining logic
}
Then in your build/other method pass this element for the registerViewFactory method.
// ignore: undefined_prefixed_name
ui.platformViewRegistry.registerViewFactory(
'payment-container',
(int viewId) => paymentDiv;
Set you JS interop to accept dynamic parameter.
#JS()
external String payment(dynamic auth);
Rewrite you Javascript to directly work with this element reference. e.g
function payment(auth){
var button = auth;
// Remaining logic
}

VIDEOJS: ERROR: TypeError: Cannot read property 'value' of undefined Angular 5

I recently discovered the videojs-thumbnails plugin for video.js and I want to implement it to my angular component, however, I keep receiving this error of
VIDEOJS: ERROR: TypeError: Cannot read property 'value' of undefined at Function.updateThumbnailTime
I've implemented videojs-thumbnails.js via
declare var thumbnails: any;
I've also ensured that videojs-thumbnails was imported to the .angular-clic.json as
"styles": [
"../node_modules/video.js/dist/video-js.css",
"../node_modules/videojs-resolution-switcher/lib/videojs-resolution-switcher.css",
"../node_modules/videojs-thumbnails/dist/browser/videojs-thumbnails.css",
"styles.scss"
],
"scripts": [
"../node_modules/video.js/dist/video.js",
"../node_modules/videojs-resolution-switcher/lib/videojs-resolution-switcher.js",
"../node_modules/videojs-thumbnails/dist/browser/videojs-thumbnails.js"
Through the videojs-thumbnails.js I keep returning the error of
VIDEOJS: ERROR: TypeError: Cannot read property 'value' of undefined at Function.updateThumbnailTime
Here is what the full component looks like
import { Component, OnInit, OnDestroy, ElementRef, Input } from '#angular/core';
interface VideoJSStatic {
(id: any, options?: any, ready?: () => void): any;
}
declare var videojs:VideoJSStatic;
declare var videoJsResolutionSwitcher: any;
declare var thumbnails: any;
#Component({
selector: 'videojs',
template:`
<video *ngIf="url" id="video_{{idx}}"
class="video-js vjs-default-skin vjs-big-play-centered vjs-16-9"
controls preload="auto" width="640" height="264">
</video>
`,
})
export class VideoJsComponent implements OnInit, OnDestroy {
// reference to the element itself, we use this to access events and methods
private _elementRef: ElementRef
// index to create unique ID for component
#Input() idx: string;
// video asset url
#Input() url: any;
//Video Resolution
#Input() private options: any = {};
#Input() private sources: Array<string> = new Array<string>();
// declare player var
private player: any;
// constructor initializes our declared vars
constructor(elementRef: ElementRef) {
this.url = false;
this.player = false;
}
ngOnInit() {}
ngOnDestroy(){}
// use ngAfterViewInit to make sure we initialize the videojs element
// after the component template itself has been rendered
ngAfterViewInit() {
//Trial for Video Resoultion
this.options.plugins = {
videoJsResolutionSwitcher: {
default: 'low',
dynamicLabel: true
},
};
// ID with which to access the template's video element
let el = 'video_' + this.idx;
// setup the player via the unique element ID
this.player = videojs(document.getElementById(el),this.options, function() {
this.updateSrc([
{
src: 'http://vjs.zencdn.net/v/oceans.mp4',
type: 'video/mp4',
label: '1080p'
},
{
src: 'http://vjs.zencdn.net/v/oceans.mp4',
type: 'video/mp4',
label: '720p'
},
{
src: 'http://vjs.zencdn.net/v/oceans.mp4',
type: 'video/mp4',
label: '480p'
},
{
src: 'http://vjs.zencdn.net/v/oceans.mp4',
type: 'video/mp4',
label: '240p'
}
])
this.on('resolutionchange', function(){
console.info('Source changed to %s', this.src())
});
//Videojs Thumbnails
this.thumbnails({
0: {
src: 'http://example.com/thumbnail1.png',
width: '120px'
},
5: {
src: 'http://example.com/thumbnail2.png'
}
});
// Store the video object
var myPlayer = this, id = myPlayer.id();
// Make up an aspect ratio
var aspectRatio = 264/640;
// internal method to handle a window resize event to adjust the video player
function resizeVideoJS(){
var width = document.getElementById(id).parentElement.offsetWidth;
myPlayer.width(width);
myPlayer.height( width * aspectRatio );
}
// Initialize resizeVideoJS()
resizeVideoJS();
// Then on resize call resizeVideoJS()
window.onresize = resizeVideoJS;
});
}
}
I know that the library has been imported because if I place
import '../../../node_modules/videojs-thumbnails/dist/browser/videojs-thumbnails.js'
into the component,
I get a return error:
VIDEOJS: WARN: A plugin named "thumbnails" already exists. You may want to avoid re-registering plugins
I've also tried importing it via import * as thumbnails from 'videojs-thumbnails';
Being relatively new to the Angular environment, I've tried multiple importation methods for this library, but they all result in the same thing. What I'm not understanding is that a previous third party plugin called videoJsResolutionSwitcher was imported the same way and I was able to call the updateSrc method without any errors.
Also, my version of video.js is 6.7.3, videojs-resolution-switcher at 0.4.3 and videojs-thumbnails is at version 1.0.3.
Well this is embarrassing, The problem to begin with was that I was using a different package than what I thought I had downloaded, and thus used the wrong syntax. The solution was I was using properties that didn't exist with this library. The right way to use the .thumbnails() method is by using
this.thumbnails(
{
// width of the single sprite clip
width: 100,
// url to sprite image
spriteUrl: "//path/to/sprite.jpg",
// how often to change thumbnail on timeline ( ex. every 2sec )
stepTime: 2,
}
);
I thought I was using Brightcove's version of videojs-thumbnails. Instead I was using a package from npm which was written by someone else but uses the same name unfortunately and not explicitly stated that it's much different.
Furthermore, I ended up using a different library altogether that uses webVTT files and sprites instead.

Categories