junsiong2008
junsiong2008

Reputation: 117

Ineffective Passing of Variable between Different Screens

I'm currently developing a Fingerspelling learning app. In the fingerspelling_screen.dart file, user will be able to choose which category that he/she would like to learn first. When the user chooses either one of the button, the app will query Firebase Firestore to get a list of signs object which contains the name of the sign, the category to which the sign belongs to and the video URL of each sign before navigating user to sign_video.dart which is a video player. From there, user can press next to switch to the next sign in the category. When the user presses on the check sign button, the user will be navigating to the check sign_checker.dart to check if they are performing a sign correctly.

I've been passing the 'category' variable from one screen to another using constructor and I do not think it is very effective. Is there any way I could solve this?

I wish to initilize vidlist variable (a variable that stores a list of Sign objects) in the initState because the video player controller needs to be initialized first. I've tried using StreamProvider, but for some reason, I couldn't initialize the vidlist variable in initState. The vidlist variable would always be null.

Thank you.

fingerspelling.dart

import 'package:slem_proto/screens/sign_video.dart';
import 'package:slem_proto/shared/constants.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:undraw/undraw.dart';

class FingerspellingScreen extends StatelessWidget {
  static String routeName = 'fingerspelling_screen';
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Padding(
        padding: EdgeInsets.only(left: 20, right: 20, top: 50),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text(
              'Fingerspelling',
              style: kHeadingTextStyle,
            ),
            SizedBox(height: 30),
            FingerspellingTab(
              title: 'Alphabets',
              illustration: UnDrawIllustration.learning,
              onTap: () {
                print('Alphabet tab tapped');
                Navigator.push(
                  context,
                  MaterialPageRoute(
                    builder: (context) => SignVideoScreen(
                      category: 'alphabets',
                    ),
                  ),
                );
              },
            ),
            SizedBox(
              height: 15,
            ),
            FingerspellingTab(
              title: 'Numbers',
              illustration: UnDrawIllustration.calculator,
              onTap: () {
                print('Number tab tapped');
                Navigator.push(
                  context,
                  MaterialPageRoute(
                    builder: (context) => SignVideoScreen(
                      category: 'numbers',
                    ),
                  ),
                );
              },
            ),
          ],
        ),
      ),
    );
  }
}

class FingerspellingTab extends StatelessWidget {
  final String title;
  final UnDrawIllustration illustration;
  final Function onTap;

  const FingerspellingTab(
      {@required this.title,
      @required this.illustration,
      @required this.onTap});

  @override
  Widget build(BuildContext context) {
    return InkWell(
      child: Container(
        width: double.infinity,
        height: 250,
        decoration: BoxDecoration(
          color: Color.fromRGBO(58, 139, 238, 0.2),
          borderRadius: BorderRadius.circular(20),
        ),
        child: Padding(
          padding: const EdgeInsets.only(left: 20, top: 20),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Text(
                title,
                style: kHeadingTextStyle.copyWith(
                  color: Color.fromRGBO(80, 80, 80, 0.8),
                  fontSize: 25,
                ),
              ),
              SizedBox(
                height: 15,
              ),
              Container(
                height: 150,
                child: UnDraw(
                  color: Color(0xFF6C63FF),
                  illustration: illustration,
                  placeholder: Text(
                      "Illustration is loading..."), //optional, default is the CircularProgressIndicator().
                ),
              ),
            ],
          ),
        ),
      ),
      onTap: onTap,
    );
  }
}

database.dart

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:slem_proto/models/sign.dart';

class DatabaseService {
  // collection reference
  final CollectionReference signCollection =
      FirebaseFirestore.instance.collection('signs');

  // Sign list from snapshot
  List<Sign> _signListFromSnapshot(QuerySnapshot snapshot) {
    return snapshot.docs.map((doc) {
      return Sign(
        category: doc.data()['category'] ?? '',
        sign_name: doc.data()['sign_name'] ?? '',
        sign_url: doc.data()['sign_url'] ?? '',
      );
    }).toList();
  }

  // get signs stream
  Stream<List<Sign>> get signs {
    return signCollection.snapshots().map(_signListFromSnapshot);
  }

  // get signs stream
  Stream<List<Sign>> getSignFromCategory({String category}) {
    return signCollection
        .where('category', isEqualTo: category)
        .snapshots()
        .map(_signListFromSnapshot);
  }
}

sign_checker.dart

import 'dart:convert';
import 'dart:io';

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:image_picker/image_picker.dart';

class SignChecker extends StatefulWidget {
  final String category;
  SignChecker({this.category});

  @override
  _SignCheckerState createState() => _SignCheckerState(category: this.category);
}

class _SignCheckerState extends State<SignChecker> {
  final String category;
  _SignCheckerState({this.category});

  File _image;
  bool predictionStarted = false;
  bool predictionComplete = false;
  var predictionResult = 'Please wait...';

  Future getImage() async {
    setState(() {
      predictionStarted = false;
      predictionComplete = false;
    });

    // Get image from camera
    // var image = await ImagePicker.pickImage(source: ImageSource.camera);

    // Get image from gallery
    var image = await ImagePicker.pickImage(source: ImageSource.gallery);
    setState(() {
      _image = image;
      predictionStarted = true;
    });

    // Base64 Encode the image
    List<int> imageBytes = image.readAsBytesSync();
    String base64Image = base64.encode(imageBytes);

    // Print the base64 encoded string in console
    print(base64Image);

    // Send the encoded image with POST request
    Map<String, String> headers = {"Accept": "application/json"};
    Map body = {"image": base64Image};

    
    // var response = await http.post('http://XX.XXX.XXX.X/automl.php',
    //     body: body, headers: headers);
    var response = await http.post('http://XX.XXX.XXX.X/automl_alphabet.php',
        body: body, headers: headers);

    // Print the status code returned by server
    print('Status code');
    print(response.statusCode);

    // Get prediction Result
    setState(() {
      predictionResult = response.body;
      predictionComplete = true;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Sign Checker'),
      ),
      body: SingleChildScrollView(
        child: Column(
          children: <Widget>[
            SizedBox(
              height: 20,
            ),
            Text(
              'Push the camera button',
              textAlign: TextAlign.center,
            ),
            RaisedButton(
              onPressed: getImage,
              child: Text('Camera'),
            ),
            (_image != null)
                ? Image.file(
                    _image,
                    scale: 50,
                  )
                : Text('No Image Picked'),
            predictionBody()
          ],
        ),
      ),
    );
  }

  Widget predictionBody() {
    var predictionText = (predictionComplete) ? 'Result' : 'Prediction started';
    if (predictionStarted) {
      return Column(
        children: <Widget>[
          Divider(),
          Text(predictionText),
          Text(predictionResult)
        ],
      );
    } else {
      return Container();
    }
  }
}

sign.dart

class Sign {
  final String category;
  final String sign_name;
  final String sign_url;
  Sign({this.category, this.sign_name, this.sign_url});
}

Upvotes: 0

Views: 48

Answers (1)

ch271828n
ch271828n

Reputation: 17597

Firstly, using constructors to pass variables may not be inefficient, since Flutter only pass on references. Say,

var a = List(...huge list...);
var b = a;

Then the second line is not costly.

Secondly, if you ask about state management, you may try Mobx, Bloc, Redux, etc. There are many ways to do so.

Upvotes: 1

Related Questions