Flutter Error: The argument type ‘String’ can’t be assigned to the parameter type ‘Uri’

The Error

If you are using a string URI when dealing with the http package in Flutter, you may be seeing this error:

The Error
The argument type 'String' can't be assigned to the parameter type 'Uri' at .... (argument_type_not_assignable)

This error is due to an update in the package.

The Solution

Parse the String to be an explicit URI by using the Uri.parse() method:

http.get(yourString) becomes http.get(Uri.parse(yourString))

http.post(yourString) becomes http.post(Uri.parse(yourString))

Here is it in an example:

String dataURL = "https://api.com/users";
http.Response response = await http.get(Uri.parse(dataURL));

To improve compile-time type safety, the http package (version 0.13.0) introduced changes that made all functions that previously accepted Uris or Strings now accept only Uris instead.

You will need to explicitly use Uri.parse to convert Strings to Uris. In the previous version, the http packaged called that for you behind the scenes.

How to Use MediaStreams in React

Do you need to access the user’s webcam for video chat or the user’s microphone for a recording? In this simple tutorial, I’ll show you how to access and use the computer’s media inputs with React.

The MediaDevices interface provides access to connected media input devices like cameras and microphones.

Get access to user’s media input

After getting the user’s permission, the MediaDevices.getUserMedia() method produces a MediaStream. This stream can have multiple tracks containing the requested types of media. Examples of tracks include video and audio tracks.

The getUserMedia() method takes in a constraints parameter with two members: video and audio, describing any configuration settings for the tracks. It returns a Promise that resolves to a MediaStream object. You can set your video element’s src to the stream.

// get the user's media stream
    const startStream = async () => {
        let newStream = await navigator.mediaDevices
          .getUserMedia({
            video: true,
            audio: true,
          })
          .then((newStream) => {
            webcamVideo.current.srcObject = newStream;
            setStream(stream);
          });

        setPlaying(true);
    };

Here are some examples of preferences that you can customize in the stream:

// Requests default video and audio
{ audio: true, video: true }

// Requests video with a preference for 1280x720 camera resolution. No audio
{
  audio: false,
  video: { width: 1280, height: 720 }
}

// Requires minimum resolution of 1280x720
{
  audio: true,
  video: {
    width: { min: 1280 },
    height: { min: 720 }
  }
}

// Browser will try to get as close to ideal as possible
{
  audio: true,
  video: {
    width: { min: 1024, ideal: 1280, max: 1920 },
    height: { min: 576, ideal: 720, max: 1080 }
  }
}

// On mobile, browser will prefer front camera 
{ audio: true, video: { facingMode: "user" } }

// On mobile, browser will prefer rear camera
{ audio: true, video: { facingMode: { exact: "environment" } } }

Save user’s media stream in a variable

After you get the user’s media stream from .getUserMedia(), you should save the stream in a state variable. This is so that you can manipulate the stream later (to stop it, get a track from it, etc.)

For example, if you want to stop the stream, get all of the stream’s tracks using the MediaStream.getTracks() method and call the .stop() method on them.

If you want to access the audio separately, use the MediaStream.getAudioTracks() method. To access video separately, use MediaStream.getVideoTracks().

You should also have state that controls if media input is on or off. You should use the useRef hook to control the video element in the DOM.

This is the final code:

import React, { useState, useRef } from 'react';

const App = () => {
    // controls if media input is on or off
    const [playing, setPlaying] = useState(false);

    // controls the current stream value
    const [stream, setStream] = useState(null);
    
    // controls if audio/video is on or off (seperately from each other)
    const [audio, setAudio] = useState(true);
    const [video, setVideo] = useState(true);

    // controls the video DOM element
    const webcamVideo = useRef();

    // get the user's media stream
    const startStream = async () => {
        let newStream = await navigator.mediaDevices
          .getUserMedia({
            video: true,
            audio: true,
          })
          .then((newStream) => {
            webcamVideo.current.srcObject = newStream;
            setStream(stream);
          });

        setPlaying(true);
    };

    // stops the user's media stream
    const stopStream = () => {
        stream.getTracks().forEach((track) => track.stop());

        setPlaying(false);
    };
    
    // enable/disable audio tracks in the media stream
    const toggleAudio = () => {
        setAudio(!audio);
        stream.getAudioTracks()[0].enabled = audio;
    };

    // enable/disable video tracks in the media stream
    const toggleVideo = () => {
       setVideo(!video);
       stream.getVideoTracks()[0].enabled = !video;
    };

    return (
      <div className="container">
	 <video ref={localVideo} autoPlay playsInline></video>
	 <button
	    onClick={playing ? stopStream : startStream}>
	    Start webcam
	 </button>

	 <button onClick={toggleAudio}>Toggle Sound</button>
	 <button onClick={toggleVideo}>Toggle Video</button>
      </div>
    );
}

export default App;

How to Embed Google Form in Website

This is how you embed a Google Form in an HTML page so that users can interact with the form directly in the page rather than having to press a link and navigate to the form in a separate window.

In the Google Form page, press the “Send” button at the top right

On the “Send form” popup, navigate to the Embed HTML tab.

Update the width and height of the form to fit the window you are going to put it in

Copy the iframe code

Paste it into the code for the HTML page you are putting the form in.

<body>

<h1>This is a form</h1>

<iframe src="https://docs.google.com/forms/d/e/1FAIpQLSf9JDsOyHEaDHD5PXQ2wzyt-th_dzUQmoCB7ad346zez1PYnA/viewform?embedded=true" width="640" height="1395" frameborder="0" marginheight="0" marginwidth="0">Loading…</iframe>

</body>