Flutter’da klasör seviyesinde kategorilendirme yaparak resim kayıt etme

Kadir Bekar
Flutter Türkiye
Published in
6 min readOct 18, 2021

Merhabalar. Bugün içerik olarak:

𐤟 Local JSON datasının yüklenmesi
𐤟 Resimleri farklı kategoriler halinde ekranda gösterme
𐤟 Galeri & Kamera ile telefon hafızasından resim alma
𐤟 Klasör oluşturma
𐤟 Resmi farklı bir dizine taşıma

konularını içeren bir örnek üzerinde çalışıyor olacağız. Klasör yapısı ve kullandığımız paketlere bir göz atalım sonrasında örneğimize başlayalım.

Projenin kaynak kodlarını yazının sonunda paylaşıyor olacağım.

Neden böyle bir uygulamaya ihtiyacımız olabilir: Telefonumuzdaki resimlerin tek bir klasör altında kayıt edildiğini bir düşünelim. Herhangi bir resme ulaşmak istediğimizde ne kadar çok zaman harcardık değil mi?

Bir de resimlerin ilişkisi olduğu kategori altında kayıt edildiklerini varsayalım. Örneğin, Hayvanlar isimli bir klasör oluşturup içerisine sadece hayvanlar ile alakalı resimleri eklemek gibi. En azından yukarıdaki senaryoya göre çok daha düzenli ve hızlı erişilebilir bir senaryo ortaya çıkar.

Bu senaryo normal hayatımızda ve iş hayatında karşımıza çıkabilir. Bugün yapacağımız örnekte, telefonumuzun hafızasında farklı isimlerde klasörler oluşturacağız. Sonrasında, bu klasörler altına ilişkisi olan resimleri ekleyeceğiz.

Uygulama senaryosu: Mobil uygulamadan istek atabileceğimiz bir servisimiz olsun. Bu servise istek attığımızda bize bazı kategori başlıkları dönülüyor. Örneğin Hayvanlar, Programlama dilleri, Arabalar, Teknoloji, Doğa…

Kod tarafında işlem yaparken her bir kategori başlığını benzersiz (Unique) yapabilmek için, JSON datamız içerisinde ID değerimiz olsun. Örneğin Hayvanlar kategorisini temsil eden ID değeri 1 ise, Arabalar 2, Teknoloji 3 olsun.

(Her bir kategori için klasör oluştururken ID değeri yerine kategori ismini kullanabilirdik. Örneğin, Hayvanlar kategorisi için bir klasör oluşturmak istediğimde, klasör adını yukarıda belirttiğim gibi 1 yapmak yerine doğrudan hayvanlar olarak yapabilirdim. Benim yaptığım kurguda, veritabanında her bir ID değeri bir isme karşılık geliyor. Örneğin 1 değerinin karşılığı Hayvanlar, 2 => Arabalar gibi.)

Bir de JSON datamıza, kategorilerimizi ekranda gösterirken tasarımsal olarak farklı bir görüntü elde edebilmek için bannerUrl değeri ekleyelim. Image.network widget’i sayesinde her bir kategori için belirlediğimiz URL’i bu widget’a verdiğimizde çok temiz bir şekilde kapak resmi elde edebiliriz.

Local JSON olarak yükleyeceğimiz datanın 2 farklı kategorisini örnek olarak bir inceleyelim.

Her bir kategori için klasör oluşturacağımız sırada ID değerini, ekranda bu kategorileri gösterirken tasarımsal olarak farklı olabilmeleri için ise name ve bannerUrl propertilerini kullanacağız. Images array propertisini ise uygulamada resimlerimizi farklı kategoriler altına dinamik bir şekilde kayıt etmek, ekranda göstermek için kullanacağız.

Şimdi sıra geldi Local olarak JSON datasını yüklemeye. (Farklı bir örnek üzerinden bu konuyu okumak isterseniz.)Bunun için öncelikle assets/json olarak bir klasör yapısı oluşturdum ve local JSON dosyamı buraya ekledim. Son olarak ise pubspec.yaml dosyama gerekli tanımlamamı yaptım.

Öncelikle kategorilerimiz ile UI tarafında rahat işlem yapabilmek adına category_model.dart dosyası içerisinde bir Dart modeli oluşturalım ve Local JSON datamızı UI tarafına Dart nesnesi olarak döndürmek için fromJson metodumuzu tanımlayalım.

Şimdi ise json_service.dart dosyası içinde, Local JSON datamızı UI için hazır edecek kodlarımızı yazalım.

Kategorilerimizi ekranda gösterebilmek için GridView tasarımı uygulayalım. Biraz daha güzel gözükmesi için ise flutter_staggered_grid_view paketinden yardım alacağız.

Verilerimizi ekranda göstermek için home_page.dart isimli bir Dart dosyası oluşturuyorum. Oluşturacağım sayfayı StatefulWidget olarak tanımlıyorum ki bu sayede initState metodunu override ederek, sayfam widget tree’ye eklendiği gibi (ekranım henüz çizilmeye başlamadan) Local olarak yükleyeceğim JSON datamın listeye atanması işlemlerine başlayabilirim.

Burada önemli olan kısım ise 27. satırda yaptığımız kontroldür. Bu kontrolün amacı, Local olarak yüklemeye çalıştığım data hazır olup listeye atanacağı sırada, widget tree’ye eklediğimiz HomePage sayfası halen aktif olarak görüntüleniyor mu. mounted değeri true ise sayfa dispose edilmemiştir, gelen datayı listeye atayıp setState metodu ile listemi güncelleyebilir ekranımızı BusyState durumundan _ImageCardList(Loaded) durumuna göre tekrar çizebilirim.

Veriler yüklendiği zaman ise aşağıdaki gibi bir görüntü elde ediyor olacağız.

Kategoriler için nasıl bir model oluşturduysak, galeriden, kameradan alacağımız resimleri daha kolay yönetebilmek için bir tane de ImageModel oluşturalım. Bu sayede elimizde olan resmin yolunu ve eklenme tarihi daha temiz bir şekilde yönetebiliriz.

Bu işlemde tamam. Herhangi bir kategoriye tıklayıp o kategorinin detay sayfasına gittiğimizde (CategoryDetail sayfasına giderken tıklanılan kategorinin nesnesini parametre olarak detay sayfasına gönderiyorum bu sayede tıklanılan kategorinin eğer bir değeri varsa onu ekranda gösterebilirim veya sonradan yeni değerleri bu nesneye ekleyebilirim), Local JSON olarak yüklediğimiz kategorilerimizin images değerleri boş bir liste olduğu için ekranda gösterecek herhangi bir resmimiz olmayacaktır. Boş bir ekranda nasıl bir görüntümüz olacak bir de onu görelim.

Yeni bir resmi galeriden, kameradan eklemek için image_picker paketinden yardım alıyoruz olacağız. FloatingActionButton olarak tanımladığımız butonların onPressed propertisine telefonumun hafızasından resim alabilmek için _pickImage metodunu tanımlıyorum. Hangi kaynaktan resim yüklemek istiyorsak bu metoda ImageSource değerini parametre olarak verelim. Seçtiğimiz resmi, detayını yüklediğimiz kategori nesnesindeki images listesine ekleyelim, setState metodu ile ekranımızı güncel verileri ile tekrar çizelim.

İki farklı resim seçtim. Güncel olarak görüntümüz aşağıdaki gibi oldu.

Diğer kategoriler için de aynı şekilde farklı resimler seçtiğimizde, seçilen resimler, bağlı olduğu kategorinin images propertisine ekleneceği için resimlerimizi farklı kategorilere göre sınıflandırmış olduk.

Son olarak ise HomePage sayfamızda AppBar kısmında bulunan Archive butonunu etkin hale getirmek. Burada yapılacak işlemler sırası ile:

𐤟 Her bir kategori için oluşturacağımız klasörleri bir klasör altında tutmak için base bir klasör oluşturmak

𐤟 Her bir kategori için farklı bir klasör oluşturmak

𐤟 Seçtiğimiz resimleri bulundukları kategori klasörleri altına taşımak

Archive butonu için IconButton tanımlayalım ve yukarıdaki işlemleri yapabilmek için hazırladığımız createFolder fonksiyonunu onPressed propertisine atıyoruz.

Klasör oluşturmak için file_service.dart isimli bir Dart dosyası açalım ve fonksiyonlarımızı sırası ile orada tanımlayalım.

Dosya işlemleri için dart:io, telefonun hafızasındaki resim ve klasörlerimizin path değerlerini okuyabilmek için ise path_provider değerlerini import ediyoruz.

Öncelikle base klasörümüzü oluşturarak işe başlayalım.

IconButton widgetinin onPressed propertisine atadığımız fonksiyon bizden 2 tane parametre bekliyor. İlk parametremiz oluşturacağımız base klasör adı(images), ikinci parametremiz ise uygulama boyunca üzerine değişiklikler yaptığımız kategori listemiz(_imageCategoryList).

Android ve IOS tarafında farklı dizinlerde işlem gerçekleştireceğimiz için _getPlatformSpecificDirectory() metodunu tanımladık. Bu sayede bulunduğumuz platform özelinde işlemlerimizi gerçekleştirebiliriz.

createFolder metodunda yaptığımız işlem images isimli bir klasör var mı, eğer yoksa oluşturalım sonrasında ise _createPerImageCategoryFolder metoduna elimizde olan categoryList ve images olarak oluşturduğumuz klasörün path değerini göndererek diğer adımları uygulayalım.

Base(images) klasörümüzü oluşturduk. Şimdi ise elimizde bulunan kategori listemizdeki her bir kategori için kendi klasörlerini oluşturalım. Bu sayede, resimleri bulundukları kategoriler altına taşıyabiliriz.

Her bir kategorimiz için klasörlerini oluşturduk. Son olarak resimlerimizi taşıyacağımız metodu yazalım. Bunun için _copyImageToItsRelatedCategoryFolder() isimli metodumuzu yazıyoruz. Bu metot bizden, taşımak istediğimiz resmin yolunu ve hangi kategori klasör altına taşıyacak isek hedef klasörün path değerini istiyor.

Bu işlemleri gerçekleştirdiğimizde base klasörümüz olan images klasörü, images altında oluşturduğumuz birbirinden farklı kategori klasörleri ve kategorilere bağlı olan resimlerin bu klasörler altına taşınma işlemlerini gerçekleştirmiş olduk.

Yapılan işlemlerin çıktısını görebilmek için bir resim ekliyorum.

Android → Data → Uygulamam için oluşturulan klasör →files → dizinlerini sırası ile takip ediyorum.

Kaynak kodları incelediğinizde Hive ile alakalı geliştirmeler olduğunu göreceksiniz. Bir sonraki yazı için hedefim, resimlerin yollarını da Local Storage üzerine kayıt ederek uygulama kapanıp tekrar açıldığında resimlerin tekrar seçilmeden kategori detay sayfasında görüntülenebilir olmaları. Diğer fikir ise Archive butonu ile bu işlemler gerçekleştirildiğinde en son images klasörünü rarlamak ve Restful olarak geliştireceğimiz servis ile uzaktaki veritabanına bu resimlerin yollarını, kategori bazlı kayıt etmek olabilir.

Umarım faydalı bir içerik olmuştur. Eksik veya hatalı olduğunu düşündüğünüz bir kısım var ise geri dönüşünüz çok faydalı olacaktır.

Projenin kaynak kodlarına erişebilmek için:

Local JSON işlemleri için diğer bir kaynak:

--

--