Membuat aplikasi sederhana tebak jenis kelamin dengan flutter

Siang semuanya, hari ini saya ingin membagi tutorial sederhana Membuat aplikasi sederhana tebak jenis kelamin dengan Flutter dengan memanfaatkan API dari website genderize.io .Jadi cara kerja aplikasi ini nantinya dengan hanya memasukkan nama,aplikasi akan menampilkan tebakan atau prediksi jenis kelamin dari nama tersebut...

OK pertama tama kita tambahkan package http ke file pubspec.yaml selanjutnya jangan lupa untuk melakukan perintah flutter pub get agar package di load ke project kita...

Selanjutnya buat kan Directory baru dengan nama screen dan didalam directory tersebut kita buat file dart baru dengan nama home_screen ...maka tampilan struktur project nya seperti ini

Lalu masuk ke file main.dart dan ubah code nya seperti dibawah

import 'package:flutter/material.dart';
import 'package:tebak_jenis_kelamin/screen/home_screen.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: HomeScreen(),
    );
  }
}

Setelah langkah diatas selesai diikuti selanjutnya masuk ke file home_screen.dart di dalam file ini kita akan membuat layout beserta logic untuk tebak jenis kelamin berdasarkan nama, Untuk code nya seperti dibawah :
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';

class HomeScreen extends StatefulWidget {
  HomeScreen({Key? key}) : super(key: key);

  @override
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  final TextEditingController _namaController = TextEditingController();
  final String faseLoading = "faseLoading";
  final String faseDone = "faseDone";
  String fase = "";

  String? nama;
  String? jenisKelamin;

  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Scaffold(
        appBar: AppBar(
          elevation: 0,
          title: const Text(
            "Tebak Jenis Kelamin",
            style: TextStyle(fontSize: 20),
          ),
        ),
        body: SingleChildScrollView(
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.center,
            children: [
              _search(context),
              fase == ""
                  ? Container()
                  : fase == faseLoading
                      ? Container(
                          margin: const EdgeInsets.only(top: 20),
                          child: const CircularProgressIndicator())
                      : _jenisKelamin()
            ],
          ),
        ),
      ),
    );
  }

  Widget _search(BuildContext context) {
    return Container(
      padding: const EdgeInsets.symmetric(horizontal: 1),
      color: const Color(0xFFEEEEEE),
      child: Card(
        shape: const RoundedRectangleBorder(
            borderRadius: BorderRadius.all(Radius.circular(3))),
        clipBehavior: Clip.antiAliasWithSaveLayer,
        child: Row(
          children: <Widget>[
            Expanded(
              child: Container(
                padding: const EdgeInsets.only(left: 10, right: 5),
                decoration: const BoxDecoration(
                  borderRadius: BorderRadius.only(
                      topLeft: Radius.circular(5),
                      bottomLeft: Radius.circular(5)),
                ),
                child: TextFormField(
                    controller: _namaController,
                    focusNode: FocusNode(canRequestFocus: false),
                    onSaved: (val) {},
                    cursorColor: Theme.of(context).colorScheme.primary,
                    decoration: const InputDecoration(
                      hintText: 'Masukkan nama',
                      hintStyle:
                          TextStyle(fontSize: 16.0, color: Color(0xFFcccccc)),
                      errorStyle: TextStyle(height: 0),
                      enabledBorder: UnderlineInputBorder(
                        borderSide: BorderSide(color: Colors.transparent),
                      ),
                      focusedBorder: UnderlineInputBorder(
                        borderSide: BorderSide(color: Colors.transparent),
                      ),
                      border: UnderlineInputBorder(
                        borderSide: BorderSide(color: Colors.transparent),
                      ),
                    ),
                    style:
                        const TextStyle(color: Colors.black, fontSize: 16.0)),
              ),
            ),
            GestureDetector(
              onTap: () {
                if (_namaController.text != "") {
                  tebakJenisKelamin();
                  FocusScope.of(context).requestFocus(FocusNode());
                } else {
                  setFase("");
                  ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
                    content: Text("Nama belum diisi"),
                  ));
                }
              },
              child: Wrap(
                children: [
                  Container(
                    padding: const EdgeInsets.symmetric(
                        vertical: 12, horizontal: 10),
                    decoration: BoxDecoration(
                        color: Theme.of(context).colorScheme.primary,
                        borderRadius: const BorderRadius.only(
                            bottomRight: Radius.circular(3),
                            topRight: Radius.circular(3))),
                    child: const Icon(
                      Icons.search,
                      color: Colors.white,
                    ),
                  ),
                ],
              ),
            )
          ],
        ),
      ),
    );
  }

  Widget _jenisKelamin() {
    if (jenisKelamin != null) {
      return Container(
        margin: const EdgeInsets.only(top: 20),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            Text(
              jenisKelamin == "male" ? "Laki-laki" : "Perempuan",
              style: const TextStyle(fontSize: 25, fontWeight: FontWeight.bold),
            ),
            Icon(
              jenisKelamin == "male" ? Icons.male : Icons.female,
              color: jenisKelamin == "male" ? Colors.blue : Colors.pink,
              size: 100,
            ),
          ],
        ),
      );
    }

    return Container();
  }

  tebakJenisKelamin() async {
    setFase(faseLoading);
    var url =
        Uri.parse('https://api.genderize.io/?name=${_namaController.text}');
    var response = await http.get(url);
    var body = json.decode(response.body);
    setState(() {
      jenisKelamin = '${body['gender']}';
      setFase(faseDone);
    });
  }

  setFase(String fase) {
    setState(() {
      this.fase = fase;
    });
  }
}

Demikian tutorial kali ini..semoga tulisan ini bermanfaat untuk yang membaca tulisan ini serta untuk penulis pribadi....

Terima kasih!!!!

Tutorial Ambil Gambar dari Galeri dan Kamera di Flutter

    Tutorial kali ini kita akan membahas bagaimana implementasi package image_picker pada project flutter kita agar bisa mengambil gambar dari galeri atau kamera,disini saya menggunakan package image_picker dengan versi ^0.8.4+4, untuk melihat versi terbaru silahkan kunjungi link disini. Project ini sudah mendukung null safety sehingga jika teman-teman ingin ikuti tutorial ini saya sarankan agar upgrade versi flutter anda agar mendukung null safety...


Pertama kita tambahkan package image_picker pada file pubspec.yaml, selanjutnya jangan lupa untuk melakukan perintah pub get agar package di load ke project kita...

Berikutnya jika langkah di atas sudah dilakukan kita akan memulai membuat design halaman awal dengan tampilan gambar seperti di bawah


untuk code nya seperti ini:

    return Scaffold(
        appBar: AppBar(
          elevation: 0,
          leadingWidth: 35,
          iconTheme: const IconThemeData(color: Colors.white),
          title: Container(
            padding: const EdgeInsets.only(top: 10, bottom: 10),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: const <Widget>[
                Text(
                  "Image Picker",
                  style: TextStyle(color: Colors.white, fontSize: 18),
                ),
              ],
            ),
          ),
          actions: [
            GestureDetector(
                onTap: () {
                  showModalBottomSheet(
                    context: context,
                    backgroundColor: Colors.transparent,
                    builder: ((builder) => _ambilGambar()),
                  );
                },
                child: Container(
                    padding: const EdgeInsets.only(right: 8),
                    child: const Icon(Icons.image_search)))
          ],
        ),
        body: Container(
          color: const Color(0xFFf2f2f2),
          child: _image == null
              ? const Center(
                  child: Icon(
                  Icons.image_aspect_ratio,
                  color: Color(0xFFE0E0E0),
                  size: 100,
                ))
              : Image(
                  width: double.infinity,
                  height: double.infinity,
                  image: FileImage(File(_image!.path))),
        ));

Selanjutnya kita akan membuat tampilan bottom sheet dialog beserta aksi tombol dimana design nya akan menampilkan dua pilihan untuk memilih mengambil gambar dari camera atau galeri

source code untuk Widget tampilan bottom sheet dialog beserta logicnya :

 Widget _ambilGambar() {
    return Container(
      width: MediaQuery.of(context).size.width,
      decoration: const BoxDecoration(
        color: Colors.white,
        borderRadius: BorderRadius.only(
            topLeft: Radius.circular(10), topRight: Radius.circular(10)),
      ),
      child: Wrap(
        children: <Widget>[
          Container(
            width: double.infinity,
            padding: const EdgeInsets.only(top: 10, bottom: 20),
            child: const Text(
              "Ambil Gambar",
              textAlign: TextAlign.center,
              style: TextStyle(fontSize: 20.0, fontWeight: FontWeight.bold),
            ),
          ),
          Row(mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[
            Expanded(
              flex: 1,
              child: GestureDetector(
                onTap: () {
                  Navigator.pop(context);
                  getImage(ImageSource.camera);
                },
                child: Column(
                  children: [
                    const Icon(
                      Icons.camera,
                      size: 40,
                    ),
                    Container(
                        margin: const EdgeInsets.only(top: 5),
                        child: const Text("Ambil dari Kamera"))
                  ],
                ),
              ),
            ),
            Expanded(
              flex: 1,
              child: GestureDetector(
                onTap: () {
                  Navigator.pop(context);
                  getImage(ImageSource.gallery);
                },
                child: Column(
                  children: [
                    const Icon(
                      Icons.image,
                      size: 40,
                    ),
                    Container(
                        margin: const EdgeInsets.only(top: 5),
                        child: const Text("Ambil dari Galeri"))
                  ],
                ),
              ),
            ),
          ]),
          Container(
              width: double.infinity,
              padding: const EdgeInsets.symmetric(vertical: 10),
              margin: const EdgeInsets.only(top: 20),
              color: Theme.of(context).colorScheme.primary,
              child: const Text(
                'TUTUP',
                textAlign: TextAlign.center,
                style: TextStyle(
                    color: Colors.white,
                    fontSize: 20,
                    fontWeight: FontWeight.bold),
              ))
        ],
      ),
    );
  }

  Future getImage(ImageSource src) async {
    var image = await _picker.pickImage(source: src);
    setState(() {
      _image = image;
    });
  }

Tampilan ketika memilih camera atau galeri dan hasilnya:

Untuk source code lengkapnya:
import 'dart:io';

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

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Image Picker',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.teal,
      ),
      home: const ImagePickerPage(),
    );
  }
}

class ImagePickerPage extends StatefulWidget {
  const ImagePickerPage({Key? key}) : super(key: key);

  @override
  State<ImagePickerPage> createState() => _ImagePickerPageState();
}

class _ImagePickerPageState extends State<ImagePickerPage> {
  XFile? _image;
  final ImagePicker _picker = ImagePicker();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          elevation: 0,
          leadingWidth: 35,
          iconTheme: const IconThemeData(color: Colors.white),
          title: Container(
            padding: const EdgeInsets.only(top: 10, bottom: 10),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: const <Widget>[
                Text(
                  "Image Picker",
                  style: TextStyle(color: Colors.white, fontSize: 18),
                ),
              ],
            ),
          ),
          actions: [
            GestureDetector(
                onTap: () {
                  showModalBottomSheet(
                    context: context,
                    backgroundColor: Colors.transparent,
                    builder: ((builder) => _ambilGambar()),
                  );
                },
                child: Container(
                    padding: const EdgeInsets.only(right: 8),
                    child: const Icon(Icons.image_search)))
          ],
        ),
        body: Container(
          color: const Color(0xFFf2f2f2),
          child: _image == null
              ? const Center(
                  child: Icon(
                  Icons.image_aspect_ratio,
                  color: Color(0xFFE0E0E0),
                  size: 100,
                ))
              : Image(
                  width: double.infinity,
                  height: double.infinity,
                  image: FileImage(File(_image!.path))),
        ));
  }

  Widget _ambilGambar() {
    return Container(
      width: MediaQuery.of(context).size.width,
      decoration: const BoxDecoration(
        color: Colors.white,
        borderRadius: BorderRadius.only(
            topLeft: Radius.circular(10), topRight: Radius.circular(10)),
      ),
      child: Wrap(
        children: <Widget>[
          Container(
            width: double.infinity,
            padding: const EdgeInsets.only(top: 10, bottom: 20),
            child: const Text(
              "Ambil Gambar",
              textAlign: TextAlign.center,
              style: TextStyle(fontSize: 20.0, fontWeight: FontWeight.bold),
            ),
          ),
          Row(mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[
            Expanded(
              flex: 1,
              child: GestureDetector(
                onTap: () {
                  Navigator.pop(context);
                  getImage(ImageSource.camera);
                },
                child: Column(
                  children: [
                    const Icon(
                      Icons.camera,
                      size: 40,
                    ),
                    Container(
                        margin: const EdgeInsets.only(top: 5),
                        child: const Text("Ambil dari Kamera"))
                  ],
                ),
              ),
            ),
            Expanded(
              flex: 1,
              child: GestureDetector(
                onTap: () {
                  Navigator.pop(context);
                  getImage(ImageSource.gallery);
                },
                child: Column(
                  children: [
                    const Icon(
                      Icons.image,
                      size: 40,
                    ),
                    Container(
                        margin: const EdgeInsets.only(top: 5),
                        child: const Text("Ambil dari Galeri"))
                  ],
                ),
              ),
            ),
          ]),
          Container(
              width: double.infinity,
              padding: const EdgeInsets.symmetric(vertical: 10),
              margin: const EdgeInsets.only(top: 20),
              color: Theme.of(context).colorScheme.primary,
              child: const Text(
                'TUTUP',
                textAlign: TextAlign.center,
                style: TextStyle(
                    color: Colors.white,
                    fontSize: 20,
                    fontWeight: FontWeight.bold),
              ))
        ],
      ),
    );
  }

  Future getImage(ImageSource src) async {
    var image = await _picker.pickImage(source: src);
    setState(() {
      _image = image;
    });
  }
}

Demikian tutorial kali ini..semoga tulisan ini bermanfaat untuk yang membaca tulisan ini serta untuk penulis pribadi....

Terima kasih!!!!

Source Code Aplikasi Resep masakan menggunakan Flutter

Hari ini saya ingin membagikan source code aplikasi resep masakan menggunakan Flutter,dimana aplikasi ini menggunakan API dari https://masak-apa-tomorisakura.vercel.app/ dan sudah mendukung null safety.

Aplikasi ini memiliki fitur:
1. Daftar resep terbaru
2. Daftar resep per kategori
3. Daftar kategori
4. Pencarian resep

Beberapa tampilan dari aplikasi ini





Demo aplikasi silahkan klik disini

Untuk mendownload source code nya silahkan klik tombol di bawah
download[4]

Cara mengatasi dual monitor tidak berfungsi atau tidak terbaca pada Ubuntu 18.04

    Tutorial kali ini saya akan membagi pengalaman saya menggunakan Ubuntu 18.04 ketika menggunakan dual monitor menggunakan kabel HDMI dimana monitor kedua tidak terbaca atau tidak menampilkan layar...Setelah beberapa cara saya lakukan akhirnya saya menemukan cara yang berhasil di kasus saya yaitu dengan cara...

Pertama buka terminal lalu ketik kan perintah sebagai berikut:

sudo dpkg-reconfigure gdm3 (mengganti manager tampilan bolak-balik antara gdm3 dan lightdm)


Jika perintah diatas sudah di lakukan maka akan tampil dialog pilihan (gdm3 dan lightdm) maka pilih lightdm, langkah selanjutnya ketik kan perintah

sudo apt-get install --reinstall lightdm ubuntu-desktop (menginstal ulang lightdm dan mengonfigurasi ulang lagi alih-alih menggunakan gdm3). Jika semua langkah sudah dilakukan cabut ulang kabel HDMI dan masukkan kembali...


Demikian tutorial Cara mengatasi dual monitor tidak berfungsi atau tidak terbaca pada Ubuntu 18.04 

Menjalankan Winbox dengan wine pada linux

Bagi Pengguna linux untuk menjalankan aplikasi windows tidak mudah, salah satu cara untuk menjalankan aplikasi windows di linux bisa menggunakan wine. Pertama pastikan teman” sudah menginstall aplikasi paket wine.Untuk mengecek apakah wine sudah terinstall apa belum dengan mengetikkan wine --version.



Sebelum memulai pastikan kita memiliki 2 file yang sudah didownload yaitu aplikasi winbox.exe dan gambar Winbox.png, disini filenya saya simpan di folder KetikanMD. Untuk aplikasi winbox bisa di download melalui link ini.

https://mikrotik.com/download



  • Copy 2 file yang sudah didownload ke folder windows pada folder  instalasi wine



  • Pastikan kedua file sudah ada di folder windows


Sekarang kita coba menjalankan winbox tanpa harus berada dengan satu folder dengan aplikasi winbox.exe


  • Untuk  membuat pintasan yang memungkinkan aplikasi untuk dijalankan, kita buatkan file winbox.desktop di folder /usr/share/applications 




  • Membuat file winbox.desktop menggunakan nano, disini teman” bebas menggunakan editor yang teman” mengerti.


  • Berikut isian file winbox.Desktop





[Desktop Entry]
Name=Winbox
GenericName=Mikrotik winbox
TryExec=wine winbox
Exec=wine winbox.exe
Terminal=false
Icon=/home/ion/.wine/drive_c/windows/Winbox.png
Type=Application
Categories=Internet
Comment=Remote Mikrotik
Keywork=mikrotik;winbox

Jika semua langka diatas sudah dilakukan maka kita telah berhasil menjalankan aplikasi winbox.  

Membuat Makefile dan kegunaannya

     Sekarang kita akan mempelajari makefile. Apa Sih itu makefile, Makefile adalah kumpulan script yang akan di-eksekusi oleh command make. make merupakan automation-tools yang diciptakan di Unix-type OS. Jadi jika OS anda merupakan satu clan dengan Unix (Linux, MacOS) maka command ini seharusnya ada.

Beberapa kegunaan makefile yaitu ketika kita diharuskan mengetikkan command yang panjang  tiap kali melakukan sesuatu dan harus menghafal semua command yang panjang tersebut. Namun  telah dibuat suatu cara untuk mempermudah pekerjaan tersebut, yaitu dengan penggunaan makefile.

Konsepnya sederhana, kita hanya perlu define beberapa command dan proses yang akan dilakukan didalam Makefile. Selanjutnya kita tinggal memanggil script tersebut dengan command make.

Jika kita menjalankan make, Program ini akan mencari sebuah file bernama makefile pada direktori, lalu mengeksekusinya. Jika terdapat beberapa makefile, maka dapat pula dieksekusi dengan perintah :

make –f makefile


Adapun lebih lengkap mengenai make dapat dilihat dengan man make.


Untuk case ini kita mempunyai project django dan menjalankan project django menggunakan makefile. Kita sudah membuat file dengan nama Makefile didalam folder yang sama dengan project django seperti dibawah ini.


*Bagi teman” yang belum tahu cara instalasi django bisa kunjungi link ini.



Kita  memiliki Makefile dengan isi seperti gambar dibawah.

Penjelasan:

Baris 2,6,10:
- nama definisi command saat dipanggil make

Baris 3,7,11:

    - eksekusi command pada django

.PHONY: runserver

  • berarti kata "runserver" tidak mewakili nama file di Makefile ini;

  • berarti Makefile tidak ada hubungannya dengan file bernama "runserver" di direktori yang sama.


Cara menggunakan makefile untuk memanggil define command yang kita buat yaitu dengan cara seperti berikut:

  • Menjalankan server Django

Penjelasan:

Make runserver

                kata “runserver” mewakili definisi command yang merujuk ke command “@python                               manage.py runserver”  yang sudah kita buatkan sebelumnya di dalam file Makefile.



  • Create app project Django


Penjelasan:

Make createartikel

                  kata “createartikel” mewakili definisi command yang merujuk ke command “@python                          manage.py startapp artikel” yang sudah kita buatkan sebelumnya di dalam file Makefile,                   setelah mengeksekusi perintah “Make createartikel” secara otomatis akan terbuat folder                      dengan nama artikel.                 


  • Create app project Django secara dinamis dengan variabel

Penjelasan:

Make createapp app=berita
- kata “createapp” mewakili definisi command yang merujuk ke command “@python                  manage.py startapp $(app)” yang sudah kita buatkan sebelumnya di dalam file                      Makefile.

        - Kata “app” merupakan nama variabel yang sudah didefinisikan di command “@python              manage.py startapp $(app)”.

        - Kata “berita” merupakan nama app yang akan kita buatkan, kata “berita” bisa diubah              sesuai keinginan.

 Setelah selesai mengeksekusi perintah “Make createapp app=berita” secara otomatis akan terbuat folder dengan nama berita


Begitu kira” penggunaan makefile, teman” bisa menggunakan makefile sesuai kebutuhan.


Lebih jauh tentang makefile bisa kunjungi artikel berikut.

https://www.gnu.org/software/make/manual/make.html