Tag: blog

Cara Membuat WhatsApp Baca Selengkapnya Read More dengan JavaScript

Cara Membuat WhatsApp Baca Selengkapnya Read More dengan JavaScript

Halo semuanya, senang sekali bisa posting lagi hari ini. Kita akan membuat whatsapp baca selengkapnya read more dengan menggunakan JavaScript.

Minggu-minggu dan bulan-bulan terakhir ini cukup terasa lebih longgar dari sebelumnya. Jadi, sudah sedikit demi sedikit terasa agak ‘normal’. Walaupun kenaikan kasus masih saja ada, tetapi kita tetap mematuhi 3M juga, yakni Masker, Mencuci Tangan, dan Menjaga jarak.

Nah, di sela-sela aktivitas, saya sempetin untuk buat tutorial yang lagi hype banget nih. Bikin WhatsApp Read More atau Baca Selengkapnya. Kalo temen-temen udah tau, itu sebenernya ada cara gampangnya ya heuehu. Cuma, as a programmer ya ada hal baru yang bisa dipelajari kenapa kacang? (baca: kenapa tidak).

Maka dari itu, hari ini akan saya share cara bikin WhatsApp Read More atau Baca Selengkapnya menggunakan JavaScript. Tidak ada library yang digunakan kok alias VanillaJS.

Demo WhatsApp Read More Baca Selengkapnya dengan JavaScript

Yuk ah langsung aja dimulai gimana cara bikinnya

Requirement Membuat whatsapp baca selengkapnya

  • Laptop yang capable buat coding HTML + JS
  • Code Editor (disini saya pakai VSCode)
  • Baca ini dulu kalo bisa : Combining Grapheme Joiner

Let’s start

Flowchart cara kerja sistem membuat whatsapp baca selengkapnya

Pertama, kita harus tau bagaimana sih cara kerja dari sistem ini. Jadi, pada dasarnya WhatsApp akan memberikan teks “Baca Selengkapnya” atau “Read More” pada obrolan kita, jika karakter dalam teks yang kita kirimkan sudah terlalu banyak dan panjang.

Maka dari itu, flowchart akan seperti dibawah ini.

Flowchart dari WhatsApp Read More Generator System

Nah, pada dasarnya si unicode character Combining Grapheme Joiner (CGJ) atau pada HTML ditulis ͏ adalah sebuah karakter yang “diabaikan” dan tidak ditampilkan oleh aplikasi (dalam hal ini WhatsApp). Walaupun begitu, WhatsApp tetap menghitung character CGJ dalam chat.

Sampai sini sudah mulai mengerti yaa? Jadi kita menggunakan “banyak” CGJ ini sebagai tambahan diantara teks awal dan teks akhir.

Baca ini juga dong guys
Cara membuat Face Detection menggunakan JavaScript

CodeSeem

Implementation: Coding Section

Nah setelah tau konsep dasarnya, kita bisa langsung menuju kepada implementasinya. Sudah tergambar betul gimana codingan-nya sepertinya haha

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>CodeSeem jQuery WhatsApp Read More Demo</title>
</head>
<body>
    <form>
        <input type="text" name="awal" id="shownText">
        <input type="text" name="akhir" id="hiddenText">
        <input type="button" onclick="generate()" value="Submit">
    </form>
    <br>
    <p id="freview" style="display:block;">Hasilnya akan muncul disini..</p>
    <div id="fenrslt">
        <pre id="theResult" contenteditable=""></pre>
    </div>
    <script src="./scripts/index.js"></script>
</body>
</html>

scripts/index.js

function generate() {
    var shownText = document['getElementById']('shownText')['value'];
    var hiddenText = document['getElementById']('hiddenText')['value'];
    var textContent = '&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;&#847;';
    document['getElementById']('theResult')['innerHTML'] = shownText + textContent + hiddenText;
    document['getElementById']('fenrslt')['style']['display'] = 'block';
    document['getElementById']('freview')['style']['display'] = 'none'
}

Penjelasan Codingan

Pada file index.html kita bisa melihat element input dan juga sebuah submit button. Tiap kolom input memiliki ID yang kemudian nantinya bisa diakses di JavaScript.

File index.js tidak kalah pentingnya karena memiliki line yang sangat berguna. Berikut ini line yang pentingnya.

document['getElementById']('theResult')['innerHTML'] = shownText + textContent + hiddenText;

Nah, line diatas memiliki fungsi untuk mengganti value dari result menjadi hasil append variable (dalam hal ini teks awal, teks kosong/CGJ, dan teks akhir).

Setelah kode diluncurkan, maka hasilnya akan terlihat dengan jelas. Copy hasil yang ada di kolom bawah ke WhatsApp. Maka akan muncul hasil seperti dibawah ini.

WhatsApp Read More Baca Selengkapnya CodeSeem

Ending

Oke setelah kita berhasil membuat whatsapp baca selengkapnya, kita telah mempelajari banyak hal. Dari sifat salah satu Unicode (dalam hal ini CGJ) dan sifat aplikasi WhatsApp yang meng-ignore karakter tersebut untuk bisa terlihat di chat.

Untuk yang menginginkan source code, tersedia di github berikut
https://github.com/alviankosim/codeseem-whatsapp-read-more

Saya harap temen-temen bisa mendapatkan manfaat dari postingan ini. Semoga kita selalu dalam keberkahan dan kelancaran hidup juga terbebas dari mara bahaya dari COVID dan apapun. Aamiin.

Tengok bentar lah video ini

As always, i’ll show you a good quote

“Mengajar adalah semacam pertunjukan yang harus menarik.”

― Helvy Tiana Rosa

Helvy Tiana Rosa, penulis dari Indonesia kelahiran Medan

Enjoy, keep learning…

Cara Membuat Simple Authentication Login React Native AsyncStorage 2020

Cara Membuat Simple Authentication Login React Native AsyncStorage 2020

Halo semuanya, senang sekali bisa posting lagi hari ini. Kita akan membuat login authentication react native. Minggu karantina yang diupgrade jadi PSBB ini alias Pembatasan Sosial Berskala Besar bikin saya dan mungkin kalian juga bosen.

Karena virus covid19 ini, kita jadi harus ngelakuin social distancing yang mana gaboleh keluar rumah kalo gak penting-penting banget. Semoga saja wabah ini cepat berlalu.

Nah, disitulah saya merasa bosan karena setelah WFH (work from home) selesai, maka kegiatan saya tinggal tidur dan istirahat. Disitulah saya berfikir.

Kenapa saya tidak buat tutorial Login Authentication di React Native dengan AsyncStorage? Bukankah itu suatu hal yang bagus juga untuk diposting.

Login Authentication kalo di internet artinya

the process or action of proving or showing something to be true, genuine, or valid.

Yah intinya sih proses validasi kalo dia punya akses gitu. Nah kali ini kita akan implementasiin secara local. Ada juga yang secara online contohnya pakai Firebase. Tapi, kali ini saya akan nunjukin lebih kepada pemakaian AsyncStorage-nya.

Disclaimer

Cara yang saya jelaskan berikut hanya sebagai dasar bagaimana proses proses autentikasi di React Native dengan React Navigation v5 bekerja menggunakan AsyncStorage. Untuk lebih baiknya kalian bisa mengimplementasikannya dengan Context, Reducer, atau bahkan Redux/Mob.

Kemudian untuk versi React Native akan terus naik dan berkembang seiring berjalannya waktu. Versi library/dependency yang digunakan juga akan berkembang juga. Maka sesuaikan jika berbeda dari yang dipaparkan disini. Adapun versi yang digunakan pada tutorial ini dibuat

  • react-native v0.62.2
  • @react-native-community/async-storage v1.9.0
  • React Navigation v5.1.5

Maka kita mulai saja ya caranya.

Let’s start

Buat project baru React Native

Pertama, kita buat project baru untuk react native login ini. Caranya dengan menggunakan perintah dibawah ini. Kemudian tunggu hingga proses selesai.

npx react-native init projectlogin

Oke, setelah proses pembuatan project baru telah selesai, kita install beberapa dependency untuk tutorial kali ini.

Struktur Direktori

Struktur direktori dari project ini bisa dilihat di bawah ini yaa

projectlogin/
- android/
- ios/
- src/
-- screens/
--- loading.js
--- login.js
--- home.js
- App.js

Tampilan Awal Aplikasi

Kita coba untuk menjalankan project baru ini dengan perintah.

npx react-native run-android //Untuk android
npx react-native run-ios //Untuk IOS / iPhone
React Native 0.62.2 Android CodeSeem cara buat login authentication asyncstorage

Jika sudah bisa muncul tampilan awal aplikasi React Native kita, maka kita bisa mulai ke tahap edit beberapa file. Kita mulai edit file App.js

App.js

import 'react-native-gesture-handler';
import React, {useEffect, useState} from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import AsyncStorage from '@react-native-community/async-storage';

//importing screens
import LoginScreen from './src/screens/login';
import HomeScreen from './src/screens/home';
import LoadScreen from './src/screens/loading';

const Stack = createStackNavigator();
const App = () => {
  
  const [foundToken, setFoundToken] = useState('');
  const [isLoad, setIsLoad] = useState(true);

  const checkToken = async () => {
    try {
      let findingToken = await AsyncStorage.getItem('token');
      setFoundToken(findingToken);
      setIsLoad(false);
    } catch (error) {
      console.log(error);
    }
  }

  const loginAction = async () => {
    //Proses post login form untuk mendapat token/ semacamnya
    let dummyToken = 'CodeSeemToken';

    try {
        await AsyncStorage.setItem('token', dummyToken);
        setFoundToken(dummyToken);
    } catch (error) {
        console.log(error);
    }
  }

  const logoutAction = async () => {
    try {
        await AsyncStorage.removeItem('token');
        setFoundToken('');
    } catch (error) {
        console.log(error);
    }
  }

  useEffect(() => {
    checkToken();
  }, []);

  return (
    <NavigationContainer>
      <Stack.Navigator>
        {
          foundToken
          ?<Stack.Screen name="Home">
            {props => <HomeScreen {...props} logout={logoutAction} />}
          </Stack.Screen>
          :(isLoad
           ?<Stack.Screen 
              name="Load"
              options={{headerShown:false}}>
              {props => <LoadScreen {...props}/>}
            </Stack.Screen>
           :<Stack.Screen name="Login">
              {props => <LoginScreen {...props} login={loginAction} />}
            </Stack.Screen>
          )
        }
      </Stack.Navigator>
    </NavigationContainer>
  );
}

export default App;

Yuk baca juga, gakalah menarik
Membuat Realtime Face Detection dengan Javascript

CodeSeem

Sedikit penjelasan

Di kode di bawah ini, saya menambahkan state variable agar bisa berpindah-pindah antar screen jika terjadi proses login/logout.

Variabel foundToken ditujukan untuk tempat token yang nantinya kita simpan di AsyncStorage.

Kemudian, variabel isLoad dibuat karena proses pengambilan token dari AsyncStorage asynchronous, maka fungsinya untuk membantu kita mendeteksi apakah proses pengambilan token sudah selesai.

const [foundToken, setFoundToken] = useState('');
const [isLoad, setIsLoad] = useState(true);

Selanjutnya, fungsi checkToken adalah fungsi asynchronous yang mengecek dahulu apakah sudah ada token yang disimpan atau belum.

Dalam fungsi ini juga dilakukan set value pada variabel isLoad dan foundToken. Karena variabel ini berubah, maka komponen akan merender ulang screen.

const checkToken = async () => {
......
}

Penjelasan Proses Login dan Logout

Kita masuk ke fungsi loginAction dan logoutAction. Fungsi ini dari namanya tentu sudah jelas untuk memproses login/logout. Dalam fungsi ini dilakukan proses set/unset token dari AsyncStorage.

const loginAction = async () => {
......
}

const logoutAction = async () => {
......
}

Tentunya proses login/logout dalam aplikasi live/production tidak akan sesimpel itu. Untuk latihan mungkin ini sudah cukup.

Bagian ini cukup menarik, karena kita memanggil fungsi useEffect dengan parameter keduanya empty array. Berguna untuk menjalankan fungsi dalam parameter pertama sekali ketika komponen dimuat.

useEffect(() => {
checkToken();
}, []);

Kita memanggil function checkToken untuk melakukan pengecekan pertama kali apakah sudah terlogin atau belum.

Bagian Return App.js

Kita masuk pada bagian return dari App.js, terdapat 3 screen yang ada didalam masing-masing kondisi. Kondisinya juga menggunakan state variable foundToken dan isLoad.

return (
    <NavigationContainer>
      <Stack.Navigator>
        {
          foundToken
          ?<Stack.Screen name="Home">
            .....
          </Stack.Screen>
          :(isLoad
           ?<Stack.Screen  name="Load" options={{headerShown:false}}>
              ....
            </Stack.Screen>
           :<Stack.Screen name="Login">
              ....
            </Stack.Screen>
          )
        }
      </Stack.Navigator>
    </NavigationContainer>
  );

Hal itulah yang menjadi kunci screen apa yang kita tampilkan pada user ketika belum login, sudah login, atau sedang loading token.

Penjelasan Bagian Setiap Screen

Kita masuk ke file loading.js. Screen ini ditampilkan ketika foundToken memiliky value falsy karena default useState adalah ‘ ‘ dan isLoad true alias masih dalam proses loading token .

Screen ini hanya menampilkan tulisan loading ditengah dengan background gelap tanpa header. Tujuannya hanya untuk menandakan bahwa proses pengambilan token sedang berlangsung.

src/screens/loading.js

import React from 'react';
import {View, Text} from 'react-native';

const Loading = () => {

    return (
        <View style={{flex:1, backgroundColor:'#333', justifyContent:'center', alignItems:'center'}}>
            <Text style={{color:'white'}}>Loading...</Text>
        </View>
    );
}

export default Loading;

Kemudian kita masuk ke file login.js. Screen ini ditampilkan ketika value foundToken masih juga falsy alias belum login setelah pengecekan karena isLoad sudah menjadi false.

Coba perhatikan, screen ini menerima props login yang isinya adalah function loginAction. Props ini akan dipanggil ketika didalam screen Login user memulai proses login. Dalam hal ini menekan tombol Login.

src/screens/login.js

import React from 'react';
import {View, Text, Button} from 'react-native';

const Login = ({login}) => {

    return (
        <View style={{flex:1, justifyContent:'center', alignItems:'center'}}>
            <Text>You haven't logged in yet</Text>
            <Button title="Login" onPress={login}/>
        </View>
    );
}

export default Login;

Nah, file home.js ditampilkan ketika foundToken berisi value truthy. Hal ini menunjukan token sudah ada di AsyncStorage artinya sudah pernah login sebelumnya.

Hampir sama seperti file login.js, screen Home juga menerima props. Tapi sebaliknya props yang diterima ada logout yang mana adalah function logoutAction yang nantinya bisa dipanggil ketika user memulai proses logout. Dalam hal ini menekan tombol Logout.

src/screens/home.js

import React from 'react';
import {View, Text, Button} from 'react-native';

const Home = ({logout}) => {

    return (
        <View style={{flex:1, justifyContent:'center', alignItems:'center'}}>
            <Text>You already logged in</Text>
            <Button title="Logout" onPress={logout} />
        </View>
    );
}

export default Home;

Nah setelah menulis dan memahami seluruh kode diatas, kita bisa langsung coba untuk melihatnya di emulator. Namun, dengan fitur Fast Refresh membuat kita bisa melihat perubahan langsung tanpa harus build ulang. Jika memang ingin build ulang dipersilahkan.

Hasilnya kurang lebih seperti ini.

Mengimplementasi Teknik Lainnya dan Mengintegrasikannya

Umm, bisa dibilang teknik diatas sangatlah simpel. Hanya sedikit pemahaman dasar gimana konsep authentication flow dan AsyncStorage bekerja.

Untuk kedepannya kalian bisa implementasi teknik seperti useReducer, createContext, useMemo, Redux, Mobx, dan lainnya.

Kalian juga bisa mengintegrasikannya dengan API yang betul-betul men-submit login form (username dan password) dan mendapatkan token atau data lain dari response API tersebut.

Ending

Oke setelah kita berhasil membuat local login authentication flow di react native, banyak hal yang bisa diimprovisasi.

Di dunia yang tidak sempurna ini, kita pasti tidak sempurna, tapi dibalik ketidaksempurnaan itu kita jadi selalu memiliki celah untuk terus improvisasi.

As always, i’ll show you a good quote

“Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live”

― John Woods

John Woods: a programmer, found in a Google group, 1991

Enjoy, keep learning…

Implementasi Face Detection di Javascript Browser dengan face-api.js

Implementasi Face Detection di Javascript Browser dengan face-api.js

Halo semuanya, good to see you again reading this post. Kita akan membuat face detection dengan face-api.js javascript. Minggu karantina ini betul-betul bikin kita cepet bosen. Karena virus covid19 ini, kita jadi harus ngelakuin social distancing yang mana gaboleh keluar rumah kalo gak penting-penting amat. Semoga saja wabah ini cepat berlalu.

Nah, disaat itulah saya merasa bosan karena setelah WFH (work from home) selesai, maka kegiatan saya hanya malas-malasan. Disitulah saya berfikir, kenapa saya gabuat tutorial tentang face detection? Bukankah suatu yang bagus juga untuk diposting.

Face Detection adalah proses pendeteksian wajah dari video atau gambar yang dilakukan oleh komputer dan bukan manusia. Face Detection yang kita akan buat diimplementasikan secara realtime melalui video dari webcam laptop kita di browser.

Disini kita akan implementasi face detection menggunakan library yang namanya face-api.js.

Maka kita mulai saja ya caranya.

Let’s start

Requirements

Pertama, kita masuk ke bagian bahan-bahan dulu yang diperlukan yakni,

  • Laptop (yang ada webcamnya yaa)
  • Code Editor (VSCode, Sublime Text)
  • face-api.js (library based on TensorFlow Core yang membantu kita untuk pendeteksian)
  • File pre-trained model (file yang berisi data pendeteksian)
  • Browser (saya saranin pakai Chrome)
  • Internet dan StackOverflow (kalo-kalo stuck)
  • Secangkir kopi, semangat, dan kemauan 🙂

Oke, setelah bahan-bahan telah dimiliki, kita mulai ke tutorialnya. Download dulu library face-api.js yang akan kita gunakan disini.

Struktur Direktori

Struktur direktori dari project ini bisa dilihat di bawah ini yaa

project/
--index.html
--main.js
--face-api.js
--model/
---- *all the models

Menampilkan Output Webcam di Browser

Kita masuk ke tahap yang pertama, buat satu file html seperti di bawah ini. Untuk file index.html dan main.js. Untuk library face-api.js nanti akan kita libatkan selanjutnya :).

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>CodeSeem Face Detection</title>
    <style>
        body {
            height: 100vh;
            display: flex;
            justify-content: center;
            align-items: center;
        }
        #videoEl {
            transform: rotateY(180deg);
            -webkit-transform: rotateY(180deg);
        }
    </style>
</head>
<body>
    <video id="videoEl" width="800" height="600" autoplay muted></video>
    <script defer src="main.js"></script>
</body>
</html>

main.js

//Get elemen video untuk menampilkan kamera
const videEl = document.getElementById('videEl');

//Membuat function untuk menampilkan input webcam di elemen video
async function startCamera(){
    navigator.mediaDevices.getUserMedia({video: true})
    .then(function(stream){
        videoEl.srcObject = stream;
    })
    .catch(function(err){
        console.log('Ada yang error');
        console.log(err);
    })
}

startCamera();

Dengan code diatas, kita sudah bisa menampilkan output dari webcam kita di browser. Hasilnya seperti di bawah ini.

CodeSeem Browser camera in html javascript. membuat face detection face-api.js javascript
Hasil yang muncul di browser.

Memulai Implementasi Face Detection

Selanjutnya, setelah kita berhasil menampilkan output dari webcam kita, kita akan mulai untuk mengintegrasikan face-api.js supaya bisa melakukan proses face detection.

Tambahkan satu baris tag script seperti dibawah ini. Kode dibawah diletakkan diatas tag script dari file main.js.

index.html

<script src="js/face-api.js"></script> <--- Tambahkan ini
<script defer src="main.js"></script>

Setelah ditambahkan, kita bisa mencoba untuk cek apakah library sudah terload dengan benar. Dengan cara membuka console log dan akses faceapi seperti dibawah

Accessing faceapi variable in console membuat face detection face-api.js javascript
Console mengakses class faceapi

Jika muncul tidak jauh seperti di atas, alias tidak ada error message maka kalian bisa ke langkah berikutnya. Jika ada error, coba dicek kembali apakah cara memanggilnya sudah benar?

Setelah itu, kita mulai untuk memakai face-api.js. Edit file main.js supaya bisa mendeteksi wajah kita menjadi seperti di bawah ini.

//Get elemen video untuk menampilkan kamera
const videoEl = document.getElementById('videoEl');

//Inisiasi function dari faceapi load model
Promise.all([
    faceapi.nets.tinyFaceDetector.loadFromUri('./models'),
    faceapi.nets.faceLandmark68Net.loadFromUri('./models'),
    faceapi.nets.faceRecognitionNet.loadFromUri('./models'),
    faceapi.nets.faceExpressionNet.loadFromUri('./models')
])
.then(startCamera);

//Membuat function untuk menampilkan input webcam di elemen video
async function startCamera(){
    navigator.mediaDevices.getUserMedia({video: true})
    .then(function(stream){
        videoEl.srcObject = stream;
    })
    .catch(function(err){
        console.log('Ada yang error');
        console.log(err);
    })
}

//Main function untuk deteksi wajah
function startFunction(){
    //Set interval setiap 0,1 detik
    setInterval(async function(){
        //Memanggil function untuk mendeteksi wajah di video webcam
        const detection = await faceapi.detectAllFaces(
            videoEl,
            new faceapi.TinyFaceDetectorOptions()
        )
        .withFaceLandmarks()
        console.log(detection);//Tes  berhasil atau tidak
    }, 100);
}

//Listen event saat output webcam sudah mulai muncul di browser
videoEl.addEventListener('playing', startFunction)

Yuk baca juga:
a hello world by CodeSeem

Penjelasan

Di bagian atas, kita menggunakan Promise untuk memanggil function loadmodel dari face-api.js. Kemudian menjalankan function startCamera tepat setelah model selesai load.

//Inisiasi function dari faceapi load model
Promise.all([
    faceapi.nets.tinyFaceDetector.loadFromUri('./models'),
    faceapi.nets.faceLandmark68Net.loadFromUri('./models'),
    faceapi.nets.faceRecognitionNet.loadFromUri('./models'),
    faceapi.nets.faceExpressionNet.loadFromUri('./models')
])
.then(startCamera);

Lalu di function startFunction, kita menjalankan function setInterval dalam waktu 0,1 detik. Kita disini menggunakan function detectAllFaces untuk mendeteksi wajah.

Pada tahap ini, kita belum benar-benar melihat bukti berhasil mendeteksi wajah secara visual, namun disini kita memanggil console.log(detection) yang akan menampilkan data hasil deteksinya secara teks.

//Main function untuk deteksi wajah
function startFunction(){
    //Set interval setiap 0,1 detik
    setInterval(async function(){
        //Memanggil function untuk mendeteksi wajah di video webcam
        const detection = await faceapi.detectAllFaces(
            videoEl,
            new faceapi.TinyFaceDetectorOptions()
        )
        .withFaceLandmarks()//Deteksi dengan metode landmark
        .withFaceExpressions()//Deteksi dengan metode ekspresi wajah
        console.log(detection);//Tes  berhasil atau tidak
    }, 100);
}

Jika berhasil, maka akan terlihat ouput data di console seperti di bawah ini.

Data Face Detection in ouput console membuat face detection face-api.js javascript
Data output dari detection

Kemudian, tahap selanjutnya adalah memvisualisasikan hasil deteksi wajah. Kita fokus pada function startFunction pada file main.js.

startFunction()

//Function ketika output webcam mulai muncul
function startFunction(){

    //Create canvas untuk detection shape nya
    const canvas = faceapi.createCanvasFromMedia(videoEl);
    document.body.append(canvas);

    //Get video element width dan height nya
    const sizeEl = {width:videoEl.width , height: videoEl.height}
    //Match ukuran canvas dengan video elemen
    faceapi.matchDimensions(canvas, sizeEl);

    //Set interval setiap 0,1 detik
    setInterval(async function(){
        //Memanggil function untuk mendeteksi wajah di video webcam
        const detection = await faceapi.detectAllFaces(
            videoEl,
            new faceapi.TinyFaceDetectorOptions()
        )
        .withFaceLandmarks()//Sistem deteksi menggunakan face landmark
        .withFaceExpressions()//Sistem deteksi menggunakan face expression
        
        //Membuat detection yang diresize menurut ukuran wajah
        const resizedSizeDetection = faceapi.resizeResults(detection, sizeEl);

        //Mengaplikasikan deteksi di canvas yang telah dibuat tadi, 
        //juga menghapus hasil deteksi yang sebelumnya
        canvas.getContext('2d').clearRect(0,0, canvas.width, canvas.height);
        faceapi.draw.drawDetections(canvas, resizedSizeDetection);

    }, 100);
}

Penjelasan *lagi

Pertama yang ditambahkan adalah code untuk membuat elemen canvas dan menyamakan ukurannya dengan elemen video.

//Create canvas untuk detection shape nya
    const canvas = faceapi.createCanvasFromMedia(videoEl);
    document.body.append(canvas);

    //Get video element width dan height nya
    const sizeEl = {width:videoEl.width , height: videoEl.height}
    //Match ukuran canvas dengan video elemen
    faceapi.matchDimensions(canvas, sizeEl);

Kemudian, fungsi untuk menampilkan visual deteksi juga ditambahkan. Jangan lupa function clearRect sangat berguna untuk menghapus hasil visual deteksi sebelumnya.

//Membuat detection yang diresize menurut ukuran wajah
        const resizedSizeDetection = faceapi.resizeResults(detection, sizeEl);

        //Mengaplikasikan deteksi di canvas yang telah dibuat tadi, 
        //juga menghapus hasil deteksi yang sebelumnya
        canvas.getContext('2d').clearRect(0,0, canvas.width, canvas.height);
        faceapi.draw.drawDetections(canvas, resizedSizeDetection);

Jangan lupa juga untuk menambah styling pada canvas supaya memiliki posisi di atas elemen lain dan tidak terganggu elemen lain.

canvas {
            position: absolute;
            transform: rotateY(180deg);
            -webkit-transform:rotateY(180deg);
        }

Jika styling sudah ditambahkan, maka seharusnya deteksi akan berjalan lancar dan tampil hasil deteksi berupa kotak dengan angka persentase di ujungnya.

Face detection in javascript with face-api membuat face detection face-api.js javascript
Hasil deteksi berhasil

Penjelasan Opsional *tapi penting

Pada kode styling di atas, elemen canvas diset posisinya menjadi absolute. Kemudian ditambahkan properti transform dengan value rotasi 180deg. Saya menambahkan itu karena sebelumnya untuk elemen video pun saya melakukan hal yang sama.

Hal itu dilakukan supaya video hasil ouput webcam dan juga hasil deteksinya tidak mirrorred. Namun, kekurangannya styling dengan CSS diatas, karena hasil deteksinya mirrored, angka persentase ketepatan deteksinya juga jadi mirrored.

Ending

Oke setelah kita berhasil membuat deteksi wajah, banyak sekali tentunya kekurangan yang bisa diimprovisasi. Kita telah membuat face detection dengan face-api.js javascript. Tapi, di dunia yang tidak sempurna ini, kita pasti tidak sempurna, tapi dibalik ketidaksempurnaan itu kita jadi selalu memiliki celah untuk terus improvisasi.

Banyak yang bisa diimplementasikan dari face-api.js ini setelah diimprovisasi. Seperti

  • Absen menggunakan wajah
  • Login atau authentication menggunakan wajah (mungkin less secured)
  • Game atau app kecil yang bisa menambah portofolio Kalian.
  • — dan banyak lagi

As always, i’ll show you a good quote

“Everyday life is like programming, I guess. If you love something you can put beauty into it.”
― Donald Knuth

Knuth, Donald.

Enjoy, keep learning…