FunProject - Arduino ile Masaüstü Gif Çıkartması Arayüz Yapımı

Herkese merhaba. Bu yazımda hobi projem Gif Button'un masaüstü arayüzünü nasıl yaptığımı anlatacağım. Öncelikle bu projede kullandığım kütüphanelerin listesini paylaşmak istiyorum. Daha sonrada bu kütüphaneleri ne amaçla kullandığımı adım adım göstererek anlatacağım.
Kullandığım program ve kütüphaneler
Node.js (https://nodejs.org/en/)
Electron.js (https://www.electronjs.org/)
React.js (https://tr.reactjs.org/)
Redux (https://redux.js.org/)
React-Router (https://www.npmjs.com/package/react-router)
Material-UI (https://material-ui.com/)
Electron-edge-js (https://www.npmjs.com/package/electron-edge-js)
Custom-electron-titlebar (https://www.npmjs.com/package/custom-electron-titlebar)
Ws(Websocket) (https://www.npmjs.com/package/ws)
notistack (https://www.iamhosseindhv.com/notistack)
electron-build (https://www.electron.build/)
İnno Setup (https://jrsoftware.org/isinfo.php)
VSCode (https://code.visualstudio.com/)
Yukarıda bu projede kullandığım bütün program ve kütüphaneler yer almaktadır. Kodların yazımı için yine electron.js ile yazılmış VSCode uygulamasını kullandım.
Kodların Yazımı için VSCode Uygulamasının İndirilmesi
Kodları yazacağımız VSCode uygulamasını https://code.visualstudio.com/ sitesinden edinebilirsiniz. Kurulumu bildiğimiz Next->Next->Next şeklinde oldukça basittir.

Yine kodların koşması için altyapı olarak node.js 'in kurulması gerekmektedir. Bunun için node.js sayfasından yine aynı şekilde kolayca indirip kurabilirsiniz. (https://nodejs.org/en/)
Proje Templatesinin İndirilmesi ve Proje Başlangıcı
Bu tarz electron, react projeleri için intertetten topladığım bilgilerle oluşturduğum bir boilerplate github projem var. Bu projeyi klonlayarak hızlıca bir temel uygulama oluşturuyorum.
Masaüstüne GifBu adında bir klasör oluşturup VSCode ile içine gidiyorum ve bir terminal açıyorum. Terminal kısayolu Ctrl + Shift + " dır. Buraya aşağıdaki kodu yapıştırıp çalıştırıyorum ve temel projem hazır.
git clone https://github.com/HakanUcaar/electron-react-boilerplate

Projemin ismini değiştirmek için proje klasörüne gidip ismini değiştiriyorum.

Tekrar klasörü açıp
npm install
diyorum. Böylece node.js benim için bağımlı kütüphaneleri ekliyor.

Daha sonra
npm start
diyerek projeyi başlatıyorum. Karşınızda hazır bir electron masaüstü uygulaması. Artık bu çerçevenin içine React componentlerimi yerleştirebilirim.

Arayüz Yapımına Başlangıç
Arayüz geliştirmelerinde React.js kullandım. Bu kısımları anlamak için React bilgisine ihtiyacınız var. React öğrenmek için kendi sayfasından başlayabilirsiniz. Türkçe çevirisinin de olduğu site yeni başlayanlar için oldukça başarılı. (https://tr.reactjs.org/)
Basit anlamda biraz React tan bahsedecek olursak. Salt Hmlt söz dizimi yerine javasicriptin gücüyle bu html yazımını class mantığına uygun düzenliyor diyebiliriz. Böylece daha çok OOP (Object Oriented) ye yaklaşarak hem yönetim anlamında hemde esneklik anlamında daha çok çeviklik sağlıyor.
Arayüz tasarımları için MATERIAL-UI adında özel bir kütüphane kullandım.(https://material-ui.com/) Bu kütüphane Google'in material tasarım yaklaşımını ve React component mantığını bünyesinde barındırıyor.
npm install @material-ui/core
Terminalde bu kodları çalıştırarak bu kütüphaneyi de projeme ekliyorum.

Arayüzümü bu kütüphanenin react componentlerini kullanarak oluşturacağım. React componentlerini klasik programlardaki componentler gibi düşünebiliriz.
Projemdeki uyarı yönetimi için de "notistack" adında bir kütüphaneden yararlandım. Bu kütüphaneyi de güncelleme işlemlerinde başarı ile kaydedildi uyarısı nı verdirmek için kullanıyorum.(https://iamhosseindhv.com/notistack)
Ana Ekranda Kullandığım Componentler(Bileşenler)
Yazının çok fazla uzun olmaması adına bitmiş projeden ekran paylaşımları ve açıklamalar şeklinde anlatarak devam etmek istiyorum. Yazının en altında Github linklerini paylaşıyor olacağım. Böylece kaynak kodları daha iyi inceleyebilirsiniz.
Projemin src klasöründe dört tane klasörüm var.

Bunlardan ilki "ArduinoSvgIconComponent" bu klasörde material-ui kütüphanesinde olmayan arduino iconunun bir componentini oluşturarak material-ui kütüphanesine dahil ettim. Giriş sayfamda görünen arduino logosunun olduğu component buradan çalışmakta.

İkinci klasörüm olan "Components" klasöründe ise uygulamamın bileşenleri yer almaktadır. Uygulamam da dört tane component bulunmakta. Aslında buradaki componentleri klasik programlardaki formlar yada bir web uygulamasındaki page ler olarak düşünebilirsiniz.

"ArduinoSettingDialog" ta arduino ayarlarını girdiğim ekran kodları bu kısımda yer alamakta.
"GifDesktopWindow" masaüstünde görünen gif resminin göründüğü ekran kodları bu kısımda yer almakta.
"GifList" çeşitli giflerin olduğu listenin kodları bu kısımda yer almakta.
"Main" ana ekran kodlarım ise bu kısımda yer almakta.
Bu ekranların kodlarına Github hesabımdan ulaşarak ayrıntılı inceleyebilirsiniz. Bu yazıda kullandığım şeyleri ne amaçla kullandığım ve nasıl kullandığımı göstermek istiyorum.
"Gifs" klasörümde static Gif resimlerim yer almaktadır.

Veritabanı Model Yapısı
Uygulamadaki iletişimi sağlamak için bir json text dosya kullanıyorum. Bu dosya içerisine arayüzden aldığım bilgileri yazıyorum ve arkada uç noktam dan da bu dosya içerisinde olan bilgileri kullanıyorum.
Örneğin arduino bağlantı bilgilerimi arayüzden bu dosyaya yazıyor. Uygulama başladığında da eğer burada bir bağlantı bilgisi varsa okuyup ardunio cihazına bağlanıyorum
Bağlantı model clasımın adı Gifbu. Bu class içerisinde resim, gösterilecek mesaj ve Arduino bağlantı bilgileri yer almakta.

Redux
Componentler arasında iletişim React da props lar üzerinden yapılmaktadır. Bunu yönetmek component sayısı arttıkça işin içinden çıkılmaz bir hal almaya başlıyor. Bu yüzdende Redux adında bir yardımcı kütüphane ile tüm bu veri alış verişini tek bir yerden yaptım.
Reduxtaki mantığa basitçe bakacak olursak eğer. Reactda, bir component içindeki değişiklikler state adını verdiğimiz özel bir prop ta tutulmaktadır. State değiştiğinde React component te bir değişiklik olduğunu algılamakta ve render işlemi ile componenti güncellemektedir. State her component içerisinde kaldığı için, bu state deki bilgileri başka bir componente taşımak zorunda kalınmakta.
Redux ta ise state ayrı bir js dosyada oluşturulmakta ve hangi componentte değişiklik olduysa bu ortak stateti güncellemekte. Component içerisinde de redux ile bağlantıyı sağlamak için özel bir function bulunmakta. Bu functionda ortak state değiştiğinde bu state'i takip eden bir function, ilgili componenti render etmekte.
Böylece ortak state ilgili componentlerin propsuna otomatik olarak gitmektedir. İlgili componentin propsun dan da ihtiyacımız olan bilgiyi alabiliyoruz.

Electron.js de Çoklu Form Açma
Electron.js de ana form haricinde başka bir form açmak çok kolay olmasına rağmen içeriği React componenti ile doldurmak bir hayli zor. Bunun için şu ablamıza teşekkürü bir borç biliriz.
Çünkü mantık basit olmasına rağmen uygulaması bir hali uğraştırıcı. Burayı şu şekilde açıklamaya çalışayım.
Electron.js bir SPA olarak iyi iş çıkarmakta ve herşeyi tek bir windows form üzerinden dialoglarla yapıyorsanız hiç bir sorun yok. İş aynı uygulamada başka bir windows form açmaya geldiğinde yine problem yok. Çünkü electron.js de bir form içeriğini yüklemek için ana html in dosya yolunu vermeniz yeterli.
Electron.js ilk çalıştığında public klasörü altındaki index.html üzerinden çalışmaya başlıyor. Siz kinci bir form açtığınızda bu sefer hedef olarak yeni bir html dosyası verirseniz o html dosyası üzerinden gidiyor. Fakat biz burada yeni bir html dosyası kullanmıyoruz. Biz React componentleri kullanıyoruz ve bu componentler dinamik html ler oluşturuyor. Yani henüz html yok elimizde.

Bunu aşmak içinse React Router kullanıyoruz ve Routerı da hook luyoruz. Diyoruz ki eğer bu adresten istek gelirse şu componente eğer şuradan istek gelirse şu componente git. İşte bunu demek için bir ViewManager classı oluşturuyoruz. (https://www.npmjs.com/package/react-router)
Normal bir react router değil bu. Dikkat ederseniz tek bir path var ve bu path de biz gelen URL deki Filter ın parametresini kullanıyoruz. Eğer filter main gelirse App componentini viewA gelirse GifDesktopWindow componentini geri döndürüyoruz.

Arduino Bağlantısının Sağlanması
Arduino ile iltişimi dll ler vasıtasıyla sağlıyor ve yine dll ile websocket eknolojisiyle arayüzümü haberleştiriyorum.
Arduino bağlantısını açmak için bir js dosyası oluşturdum. Dll ler ile bağlantı için electron-edge-js kütüphanesini kullandım.(https://www.npmjs.com/package/electron-edge-js) .Bu kütüphane javasicript ile dll içerisinden fonksiyonlar çağırmama yarıyor.
Resimde de görüldüğü gibi Gifbu.dll içerisinden Connect methodumu çağırıyor ve setting dosyama yazdığım bilgileri okuyarak arduino cihazıma bağlanıyorum.

Websocket ile Arduinodan Gelen Bilgilerin Okunması
Electron uygulamam ayağa kalkarken bir websocket server oluşturuyorum. Arduino cihazıma bağlantı sağladığımda bu websocket servera Arduino cihazımdan okuduğum bilgileri gönderiyorum.

GifButtonlar Son Halleri

Github Gifbu: https://github.com/HakanUcaar/Gifbu
Github GifbuService : https://github.com/HakanUcaar/GifbuService