├── .nojekyll
├── README.md
├── _coverpage.md
├── _sidebar.md
├── image
├── WhatsApp Image 2020-11-07 at 08.15.50.jpeg
├── architecture.png
├── core
│ ├── Screen Shot 2020-10-20 at 15.54.16.png
│ ├── Screen Shot 2020-10-20 at 15.54.23.png
│ ├── Screen Shot 2020-10-20 at 15.54.50.png
│ ├── Screen Shot 2020-10-20 at 15.55.03.png
│ ├── arabic.png
│ ├── atomic-design.png
│ ├── base.png
│ ├── lang.png
│ ├── mobx.png
│ ├── route_animation.png
│ ├── view_core.png
│ ├── view_folder.png
│ └── widgets.png
├── drawio
│ ├── atomics.png
│ ├── core-models.png
│ ├── core-widgets.png
│ ├── folders-Features.png
│ ├── folders-Test.png
│ ├── folders-Theme.png
│ ├── folders-beyza.png
│ ├── folders-cache.png
│ ├── folders-constants.png
│ ├── folders-core-models.png
│ ├── folders-googlePlay.png
│ ├── folders-iosPublish.png
│ ├── folders-lang.png
│ ├── folders-me.png
│ ├── folders-mvvm.png
│ ├── folders-navigation.png
│ ├── folders-network.png
│ ├── folders-projects.png
│ ├── folders-state-management.png
│ ├── folders.drawio
│ ├── folders.png
│ ├── nameds.png
│ └── themes.png
├── features
│ ├── _features.png
│ ├── _feautres2.png
│ ├── _subs.png
│ └── _subs2.png
├── panache.png
├── structure.png
└── typgrophi.png
├── index.html
└── src
├── core
├── base_models.md
├── cache.md
├── constants.md
├── core_widget.md
├── extension.md
├── lang_change.md
├── navigation.md
├── network.md
├── state_management.md
└── theme_change.md
├── publish
├── android_publish.md
└── ios_publish.md
├── screens
├── features.md
├── mvvm_struct.md
├── theme_generate.md
└── unit-test.md
├── structure
├── atomic.md
├── folder.md
└── names.md
└── support
├── me-about.md
├── projects.md
└── supports.md
/.nojekyll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VB10/flutter-architecture-docs/a755fc285115275f5b808bec82fde0bd34bcc482/.nojekyll
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # **Flutter Architecture**
2 |
3 | Herkes merhaba 🙋
4 |
5 | Flutter ile gerçek bir proje geliştirme hazzına hazır mısınız?
6 |
7 | Gerek kanalda gerekse yazılarla hep sizlerle birlikte oldum ve özellikle içerik konusunda eşsiz kaynaklar ürettik gelin bunları biraz detayları ile inceleyelim.
8 |
9 | ## Nedir bu Architecture ?
10 |
11 | 
12 |
13 | Birçok uygulama yazılırken süresine, takım liderine veya yetkinliğe bağlı olarak çeşitli yaklaşımlar ile yazılıyor.
14 |
15 | > Burada developer'in her ne kadar eskikliği gibi gözüksede aslında projenın yönetimininde büyük bir suçu vardır.
16 |
17 | **Architecture** yani mimari aslında bir projenin geleceğini ve geçmişini doğru zamanda düşünüp yatırım yapmak ve bu yatırımın sonuçlarını kısa sürede değil ilerleyen günlerde almak olarak düşünebilirsiniz.Bende sizler için bunu bir video serisine çevirip istediğiniz zaman okuyup inceleyip kafanızda bir uygulamının mimarisini nasıl sıfırdan çizebileceğinizi ele aldım.
18 |
19 | 
20 |
21 | Burada gördüğünüz sadece bir özeti buradaki tüm katmanların hepsinin bir amacı ve proje hayatında bir yeri olacak. Diğer sayfalarımızda gelin bunu konuşalım ve geleceğimizi planyalım.
22 |
23 | > Bu seriyi eğer yeni başlıyorsanız birebir yapmanızı tavsiye ederim eğer devam ediyorsanız genel bakış açısıyla kendinize eklemeler yapabilirsiniz.
24 |
25 | Özellikle bu serideki amacım kaliteli kod yazma düşüncesini ve flutter'in bize vermiş olduğu asıl gücü keşfedebilmek olacak. Bir solukta okuyup birçok kavrama ve mantığa alışacağınız bu güzel seriye hazır olun.
26 |
--------------------------------------------------------------------------------
/_coverpage.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | 
4 |
5 | # Flutter Uygulama Mimarisi 1.0.0
6 |
7 | > Bir mobil uygulamanın tüm süreçlerini tek tek ele alıp ardından çözümleriyle birlikte işliyoruz.
8 |
9 | - Mobil uygulama prensibleri, klasörleme.
10 | - Yapısal geliştirmeler
11 | - Ağ istekleri, yerel veri saklama katmanları.
12 | - Durum(State) yönetimi ve paylaşımı.
13 | - Uygulamaları market süreçleri
14 |
15 | [GitHub](https://github.com/VB10/flutter-architecture-template)
16 | [Get Started](#docsify)
17 |
--------------------------------------------------------------------------------
/_sidebar.md:
--------------------------------------------------------------------------------
1 | - [**Flutter Architecture**](/)
2 |
3 | - Yapı
4 |
5 | - [Klasörleme](src/structure/folder.md)
6 | - [İsimlendirme](src/structure/names.md)
7 | - [Atomic Yapı](src/structure/atomic.md)
8 |
9 | - Ana Kısım
10 |
11 | - [Tema Değişimi (Theme Notifier)](src/core/theme_change.md)
12 | - [Ana Widgetlar (Core Widget)](src/core/core_widget.md)
13 | - [Ana Modeller (Base Models)](src/core/base_models.md)
14 | - [Çoklu Dil (Muti Language)](src/core/lang_change.md)
15 | - [State Yönetimi(State Management)](src/core/state_management.md)
16 | - [Sabit değerler(Constants)](src/core/constants.md)
17 | - [Yönlendirme(Navigation)](src/core/navigation.md)
18 | - [Saklama(Cache)](src/core/cache.md)
19 | - [Ağ Katmanı(Network Layer)](src/core/network.md)
20 | - [Uzantılar(Extension)](src/core/network.md)
21 |
22 | * Ekranlar
23 |
24 | - [Geliştirmeler (Features)](src/screens/features.md)
25 | - [MVVM Yapısı (MVVM Structure)](src/screens/mvvm_struct.md)
26 | - [Tema Yönetimi (Theme Management)](src/screens/theme_generate.md)
27 | - [Birim Test (Unit Test)](src/screens/unit-test.md)
28 |
29 | * Publish
30 |
31 | - [IOS Paket, Market Yönetimi ve Fastlane](src/publish/ios_publish.md)
32 | - [Android Paket,Market Yönetimi ve Fastlane](src/publish/android_publish.md)
33 |
34 | - [Referans Projeler](src/support/projects.md)
35 | - [Biraz da Ben](src/support/me-about.md)
36 | - [Gönüllü Takımımız](src/support/supports.md)
--------------------------------------------------------------------------------
/image/WhatsApp Image 2020-11-07 at 08.15.50.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VB10/flutter-architecture-docs/a755fc285115275f5b808bec82fde0bd34bcc482/image/WhatsApp Image 2020-11-07 at 08.15.50.jpeg
--------------------------------------------------------------------------------
/image/architecture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VB10/flutter-architecture-docs/a755fc285115275f5b808bec82fde0bd34bcc482/image/architecture.png
--------------------------------------------------------------------------------
/image/core/Screen Shot 2020-10-20 at 15.54.16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VB10/flutter-architecture-docs/a755fc285115275f5b808bec82fde0bd34bcc482/image/core/Screen Shot 2020-10-20 at 15.54.16.png
--------------------------------------------------------------------------------
/image/core/Screen Shot 2020-10-20 at 15.54.23.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VB10/flutter-architecture-docs/a755fc285115275f5b808bec82fde0bd34bcc482/image/core/Screen Shot 2020-10-20 at 15.54.23.png
--------------------------------------------------------------------------------
/image/core/Screen Shot 2020-10-20 at 15.54.50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VB10/flutter-architecture-docs/a755fc285115275f5b808bec82fde0bd34bcc482/image/core/Screen Shot 2020-10-20 at 15.54.50.png
--------------------------------------------------------------------------------
/image/core/Screen Shot 2020-10-20 at 15.55.03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VB10/flutter-architecture-docs/a755fc285115275f5b808bec82fde0bd34bcc482/image/core/Screen Shot 2020-10-20 at 15.55.03.png
--------------------------------------------------------------------------------
/image/core/arabic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VB10/flutter-architecture-docs/a755fc285115275f5b808bec82fde0bd34bcc482/image/core/arabic.png
--------------------------------------------------------------------------------
/image/core/atomic-design.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VB10/flutter-architecture-docs/a755fc285115275f5b808bec82fde0bd34bcc482/image/core/atomic-design.png
--------------------------------------------------------------------------------
/image/core/base.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VB10/flutter-architecture-docs/a755fc285115275f5b808bec82fde0bd34bcc482/image/core/base.png
--------------------------------------------------------------------------------
/image/core/lang.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VB10/flutter-architecture-docs/a755fc285115275f5b808bec82fde0bd34bcc482/image/core/lang.png
--------------------------------------------------------------------------------
/image/core/mobx.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VB10/flutter-architecture-docs/a755fc285115275f5b808bec82fde0bd34bcc482/image/core/mobx.png
--------------------------------------------------------------------------------
/image/core/route_animation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VB10/flutter-architecture-docs/a755fc285115275f5b808bec82fde0bd34bcc482/image/core/route_animation.png
--------------------------------------------------------------------------------
/image/core/view_core.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VB10/flutter-architecture-docs/a755fc285115275f5b808bec82fde0bd34bcc482/image/core/view_core.png
--------------------------------------------------------------------------------
/image/core/view_folder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VB10/flutter-architecture-docs/a755fc285115275f5b808bec82fde0bd34bcc482/image/core/view_folder.png
--------------------------------------------------------------------------------
/image/core/widgets.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VB10/flutter-architecture-docs/a755fc285115275f5b808bec82fde0bd34bcc482/image/core/widgets.png
--------------------------------------------------------------------------------
/image/drawio/atomics.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VB10/flutter-architecture-docs/a755fc285115275f5b808bec82fde0bd34bcc482/image/drawio/atomics.png
--------------------------------------------------------------------------------
/image/drawio/core-models.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VB10/flutter-architecture-docs/a755fc285115275f5b808bec82fde0bd34bcc482/image/drawio/core-models.png
--------------------------------------------------------------------------------
/image/drawio/core-widgets.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VB10/flutter-architecture-docs/a755fc285115275f5b808bec82fde0bd34bcc482/image/drawio/core-widgets.png
--------------------------------------------------------------------------------
/image/drawio/folders-Features.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VB10/flutter-architecture-docs/a755fc285115275f5b808bec82fde0bd34bcc482/image/drawio/folders-Features.png
--------------------------------------------------------------------------------
/image/drawio/folders-Test.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VB10/flutter-architecture-docs/a755fc285115275f5b808bec82fde0bd34bcc482/image/drawio/folders-Test.png
--------------------------------------------------------------------------------
/image/drawio/folders-Theme.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VB10/flutter-architecture-docs/a755fc285115275f5b808bec82fde0bd34bcc482/image/drawio/folders-Theme.png
--------------------------------------------------------------------------------
/image/drawio/folders-beyza.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VB10/flutter-architecture-docs/a755fc285115275f5b808bec82fde0bd34bcc482/image/drawio/folders-beyza.png
--------------------------------------------------------------------------------
/image/drawio/folders-cache.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VB10/flutter-architecture-docs/a755fc285115275f5b808bec82fde0bd34bcc482/image/drawio/folders-cache.png
--------------------------------------------------------------------------------
/image/drawio/folders-constants.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VB10/flutter-architecture-docs/a755fc285115275f5b808bec82fde0bd34bcc482/image/drawio/folders-constants.png
--------------------------------------------------------------------------------
/image/drawio/folders-core-models.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VB10/flutter-architecture-docs/a755fc285115275f5b808bec82fde0bd34bcc482/image/drawio/folders-core-models.png
--------------------------------------------------------------------------------
/image/drawio/folders-googlePlay.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VB10/flutter-architecture-docs/a755fc285115275f5b808bec82fde0bd34bcc482/image/drawio/folders-googlePlay.png
--------------------------------------------------------------------------------
/image/drawio/folders-iosPublish.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VB10/flutter-architecture-docs/a755fc285115275f5b808bec82fde0bd34bcc482/image/drawio/folders-iosPublish.png
--------------------------------------------------------------------------------
/image/drawio/folders-lang.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VB10/flutter-architecture-docs/a755fc285115275f5b808bec82fde0bd34bcc482/image/drawio/folders-lang.png
--------------------------------------------------------------------------------
/image/drawio/folders-me.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VB10/flutter-architecture-docs/a755fc285115275f5b808bec82fde0bd34bcc482/image/drawio/folders-me.png
--------------------------------------------------------------------------------
/image/drawio/folders-mvvm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VB10/flutter-architecture-docs/a755fc285115275f5b808bec82fde0bd34bcc482/image/drawio/folders-mvvm.png
--------------------------------------------------------------------------------
/image/drawio/folders-navigation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VB10/flutter-architecture-docs/a755fc285115275f5b808bec82fde0bd34bcc482/image/drawio/folders-navigation.png
--------------------------------------------------------------------------------
/image/drawio/folders-network.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VB10/flutter-architecture-docs/a755fc285115275f5b808bec82fde0bd34bcc482/image/drawio/folders-network.png
--------------------------------------------------------------------------------
/image/drawio/folders-projects.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VB10/flutter-architecture-docs/a755fc285115275f5b808bec82fde0bd34bcc482/image/drawio/folders-projects.png
--------------------------------------------------------------------------------
/image/drawio/folders-state-management.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VB10/flutter-architecture-docs/a755fc285115275f5b808bec82fde0bd34bcc482/image/drawio/folders-state-management.png
--------------------------------------------------------------------------------
/image/drawio/folders.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VB10/flutter-architecture-docs/a755fc285115275f5b808bec82fde0bd34bcc482/image/drawio/folders.png
--------------------------------------------------------------------------------
/image/drawio/nameds.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VB10/flutter-architecture-docs/a755fc285115275f5b808bec82fde0bd34bcc482/image/drawio/nameds.png
--------------------------------------------------------------------------------
/image/drawio/themes.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VB10/flutter-architecture-docs/a755fc285115275f5b808bec82fde0bd34bcc482/image/drawio/themes.png
--------------------------------------------------------------------------------
/image/features/_features.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VB10/flutter-architecture-docs/a755fc285115275f5b808bec82fde0bd34bcc482/image/features/_features.png
--------------------------------------------------------------------------------
/image/features/_feautres2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VB10/flutter-architecture-docs/a755fc285115275f5b808bec82fde0bd34bcc482/image/features/_feautres2.png
--------------------------------------------------------------------------------
/image/features/_subs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VB10/flutter-architecture-docs/a755fc285115275f5b808bec82fde0bd34bcc482/image/features/_subs.png
--------------------------------------------------------------------------------
/image/features/_subs2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VB10/flutter-architecture-docs/a755fc285115275f5b808bec82fde0bd34bcc482/image/features/_subs2.png
--------------------------------------------------------------------------------
/image/panache.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VB10/flutter-architecture-docs/a755fc285115275f5b808bec82fde0bd34bcc482/image/panache.png
--------------------------------------------------------------------------------
/image/structure.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VB10/flutter-architecture-docs/a755fc285115275f5b808bec82fde0bd34bcc482/image/structure.png
--------------------------------------------------------------------------------
/image/typgrophi.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VB10/flutter-architecture-docs/a755fc285115275f5b808bec82fde0bd34bcc482/image/typgrophi.png
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Document
6 |
7 |
8 |
12 |
16 |
17 |
18 |
19 |
20 |
21 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/src/core/base_models.md:
--------------------------------------------------------------------------------
1 | # Ana Modeller
2 |
3 | 
4 |
5 | Proje gelişim sürecinde gerekliliği tartışılabilir ama dünden bugüne okuduğum ve araştırdığım zaman birçok faydasını gördüğüm bir yapı burada bizimle olacak.
6 |
7 | Birincisi ben sayfalarımı türetirken ana state üzerinden değil
8 | de base state üzerinden türeterek onlara temel özellikler kazandırıyorum.
9 |
10 | ```dart
11 | abstract class BaseState extends State {
12 | ThemeData get themeData => Theme.of(context);
13 | }
14 | ```
15 |
16 | Ve bir sayfa tanımlarken **\_HomeView extends State** değil **extends BaseState** yaparak bu özellikleri doğrudan ona tanımlamış oluyorum.
17 |
18 | > Bu kısıma siz istediğiniz kadar özellik verebilirsiniz burada ekranların kullanacağı temel yapıları tanımlamak elinizi çok rahatlacaktır.
19 |
20 | Peki sayfalarımızı düşünecek olursak neden [statefull](https://www.youtube.com/watch?v=6baZbJiIuiQ) veya [stateless](https://www.youtube.com/watch?v=ZkP7QgLaZcY) derseniz onları ilgili içeriklerden inceleyebilirsiniz. Biz bir sayfa yaptığımızda genellikle statefull gideriz ama büyük projelerde tüm sayfaları yönetecek bir katmana ihtiyacımız olabilir.O zaman baseview yapısını kurguluyoruz.Bu yapıyla artık kullanacağımız **ViewModel**'i de özellikle istiyoruzki sayfaya güç ve güveni de vermiş oluyoruz.
21 |
22 | > Bu yapı özellikle bir projede eğer internet yoksa tüm ekranlarda ana bir pop-up göstermem gerektiği durumda çok fazla işime yaradı.
23 | > Peki bu ana katmana bakacak olursak;
24 |
25 | ```dart
26 | class BaseView extends StatefulWidget {
27 | final Widget Function(BuildContext context, T value) onPageBuilder;
28 | final T viewModel;
29 | final Function(T model) onModelReady;
30 | final VoidCallback onDispose;
31 | const BaseView({Key key, @required this.viewModel, @required this.onPageBuilder, this.onModelReady, this.onDispose})
32 | : super(key: key);
33 |
34 | @override
35 | _BaseViewState createState() => _BaseViewState();
36 | }
37 | ```
38 |
39 | - İlk satırda kullanıcıdan Store(Mobx yazısı veya dersinde göreceksiniz) istiyoruz ve adama geri döndürüp ekranını çizmesini istiyorum.
40 | - İkinci satırda viewModel katmanını tanımlaması için istiyorum bu iki kısmı **@required** ile işaretliyorumki vermek zorunda olsun.
41 | - Son kısım ise sayfadan çıktığında bir şey yapmak isterse burada çağırması için.
42 |
43 | Ve bu yapıdan türeyen bir örnek yapmak istediğimizde;
44 |
45 | ```dart
46 | @override
47 | Widget build(BuildContext context) {
48 | return BaseView(
49 | viewModel: LoginViewModel(),
50 | onModelReady: (model) {
51 | model.setContext(context);
52 | model.init();
53 | viewModel = model;
54 | },
55 | onPageBuilder: (BuildContext context, LoginViewModel value) => buildScaffold(context),
56 | );
57 | }
58 | ```
59 |
60 | Biz hem sayfa açılınca yapılacak kısımları tanımlamış olduk hem de bu ekranın çizimi için gereken katmanı hazırlayıp viewModel nesnemizi alt birimlerine verme imkanı edindik.
61 |
62 | - Güç ✅ (Tüm sınıflar bildiğimz bir katmandan türüyor.)
63 | - Çeviklik ✅ (Vereceğimiz yeni özelliklere doğrudan erişebilme.)
64 | - Kontrol ✅ (ViewModel katmanımız olsun dispose katmanımız olsun daima ilgili yapılardan türeyip almak zorunda.)
65 |
66 | Burada sayfayı yaparken BaseView kullandığınız için illaki StateFull yapmanıza gerek yok stateless bir widget yaparak baseview içindeki viewmodel objesini ilgili functionlar ile servis edip değişikliği [mobx](https://www.youtube.com/watch?v=1_vqvdqTjP8) katmanında yapabilirsiniz.
67 |
68 | Ve ana modelimizde hazır daha fazlası için 🥳
69 | [](https://www.youtube.com/watch?v=crKJEBxyxS8&list=PL1k5oWAuBhgV_XnhMSyu2YLZMZNGuD0Cv&index=2)
70 |
--------------------------------------------------------------------------------
/src/core/cache.md:
--------------------------------------------------------------------------------
1 | # Veri Saklama (Local Cache)
2 |
3 | 
4 |
5 | Veri konusu özellikle mobil uygulamada en önemli noktalardan birisi değil ta kendisidir çünkü uygulamamız canlıya çıktığında(ilgili marketler de yayına girdiği an) eğer bir güvenlik testine girerse ilk baktıkları nokta uygulamanın cihaz içindeki verileri nerede ve nasıl tuttuğudur. Peki bu veriler nedir:
6 |
7 | 1. Kullanıcının kimlik bilgileri(token,id vb)
8 | 2. Uygulamanın verileri
9 | 3. Az sıklıkla kullanılacak servisden gelen bilgiler(iller, kan grupları vb.)
10 |
11 | Tabiki liste uzar gider. Biz bu verileri mobil uygulamalarda yine birkaç yöntem ile saklayabiliriz:
12 |
13 | - Key-Value([Shared](https://developer.android.com/reference/android/content/SharedPreferences),[UserDefaults](https://developer.apple.com/documentation/foundation/userdefaults))
14 | - File (Doğrudan bir json veya txt dosyasına yazmak)
15 | - [SQLite](https://www.sqlite.org/index.html) (Mobil telefonlar için basit sql database)
16 | - [Core Data ](https://developer.apple.com/documentation/coredata)(Sadece IOS Framework'ü destekleyen bir database mimarisi)
17 |
18 | Ve birkaç özel platform dahilindeki çözümler ile bize saklama imkanı sunuyor. Basit veriler saklamak için en sevdiğim çözüm ise shared yapısı.
19 |
20 | Burada verilerin saklandığı yerde önemli bir nokta. Bu noktada elimizde uygulama içinde kullancının direk erişemediği alan ve telefonun içine kaydetmek üzere alanlar bulunmaktadır.
21 |
22 | Özellikle bu verileri saklamalardan hangisini seçerseniz seçin bir şekilde telefon rootlanarak güvenlik şirketleri tarafından teste sokulup sakladığınız veriler erişip buradan sizin zaafiyetinizi bulabilirler. Bundan ötürü şimdiki yazacağımız cache katmanı önemli ve isterseniz birkaç özellik katarak (bazı verileri kullanarak) kullanıcının bilgilerini şifreleyebilir ve bu sayede güvenliğinizi artırabilirsiniz.
23 |
24 | [Shared Preferences](https://pub.dev/packages/shared_preferences) yani key-value kullanacağım yapıda saklamak için birkaç özel ekleme yapıyor ve bu proje boyunca kullanacağım için bir 'eager singleton pattern' kullanarak bu değeri bir kere üretip devam ettiriyorum.
25 |
26 | [Bu yazımda](https://medium.com/flutter-community/cache-manager-with-flutter-5a5db0d3a3e6) projede özellikle bu cache katmanını birkaç kalemde ele alıp [strategy pattern](https://refactoring.guru/design-patterns/strategy) kullanarak detay bir şekilde ele aldım.
27 |
28 | ```dart
29 | class LocaleManager {
30 | static LocaleManager _instance = LocaleManager._init();
31 |
32 | SharedPreferences _preferences;
33 | static LocaleManager get instance => _instance;
34 | }
35 | ```
36 |
37 | Burada ilk sınıf oluşurken [SharedPreferences](https://www.youtube.com/watch?v=aV4eLUTPSUM) değerinin bir oluşması gerekiyor.(Asenkron bir istek, bu değeri ilk sınıf oluşurken çağırıyoruz ama dediğim gibi bir asenkron olma durumu olduğu için değerin tam olarak almama durumu mevcut.).
38 |
39 | ```dart
40 | LocaleManager._init() {
41 | SharedPreferences.getInstance().then((value) {
42 | _preferences = value;
43 | });
44 | }
45 | ```
46 |
47 | Bu durumu önlemek için şöyle bir çözüm getirip kesin bir şekilde değerin verilmiş olmasını sağlıyorum.
48 |
49 | ```dart
50 | static prefrencesInit() async {
51 | if (instance._preferences == null) {
52 | instance._preferences = await SharedPreferences.getInstance();
53 | }
54 | return;
55 | }
56 |
57 | ```
58 |
59 | Ve ilgili değeri `main.dart` dosyasında çağırıyorum.
60 |
61 | ```dart
62 | Future main() {
63 | WidgetsFlutterBinding.ensureInitialized();
64 | await LocaleManager.prefrencesInit();
65 | runApp(...)
66 | }
67 | ```
68 |
69 | Ve hazırız artık shared değerimiz elimizde hazır durumda. Şimdi ben projelerimde şu şekilde gidiyorum:
70 |
71 | - [Key - value](https://www.youtube.com/watch?v=aV4eLUTPSUM) yapısı olduğu için key değerini adamın elle vermemesi için enum istiyorum ve gelen enumun değerini toString diyerek key yapıyorum.
72 | - İlgili metodları ben kendim tekrar yazıyorum.(setStringValue ,setBoolValue)
73 | - Yine ilgili değerleri verdikten sonra bu değerleri almak için getStringValue metodlarını yazmış oluyorum
74 |
75 | > İşte bu yönetici sınıfı ile ileride her kaydettiğimiz verinin şifrelenmesini burada yapmış olacağız.
76 | > Değeri ilk başta asenkron olarak yüklediğimiz için getStringValue dediğimizde doğrudan değeri okuyabiliyoruz aksi halde async dememiz gerekecekti.
77 |
78 | ```dart
79 | Future setStringValue(PreferencesKeys key, String value) async {
80 | await _preferences.setString(key.toString(), value);
81 | }
82 |
83 | String getStringValue(PreferencesKeys key) =>
84 | _preferences.getString(key.toString()) ?? "";
85 | ```
86 |
87 | Parametre olarak istenilen ise bir enum olup her yeni değer saklamak istediğimizde buraya parametre olarak ekleyeceğiz.
88 |
89 | ```dart
90 | enum PreferencesKeys {
91 | APP_NAME
92 | }
93 | ```
94 |
95 | Ve artık hazırız. Projemizde istediğimiz an şu şekilde çağırabiliriz:
96 |
97 | ```dart
98 | Text(LocaleManager.getStringValue(PreferencesKeys.APP_NAME));
99 | ```
100 |
101 | Diğer detaylara buradan erişebilirsiniz 🥳
102 |
103 | [](https://www.youtube.com/watch?v=4U8ekZJLxac&list=PL1k5oWAuBhgV_XnhMSyu2YLZMZNGuD0Cv&index=6)
104 |
--------------------------------------------------------------------------------
/src/core/constants.md:
--------------------------------------------------------------------------------
1 | # Sabit Değerler (Constants)
2 |
3 | 
4 |
5 | Bir uygulama hayatında çok önemli olmasa da yönetimi açısından önemli olan bir kavramdır. Özellikle sabit tanımlarken iki tavır belirliyorum genelde:
6 |
7 | 1. Proje boyunca kullanılacak ve katma değeri çok yüksek ise(proje ismi gibi) bunları [Magic Number](https://help.semmle.com/wiki/display/JAVA/Magic+numbers#:~:text=A%20magic%20number%20is%20a,for%20other%20programmers%20to%20understand.) olarak tanımlıyorum.
8 | 2. Projede gerekli alanlarda ihtiyacım olacak ise [lazy singleton pattern](https://www.journaldev.com/1377/java-singleton-design-pattern-best-practices-examples#eager-initialization) kullanarak yapıyorum.
9 |
10 | > Bu tarz tanımlamalar yaparken kendi oluşturduğum snippet'larımı kullanarak çok hızlıca tanımlıyorum.
11 |
12 | ## Magic Number
13 |
14 | Burada aslında temel olarak bize anlatılmak istenen ilgili değişkenin projenin en üstünde ve değerli bir başka developerin bu değişkene dokunmaması gerektiği anlamına gelmektedir.
15 |
16 | Tanımlanırken `constant static Type veriable_name = value;` formatında olur. Örnek olarak bakalım;
17 |
18 | ```dart
19 | class YourConstantsClass {
20 | static const String PROJECT_NAME = "HWA";
21 | static const String FONT_FAMILY = "POPPINS";
22 | }
23 | ```
24 |
25 | ## Lazy Singleton Pattern
26 |
27 | Singleton pattern bildiğimiz gibi bir değişkeni hayatı boyunca ayakta tutan ve yeni bir nesne üretmemizi engelleyen dizayn olarak düşünebiliriz. Burada dizaynın alt dalları mevcut.Ben kullanırken lazy yaklaşımını seviyorum. Buradaki amaç ilgili obje çağrıldığı anda doldurulması ve bundan sonra hayatına devam etmesi.
28 |
29 | ```dart
30 | class YourConstantsClass {
31 | static YourConstantsClass _instace;
32 | static YourConstantsClass get instance {
33 | if (_instace == null) _instace = YourConstantsClass._init();
34 | return _instace;
35 | }
36 |
37 | YourConstantsClass._init();
38 |
39 | String phoneNumber = "********";
40 | String mailAdress = "**********";
41 | }
42 | ```
43 |
44 | Kullanırken ise;
45 |
46 | `Text(YourConstantsClass.instance.phoneNumber)` şeklinde çağırmış oluruz.
47 |
48 | > Snippetlar ile magicnumber ve eager or lazy yazarak bu patterni dahil etmiş oluyorum. Sadece ismini vererek oluşuyor.
49 |
50 | Diğer detaylara buradan erişebilirsiniz🥳
51 |
52 | [](https://www.youtube.com/watch?v=cCBQSpDup4o&list=PL1k5oWAuBhgV_XnhMSyu2YLZMZNGuD0Cv&index=5)
53 |
--------------------------------------------------------------------------------
/src/core/core_widget.md:
--------------------------------------------------------------------------------
1 | # Ana Widget
2 |
3 | 
4 |
5 | Projeler de widget'larımızı ne kadar parçalayabilirsek bizim gücümüz bir o kadar artacaktır.Bu yapıda dikkat etmemiz gereken hangilerinin ana widget olacağıdır.
6 |
7 | > Bu yazıyı okumadan önce [stateless](https://www.youtube.com/watch?v=ZkP7QgLaZcY) ve [statefull](https://www.youtube.com/watch?v=6baZbJiIuiQ) kavramları ile ilgili içerikleri izlemeyi unutmayın.
8 |
9 | - Eğer projedeki kullandığınız widget'in bağımlılığı(herhangi bir iş katmanına) yok ise bu ana widget olmaya adaydır.
10 | Örnek olarak bir indicator widgeti yapacak olsaydık bunun tek görevi ilgili item seçildiğinde büyük gözükmek olsaydı bunu sadece dışarı rahatlıkla çıkartabilirdik.
11 |
12 | ```dart
13 | class CustomIndicator extends StatelessWidget {
14 | final bool isSelected;
15 |
16 | CustomIndicator(this.isSelected);
17 |
18 | @override
19 | Widget build(BuildContext context) {
20 | return CircleAvatar(backgroundColor:isSelected? Colors.blue : Colors.white)
21 | }
22 | ```
23 |
24 | Tabiki sadece iş yapan katmanlar için bunu söylemek doğru olmaz burada diyelim ki indicator'leri yönetecek bir katmanımız var ama işi sadece bunu yapmak olsun ve seçileni geri döndürmek olsun;
25 |
26 | ```dart
27 | class CustomIndicator extends StatefulWidget {
28 | CustomIndicator({Key key}) : super(key: key);
29 |
30 | _CustomIndicatorState createState() => _CustomIndicatorState();
31 | }
32 |
33 | class _CustomIndicatorState extends State {
34 | int currentIndex = 0;
35 |
36 | @override
37 | Widget build(BuildContext context) {
38 | return Scaffold(
39 | floatingActionButton: FloatingActionButton(onPressed: () {
40 | setState((){
41 | currentIndex++;
42 | });
43 | }),
44 | body: ListView.builder(
45 | itemCount: 3,
46 | shrinkWrap: true,
47 | itemBuilder: (BuildContext context, int index) {
48 | return CustomIndicator(isSelected: index == currentIndex);
49 | },
50 | ));
51 | }
52 | }
53 | ```
54 |
55 | Gibi bir örnekle hiçbir kodu sayfaya eklemeden atomic olarak dışarı çıkarmış ve işimizi bitirmiş olacaktık.Tabiki buralara ekleme yapılabilir, çoğaltılabilir ama tüm mantık aslında atomic design için bu kadar **basit** ve **sade** olmalı.
56 |
57 | Örnek bir projemdeki atomic katmanım şu şekilde;
58 | 
59 |
--------------------------------------------------------------------------------
/src/core/extension.md:
--------------------------------------------------------------------------------
1 | # Uzantılar (Extensions)
2 |
3 | Bir projeyi en rahatlacak ve kodlarımıza güç katacak kısım olarak tam da burayı düşünebiliriz.Buradaki amacımız yapılara güç kazandırıp hem kodsal açıdan avantaj elde etmek hem de fazladan değer katmaktır.
4 |
5 | Extension hemen hemen tüm modern dillerde mevcuttur.Dillere göre farklı özellikleri; örneğin swift dili için kendi kurucu metodu olması içinde fonksiyon yazılması gibi gelişmiş kullanımları mevcut dartta daha standart ama işimizi oldukça kolaylaştırıyor.
6 |
7 | Bir extension yazmadan önce düşünmemiz gereken neye, nerede, ne kadar ihtiyacımız var.Örneğin tüm sayfalarda hemen hemen padding kullanırız.Yani boşluk vermek için bir değer atarız bunu her yerde elle tanımlamak yerine bir extension yazarak context değerimiz aracılığıyla erişebiliriz.
8 |
9 | ```dart
10 | extension PaddingExtension on BuildContext {
11 | EdgeInsets get paddingLow => EdgeInsets.all(lowValue);
12 | }
13 | ```
14 |
15 | İlk extension'umuzun ismini yazıyoruz 'on' dan sonraki kısımda ise neye değer kattığımızı ekleyerek tamamlamış oluyoruz.
16 |
17 | ```dart
18 | import 'context_extension.dart';
19 |
20 | class HelloView extends StatelessWidget {
21 | const HelloView({Key key}) : super(key: key);
22 |
23 | @override
24 | Widget build(BuildContext context) {
25 | return Container(
26 | padding:context.paddingLow,
27 | child: child,
28 | );
29 | }
30 | }
31 | ```
32 |
33 | Diyerek hem merkezi hem de sayfalarımızın hepsinde ortak bir padding değeri kullanmış oluyoruz.Bunu istediğimiz her yere bu mantıkla dahil edebiliriz.
34 |
35 | Burada dikkat etmeniz gereken bir extension'u ilgili sınıfa kazandırabilmeniz için o extension sınıfını ilgili sayfaya import etmiş olmanız gerekiyor.Bu path sayesinde o extension'a erişip gücünü o değere veriyor.
36 |
37 | ---
38 |
39 | Ve ana modelimiz de hazır daha fazlası için 🥳
40 |
41 | [](https://www.youtube.com/watch?v=FRStsCaAm_g&list=PL1k5oWAuBhgV_XnhMSyu2YLZMZNGuD0Cv&index=9)
42 |
--------------------------------------------------------------------------------
/src/core/lang_change.md:
--------------------------------------------------------------------------------
1 | # Çoklu Dil Desteği ve Anlık Dil Değişimi
2 |
3 | 
4 |
5 | Birçok uygulamanın artık olmazsa olmaz noktalarından birisidir. Özellikle ingilizce desteği çok önemli bir yere sahiptir. Önceden dil desteği gibi işlemler için kendi yapımı kullanırdım ama [easy localization](https://pub.dev/packages/easy_localization) paketi son haliyle birçok konuda bu kısmı çözüyor.
6 |
7 | > Paketin kullanımı oldukça kolay ama yine de dikkat etmeniz gereken noktalar ve birkaç script ile işinizi kolay yolla çözmeyi inceleyelim.
8 |
9 | Proje ilk başlarken runApp kısmında EasyLocalization ile sarmalamamız gerekiyor.
10 |
11 | ```dart
12 | child: EasyLocalization(
13 | child: MyApp(),
14 | supportedLocales: LanguageConstants.instance.supportedLocales,
15 | fallbackLocale: LanguageConstants.instance.trLocale,
16 | path: AppConstants.ASSETS_LANG_PATH,
17 | ),
18 |
19 | class MyApp extends StatelessWidget {
20 | @override
21 | Widget build(BuildContext context) {
22 | return MaterialApp(
23 | localizationsDelegates: context.localizationDelegates,
24 | supportedLocales: context.supportedLocales,
25 | locale: context.locale,
26 | )}}
27 | ```
28 |
29 | - LanguageConstants sınıfımı özel olarak yapıp içine tr ve en paketlerini ekliyorum
30 | Örneğin trLocale = Locale("tr","TR);
31 | - FallBack locale kısım ise projenin ana dilini belirlemek için kullanıyoruz bazı projeler de sadece tr istenebiliyor ondan ben bu şekilde bir örnek yaptım.
32 | - Path kısmı benim tr ve en jsonlarımı sakladığım kısmın adresidir.(Kendisi bir otomatik adres atıyor fakat ben yazdığım script ile istediğim yerde konumlandırıyorum.)
33 |
34 | Örnek kulalnımda ise;
35 |
36 | > Extension kullanmak istersek EasyLocalization yazıp import pathini ekliyoruz
37 |
38 | ```dart
39 | Text(LocalaKeys.sample_title.locale).tr()
40 | //veya kendi yazacağınız StringExtension ile bu gücü kazanabilirsiniz.
41 | Text(LocalaKeys.sample_title.locale)
42 | ```
43 |
44 | Değiştirmek için ise çok basitçe;
45 |
46 | ```dart
47 | context.locale = Locale('en', 'US');
48 | ```
49 |
50 | Burada oluşturacağımız tr ve en json dosyaları için şu şekilde bir sh script hazırladım siz de rahatlıkla bunu kullanabilirsiniz.
51 |
52 | ```sh
53 | flutter pub run easy_localization:generate -O lib/core/init/lang -f keys -o locale_keys.g.dart --source-dir assets/lang
54 | ```
55 |
56 | Oluşturacağımız json dosyalarının içine herhangi bir key value koyup ardından bu scripti çağırarak doğrudan kodları üretmiş oluyoruz.
57 |
58 | 
59 |
60 | Özellikle projelerimde genelde ingilizce devam ediyorum ama gün sonunda tr de gerektiğinde tüm seçili jsondaki valueleri seçip [vscode daki converter](https://marketplace.visualstudio.com/items?itemName=funkyremi.vscode-google-translate) extensionu ile istenilen dile çevirebilirsiniz.
61 |
62 | Burada valueleri seçmek için şu şekilde bir regex yapıyorum ve sadece değerleri seçebiliyorum.
63 |
64 | > (: ")(.\*?)(?:")
65 |
66 | 
67 |
68 | Ve artık hem çoklu dil desteğimiz tek dokunuş ile hazır hem de çalışma zamanında değişiklik yapabiliyoruz.
69 |
70 | Ve ana modelimiz de hazır daha fazlası için 🥳
71 | [](https://www.youtube.com/watch?v=jQ8JuX5RpNc&list=PL1k5oWAuBhgV_XnhMSyu2YLZMZNGuD0Cv&index=4)
72 |
--------------------------------------------------------------------------------
/src/core/navigation.md:
--------------------------------------------------------------------------------
1 | # Yönlendirme (Navigation)
2 |
3 | 
4 |
5 | Projelerin hayatında en önemli olan kısımlardan birisidir. Özellikle mobil app için çok sıklıkla kullanıp sayfalar arası veri taşıma veya sayfalardan geçiş animasyonları gibi katmanları burada yapıyoruz.
6 |
7 | > Navigasyon işlemi için birkaç yöntem mevcut ben en iyi yöntem olarak navigation key kullanarak global olarak yönetmeyi seviyorum. Bu yöntemle bir daha contexte ihtiyacım olmadan kullanabiliyorum. Aynı şekilde bu değişkene signleton olarak erişebildiğim gibi provider kısmına da ekleyip istediğim anda erişebiliyorum.
8 |
9 | Öncelikle bir navigation sınıfı yaratıyorum. Bu içerisinde hem navigation keyi tutacak hem de navigation işlemlerimi yapacaktır. Burada proje boyunca kullanacağım için navigationu lazy singleton olarak bir sınıf tanımlayıp her yerden çağrılabilecek hale geliyorum.
10 |
11 | ```dart
12 | class NavigationService implements INavigationService {
13 | static NavigationService _instance = NavigationService._init();
14 | static NavigationService get instance => _instance;
15 |
16 | NavigationService._init();
17 |
18 | GlobalKey navigatorKey = GlobalKey();
19 | }
20 | ```
21 |
22 | Ardından sınıfıma navigate hareketleri kazandırıyorum. Birçok durum olabilir ama ben projelerimde çok sık kullandığım ikisini ekledim şuanlık devamında diğerlerini de eklemiş oluruz.
23 |
24 | ```dart
25 |
26 | @override
27 | Future navigateToPage({String path, Object data}) async {
28 | await navigatorKey.currentState.pushNamed(path, arguments: data);
29 | }
30 |
31 | @override
32 | Future navigateToPageClear({String path, Object data}) async {
33 | await navigatorKey.currentState.pushNamedAndRemoveUntil(path, removeAllOldRoutes, arguments: data);
34 | }
35 | ```
36 |
37 | Artık bu sınıfımızı kullanıp projemizde hareketleri buradan yapabiliriz. Dediğim gibi bir yerden yönetmek bize her anlamda avantaj sağlayacaktır.(Misal hangi sayfaya daha çok girdiği verilerini bu katmandan analitik tutarak servislere atabilmek gibi.)
38 |
39 | Projemiz içindeki main.dart dosyasına gidip bu navigator key'imizi verelim ve projenin buradan işlem yapacağını anlamış olsun.
40 |
41 | ```dart
42 | class MyApp extends StatelessWidget {
43 | @override
44 | Widget build(BuildContext context) {
45 | return MaterialApp(
46 | theme: Provider.of(context, listen: false).currentTheme,
47 | home: OnBoardView(),
48 | onGenerateRoute: NavigationRoute.instance.generateRoute,
49 | navigatorKey: NavigationService.instance.navigatorKey,
50 | );
51 | }
52 | ```
53 |
54 | Navigator Key tanımladıktan sonra ihtiyacımız olan [onGerateRoute](https://github.com/VB10/flutter-architecture-template/blob/master/lib/core/init/navigation/navigation_route.dart) kısmı, bu kısım için ise bize lazım olan bir yönlendirme yönetimi yapacak katmandır.
55 |
56 | > Yönlendirme yönetiminde amaç hangi sabitin hangi yere gideğini belirlemek ve geçiş yaparken animasyonları belirlemek olarak düşünebilirsiniz.
57 |
58 | ```dart
59 | class NavigationRoute {
60 | static NavigationRoute _instance = NavigationRoute._init();
61 | static NavigationRoute get instance => _instance;
62 |
63 | NavigationRoute._init();
64 |
65 | Route generateRoute(RouteSettings args) {
66 | switch (args.name) {
67 | case NavigationConstants.TEST_VIEW:
68 | return normalNavigate(TestsView());
69 | default:
70 | return MaterialPageRoute(
71 | builder: (context) => NotFoundNavigationWidget(),
72 | );
73 | }
74 | }
75 |
76 | ```
77 |
78 | Temel mantıkta ilgili sabitlere göre yönlendirmeyi her sayfa için tanımlayıp ardından buradaki koşullarda yönlendirmeyi veya verileri paslamanız gerekmektedir.
79 |
80 | > Bir enum yapısı yapılıp extension da eklenebilir.Ben navigation da sabit tanımlamayı daha kolay ve hızlı buluyorum.
81 |
82 | Burada normalNavigate gibi misal projelerimde fadein veya bounce out gibi eventler vererek sayfa geçişlerimi yapabiliyorum [bunların hepsini ](https://github.com/VB10/flightflutter/tree/master/lib/core/init/navigation)bu katmanda verip sadece [ilgili yönlendirme sınıflarına](https://www.youtube.com/watch?v=H9z0SyFs6Uc) paslamak oluyor.
83 |
84 | ```dart
85 | Route fadeNavigate(Widget widget, RouteSettings settings) {
86 | return FadeRoute(page: widget, settings: settings);
87 | }
88 | ```
89 |
90 | 
91 |
92 | Ve artık gideceği yer ve nasıl yapılacağı hazır sadece sabitleri tanımlamamız gerekiyor.
93 |
94 | ```dart
95 | class NavigationConstants {
96 | static const TEST_VIEW = "/test";
97 | }
98 | ```
99 |
100 | Ardından kullanırken;
101 | `NavigationService.instance.navigateToPage(NavigationConstants.TEST_VIEW)` şeklinde yapıp işlemimizi bitirmiş oluyoruz.
102 |
103 | Diğer detaylara buradan erişebilirsiniz🥳
104 |
105 | [](https://www.youtube.com/watch?v=cCBQSpDup4o&list=PL1k5oWAuBhgV_XnhMSyu2YLZMZNGuD0Cv&index=5)
106 |
107 | | Konular | Açıklama |
108 | | ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
109 | | State Management | [](https://www.youtube.com/watch?v=eP2xfFylc24&list=PL1k5oWAuBhgV_XnhMSyu2YLZMZNGuD0Cv&index=3) |
110 | | Provider | [](https://www.youtube.com/watch?v=jQ8JuX5RpNc&list=PL1k5oWAuBhgV_XnhMSyu2YLZMZNGuD0Cv&index=4) |
111 |
--------------------------------------------------------------------------------
/src/core/network.md:
--------------------------------------------------------------------------------
1 | # Ağ Katmanı (Network Layer)
2 |
3 | 
4 |
5 | Bir mobil uygulamada olmazsa olmaz ve doğru yönetilmesse çok zor olacağı bir katmandır.Burada ki amacımız bize verilen misal [Json Place Holder](https://jsonplaceholder.typicode.com/) gibi bir servisi alıp doğrudan uygulamamızda çağırıp kullanmak.Tabii ki bu katmanda işlemler merkezileştirilip tekrar tekrar veya tek bir noktadan kullanılması düşünülmek üzere planlamalıyız. Benim açıkça en çok değer verdiğim ve önemsediğim katmandır.
6 |
7 | > Bu noktaya başlarken sıfırdan yazıp anlattığım gibi bu anlattığım yapıyı her projede oluşturmak yerine ortak bir library yapıp pub.dev üzerinde yayınladım isterseniz sizde kullanıp destek verebilirsiniz.
8 |
9 | [**\*Vexana\*\***](https://pub.dev/packages/vexana) network servis hizmeti veren bir paket.
10 |
11 | Peki gelin önce konuşalım bir servis katmanında neler olur neler olmalı:
12 |
13 | - Genelde mobil uygulamalar tek bir servis noktası üzerinden çalışır yani o x,y,z db bilmez, host bilmez, bundan ötürü bu servis linkimizi proje başlarken verebiliriz.
14 | - İkinci olarak projelerde genelde iki ama toplamda dört yöntem ile gideriz:
15 | - GET: Bu istek ile genelde sadece verileri çekmek için kullanırız.
16 | - POST: Bu istek ile verimizi servise göndermek için kullanırız.Model yollayabildiğimiz için [query paramatere](https://en.wikipedia.org/wiki/Query_string) göre daha güvenlidir.
17 | - DELETE: Bu istek ismindeki gibi servise gönderilip ilgili verinin silinmesi için seçiilir.
18 | - PUT: Bu istek ilede servis gönderilip veri güncellemesi yapılır.
19 | - Servisten gelen başarılı cevapları ortak bir modelle karşılamak ve gelen sorunları ortak bir modele çevirme işlemi gerekir.
20 | - Servis istekleriniz de diyelim ki kullanıcı giriş yaptıysa token datasının gitmesini istiyorsunuz bunu ana servis katmanınızda halledebilirsiniz.
21 | - Servisinizden gelen hatalara göre misal 401 uygulamınızda refresh yapısı kurgulayıp kullanıcı hiç anlamadan onu tekrar devam ettirebilirsiniz.
22 |
23 | Yukarıdaki tüm başlıkları vexana paketinde bulabilirsiniz.Tabii ki daha farklı çözümler veya katmanlarda olabilir ama benim gördüğüm bu başlıklarla çok rahat uygulamanızı yönetir ve rahatlıkla testlerinizi yazıp çok rahat geliştirmeye devam edersiniz.
24 |
25 | > Bu yazdığımız başlıkların merkezi bir katmanda değil her istekte yapıldığını düşündüğümüzde ne kadar zor ve yönetiminin neredeyse imkansız olduğunu görebilirsiniz.
26 |
27 | > Bu servis konusunda ele aldığım [5 Dakikada Firebase](https://medium.com/hardwareandro/5-minutes-firebase-rest-service-c990c1f70031) ile servis geliştirme yazımı inceleyebilir konuyu tam olarak kullanıp demo uygulamalarınız için hızlıca geliştirebilirsiniz.
28 |
29 | Şimdi ben doğrudan flutterin vermiş olduğu ağ özellikleri ile yapabilirdim fakat bu tarz ağ katmanlarının ilk kısımlarını genelde topluluklarının çok kullandığını tercih edip üzerine kendi fikirlerimi ekliyorum. Flutter tarafında en çok kullanılan benim gördüğüm:
30 |
31 | - [HTTP](https://pub.dev/packages/http) : Google Ekibinin yazmış olduğu basit bir şekilde isteklerinizi atıp, cevaplarını karşılayabildiğiniz çözüm.
32 | - [Dio](https://pub.dev/packages/dio): Google China ekibinin yazmış olduğu http ye göre daha kompleks ve bir çok özellik barındıran paket.
33 |
34 | Burada tercih ederken hiç düşünmeden dio seçip vermiş olduğu özellikleri kullanmayı seçtim. HTTP genelde benim sample veya kolay projelerde tercih ettiğim yapıdır.
35 |
36 | ---
37 |
38 | [Bu katman](https://github.com/VB10/flutter-architecture-template/blob/master/lib/core/init/network/core_dio.dart) için kendim diodan türeyen bir sınıf oluşturup kendi özelliklerimi(fetch) kazandırıyorum. Bu projede kullanıcıya sadece options alıp base url, connection timeout gibi özellikleri veriyorum.
39 |
40 | ```dart
41 | class CoreDio with DioMixin implements Dio, ICoreDio {
42 | final BaseOptions options;
43 |
44 | CoreDio(this.options) {
45 | this.options = options;
46 | this.interceptors.add(InterceptorsWrapper());
47 | this.httpClientAdapter = DefaultHttpClientAdapter();
48 | }
49 | }
50 | ```
51 |
52 | [Interceptor](https://docs.microsoft.com/en-us/dotnet/framework/data/wcf/interceptors-wcf-data-services) yapısı dio da en çok sevdiğim ve bize request,response,error anlarını yönetmeyi sağlıyor.
53 |
54 | ```dart
55 | InterceptorsWrapper(onError:,onResponse:,onRequest:)
56 | ```
57 |
58 | [Burada yaptığım](https://github.com/VB10/WhatsApp-Chat) bir örnekte requestlerimin hepsinin sonuna .json eklemeyi yapmıştım sadece bir düşünce olarak devam edebilirsiniz.
59 |
60 | Şimdi yazacağımız en önemli katman ise burasıdır.Burada yazacağımız fetch methodu tüm istekleri yönetip sonuçlara göre kullanıcıya haber verecektir.
61 |
62 | ### BaseModel
63 |
64 | Flutter projelerinde çok sıklıkla göreceğiniz toJson ve fromJson methodlarıdır.Bu methodlar gelen jsonu parse etmek ve var olan modeli json yapmak içindir.Base Model ile şunu diyorum kullanıcıya:
65 | **Eyy kullanıcı bu modeli kafana göre veremezsin, ben senin parse işlemini yapacağım bunun için baseModelden türemek zorundadır.**
66 |
67 | ```dart
68 | abstract class BaseModel {
69 | Map toJson();
70 | T fromJson(Map json);
71 | }
72 | ```
73 |
74 | Ve bu tanımlamadan sonra fetch metodumdaki ilk kısım anlamlanmış oluyor.
75 | `Future> fetch`
76 |
77 | Peki bu IResponseModel ne yapıyor derseniz bu da aynı basemodel gibi çalışıyor farkı kullanıcı ne isterse onu verip üzerine kendim oluşturduğum yapıya göre dönüyor.
78 |
79 | Yani diyelim ki User modeli istiyorsunuz sadece demeniz gereken:
80 | `CoreDio.fetch` peki neden iki defa user dedik diyecek olabilirsiniz buradaki amaç şu ilk verdiğiniz parametre dönecek olan tip ikinci parametre ise o tipin parse olacağı model.
81 |
82 | Siz bir List isteyebilirdiniz `CoreDio.fetch,User>` şeklinde çağırabileceksiniz. Bu konuyu özellikle yaklaşık bir buçuk saatlik videoda ele aldım yazının sonunda orada da dinleyip anlayacaksınız.
83 |
84 | > Bu T ler R ler generic kullanımdır kullanıcın verdiği değere göre şekillenirler [buradan](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/generic-type-parameters) bu konun detayını incleyebilirsiniz.
85 |
86 | ```dart
87 | abstract class IResponseModel {
88 | T data;
89 | IErrorModel error;
90 | }
91 | ```
92 |
93 | IResponseModel ile artık developere istediği değer ve error ile birlikte bir yapı dönmüş oluyorum. Şimdi kullancıdan istediği type, path, query gibi değerleri alıp bizim istek atacağımız katmana ekliyoruz.
94 |
95 | ```dart
96 | Future> fetch(String path,
97 | {@required HttpTypes type,
98 | @required T parseModel,
99 | dynamic data,
100 | Map queryParameters,
101 | void Function(int, int) onReceiveProgress})
102 | ```
103 |
104 | Ve kullanıcının verdiği bilgilere göre isteğimizi atıp sonuca göre şekillendiriyorum.
105 |
106 | ```dart
107 | final response = await request(path, data: data, options: Options(method: type.rawValue));
108 | switch (response.statusCode) {
109 | case HttpStatus.ok:
110 | case HttpStatus.accepted:
111 | final model = _responseParser(parseModel, response.data);
112 | return ResponseModel(data: model);
113 | default:
114 | return ResponseModel(error: BaseError("message"));
115 | }
116 | ```
117 |
118 | Yapmak istediğim gelen sonuç 200 ve 201 ise başarılı görüp servisten gelen o json bilgisini adamın verdiği modele çevirip adama geri döndürüyorum.
119 |
120 | Diyelim ki cevap başarısız bu projede geriye base error dönüp ekranda bunu gösteriyorum.
121 |
122 | Peki \_responseParser ne yapıyor diye düşünürsek bu da çok basitce gelen veriyi list mi map mi yoksa ilkel bir veri mi diye bakıp işlemini yapıp geriye döndürüyor.
123 |
124 | ```dart
125 | R _responseParser(BaseModel model, dynamic data) {
126 | if (data is List) {
127 | return data.map((e) => model.fromJson(e)).toList().cast() as R;
128 | } else if (data is Map) {
129 | return model.fromJson(data) as R;
130 | }
131 | return data as R;
132 | }
133 | ```
134 |
135 | Ve artık katmanımız hazır ya k[ullanmak isteseydik](https://github.com/VB10/flutter-architecture-template/blob/master/test/core/network/core_dio_test.dart):
136 |
137 | ```dart
138 | setUp(() {
139 | service = CoreDioMock(BaseOptions(baseUrl: "https://jsonplaceholder.typicode.com"));
140 | });
141 | test("CoreDio List", () async {
142 | final response =
143 | await service.fetch, PostModel>("/posts", type: HttpTypes.GET, parseModel: PostModel());
144 |
145 | expect(response.data == List , true);
146 | });
147 | ```
148 |
149 | Şeklinde çekip alabiliriz. Peki ekranımıza hata bilgisini basmak isteseydik;
150 |
151 | ```dart
152 | final response =
153 | await service.fetch, PostModel>("/posts", type: HttpTypes.GET, parseModel: PostModel());
154 | if (response.error != null) {showMessage(response.error.message)}
155 | ```
156 |
157 | Çok basit ve güzel bir şekilde mimarimiz hazır. Bırakacağım bu iki içerikle konuları iyice çözebilir ve kendi düşüncenize göre yapabilirsiniz.
158 |
159 | | Konular | Açıklama |
160 | | ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
161 | | Network Katmanı Giriş | [](https://www.youtube.com/watch?v=Nf0PhgbuNRw&list=PL1k5oWAuBhgV_XnhMSyu2YLZMZNGuD0Cv&index=7) |
162 | | Network Katmanı Advance | [](https://www.youtube.com/watch?v=SuCvQyZe054&list=PL1k5oWAuBhgV_XnhMSyu2YLZMZNGuD0Cv&index=10) |
163 |
--------------------------------------------------------------------------------
/src/core/state_management.md:
--------------------------------------------------------------------------------
1 | # Durum(State) Yönetimi
2 |
3 | 
4 |
5 | Öncelikle state dediğimiz kavramı olay, durum veya küçük bir hayat olarak düşünebiliriz. Bu kadar önemli tutan şey ise doğru bir yapı kurgulanması yönetimini kolaylaştırdığı gibi kompleks projelerde size ilgili yapı(framework) verdiği saf haliyle gitmek ilerledikçe karmaşa ve bazı performans sorunları da açacaktır.
6 |
7 | 
8 |
9 | > En sevdiğim görsellerden yani bize diyor ki ekrandaki değişiklik sayfadaki kodlarının state göre etkilenmesi sonucunda ortaya çıkandır.
10 |
11 | Flutter kısmına gelecek olursak birçok kullanım birçok yöntem paketler ve yazılarla destekleniyor ama ben projelerimde iki tavır ile gidiyorum. Bunlardan birisi [mobx](https://www.youtube.com/watch?v=OxdgMVg6yl0), birisi [bloc](https://www.youtube.com/watch?v=L5MAldB2aSc) olarak söyleyebilirim. Bu iki yönetim ile sayfayı yönetirken global state yönetiminde [provider](https://pub.dev/packages/provider) kullanarak rahatlıkla sayfalarımda veri olur veya başka bir işlem olur yapabiliyorum.
12 |
13 | > Örnek verelim: son projemde sepete ürün ekleme, silme işlemleri vardı ama bu işlem 3-4 farklı iç ve ana sayfalardan yapalabiliyordu. Bunu yapmak için sadece bir product sınıfı yapıp bunu globalde context te tutarak ilgili metodu çağırarak sonuca varmış oldum.
14 | > Bir örnek de [Cumhuriyet](https://play.google.com/store/apps/details?id=tr.com.vbt.cumhuriyetmobileapp) app'inde sayfa detayındaki font değişikliği veya tema hareketleri olarak inceleyebilirsiniz.
15 |
16 | ---
17 |
18 | 
19 | Biz kendi yapımıza gelecek olursak ilk olarak sayfa özelinde gidelim burada mobx tercih ettim. Sebepleri olumlu olumsuz yönleri elbette her şey gibi var ama hızlı ve çok fazla tekrar kod yazmadan observer yaklaşım ile bunu yapmak projelerim için gayet mantıklı.
20 |
21 | > Burada yine yapacağımız proje bazında düşünecek olursak daha fazla kontrollü ve zamanımız test yapmaya da müsait ise bloc pattern ile gidip bunları yönetmenin avantajı görülebilir ama ben bu şartlarda bunun gerçekci olamdığını düşündüğüm için hızlı ve performans için bloc seçiyorum.
22 |
23 | Haydi projemizde kullanmaya başlayalım:
24 |
25 | 1. [Mobx](https://pub.dev/packages/mobx) paketi , [build runner](https://pub.dev/packages/build_runner) paketi ve [flutter mobx ](https://pub.dev/packages/flutter_mobx) paketi pub.dev den indirilir.
26 | 2. VSCode için kullandığım extensionları indirip hem hızlı hemde anlık kod yazmayı sağlıyoruz.
27 | 1. [Mobx](https://marketplace.visualstudio.com/items?itemName=Flutterando.flutter-mobx) extensionu ile hem anlık build almasını hem de observer widgetlar sağlıyoruz.
28 |
29 | > Flutter ile mobx paketinin çalışma prensibi aslında yazılan mobx store sınıflarının build runner paketi aracalığıyla generator \_g.dart sınıflarının oluşması sonucunda oluyor.
30 |
31 | Login view Model sınıfımız incelersek yaptığımız mobx yazıp extension ile iligili kısımları kendisi yapıp bize sağlıyor.
32 |
33 | ```dart
34 | part 'login_view_model.g.dart';
35 |
36 | class LoginViewModel = _LoginViewModelBase with _$LoginViewModel;
37 |
38 | abstract class _LoginViewModelBase with Store, BaseViewModel {
39 | void setContext(BuildContext context) {
40 | this.context = context;
41 | }
42 |
43 | void init() {}
44 |
45 | @observable
46 | String name;
47 |
48 | @computed
49 | bool get nameIsValid => name.length > 5;
50 |
51 | @action
52 | void changeName(String name) {
53 | this.name = name;
54 | }
55 | }
56 | ```
57 |
58 | > Her işlemden sonra eğer mobx extensionu kullanıyorsanız dosyayı kayıt ettiğinizde kendisi g.dart sınıfını oluşturacaktır ya da bu komutu kullanarak yapabilirsiniz: `sh mobx.sh`
59 |
60 | mobx.sh
61 |
62 | ```sh
63 | if [ "$1" = "force" ]
64 | then
65 | flutter packages pub run build_runner build --delete-conflicting-outputs
66 | else
67 | flutter packages pub run build_runner build
68 | fi
69 |
70 | ```
71 |
72 | Ve işlem sonunda g.dart dosyanızda yapmış olduğunuz işlemlere göre kodlar üretiliyor olacak eğer dediğim gibi extension ile anlık dinlemiyorsanız **her defasında** bu işlemi yapmanız gerekiyor.
73 |
74 | Birkaç mobx özelinde bilinmesi gereken nokta mevcut gelin bunlara bakalım:
75 |
76 | - Observable: Sayfamızda değişecek değerlere verdiğimiz bir bağlamdır bu sayede kendisine gelen değerleri doğrudan alıp dinleyenlere haber verecektir.
77 | - Computed: Bu değişken tipi ise sayfada observer olan nesneleri dinleyip son halini bize döndüren durumdur yani hesaplanmış hali gibi düşünebilirsiniz.
78 | - Action: Bu kavram ise bize observer olarak tanımladığımız değişkenlerimizi değiştirip yenileme veya silme gibi durumları sağlar.
79 |
80 | Bu üç işlemin sonunda sayfamızda observer olarak işlenmiş olan bir widget doğrudan durumlara göre harekete geçip kendini günceller.
81 |
82 | ```dart
83 | Widget buildObserverIndcator() {
84 | return Observer(builder: (_) {
85 | return OnBoardIndcator(
86 | itemCount: viewModel.onBoarModel.length,
87 | currentIndex: viewModel.currentPageIndex,
88 | );
89 | });
90 | }
91 | ```
92 |
93 | [Buradaki](https://github.com/VB10/flutter-architecture-template/blob/master/lib/view/authenticate/onboard/view/on_board_view.dart) örnekte onboardViewModel deki değişikliğe göre anlık olarak kendini güncelleyen ve ekranda yerini bulan bir örnek görebilirsiniz.
94 |
95 | ---
96 |
97 | Peki sayfayı yönetmeyi anladık bu global state yönetimi konusuna değinelim. Projenizde bir kullanıcınızın baştan sona ilgilendiren ve her katmanda bir etkilenmesi olabilir. Yine aynı şekilde hep verilen örneklerden olan temanızın değişikliği gibi bir durumda olabilir. Bu tarz durumlarda global seviyede bir sınıf tanımlayarak ilgili değişiklikleri bir ana yerde sağlayıp diğer sınıflardan [context](https://api.flutter.dev/flutter/widgets/State/context.html?gclsrc=ds&gclsrc=ds) aracılığıyla yakalayıp değiştirme imkanı ediniyoruz.
98 |
99 | > Tabii ki bu aslında yazılımda çok alışık olduğumuz [Dependecy Injection](https://blog.gtiwari333.com/2011/05/understanding-dependency-injection-and.html) mantığı olarak düşünebilirsiniz bu sayede alt sınıflardan hem kendi sınıfını hem de üst sınıftaki objeyi değiştirip güncelleyip etkileyebiliyoruz.
100 |
101 | Projelerimizde genelde birden çok global durum olduğu için provider paketi içindeki multiProvider özelliğini kullanarak içerisine istediğimiz nesneleri vs atıyoruz.(Özellikle son zamanda gelen lazy özelliğini aktif ederek projede ihtiyacı olduğunda ayağa kalkmasını ve performans artışı sağlamış olursunuz.)
102 |
103 | ```dart
104 | MultiProvider(
105 | providers: [...ApplicationProvider.instance.dependItems],
106 | child: MyApp()}
107 | ```
108 |
109 | > Normalde direk ApplicationProvider sınıfındaki providers nesnesini de verebilirdim ama örnek olsun diye sadece birini bağladım. Burada [depedend item](https://www.filledstacks.com/post/flutter-provider-v3-architecture/) gibi mantıkla providerin türlerini bağlamayı hedefliyoruz ama ben genelde kendi projelerimde birkaç tanesi yeterli olduğu için çok detayına girmeden işi çözüyorum.
110 |
111 | Kendi ürünlerimden bir örnek verecek olursam bir kullanıcıyı global state içine atıp;
112 |
113 | ```dart
114 | List dependItems = [
115 | ChangeNotifierProvider(create: (context) => ThemeNotifier(), lazy: true),
116 | ChangeNotifierProvider(create: (context) => User(), lazy: true),
117 | ];
118 |
119 | ```
120 |
121 | Tema sınıfı bildiğimiz gibi ama farklı olarak user sınıfım ne yapıyor diye şöyle bakacak olsaydım;
122 |
123 | ```dart
124 | class User extends ChangeNotifier implements IUser {
125 | List productItems = [];
126 |
127 | double totalProductsMoney = 0;
128 |
129 | Product _getProduct(Product product) {
130 | return _products.keys.firstWhere((element) => element.urunGuid == product.urunGuid);
131 | }
132 |
133 | void addProduct(Product product) {
134 | _products[product] = 1;
135 | productsTotalMoney();
136 | notifyListeners();
137 | }
138 | }
139 | ```
140 |
141 | Bu oluşturmuş olduğum sınıfa artık projenin her yerinden ulaşabilir haldeyim. [ChangeNotifier](https://flutter.dev/docs/development/data-and-backend/state-mgmt/simple) yapmamın sebebi ise projede kullandığım her sepete eklenen ürünleri gösteren widget için (1,2,3 ve ürünlerin toplam fiyatları vb.). Kullanırken ise;
142 |
143 | ```dart
144 | context.read().addProduct(widget.product);
145 | //or
146 | Provider.of(context,listen:false).addProduct(widget.product);
147 | ```
148 |
149 | Şeklinde çok basitce o ürünü sepete ekleyip işlemimizi bitiryoruz. Ve kullanırken ise;
150 |
151 | ```dart
152 | Widget buildLocaleTextMinumumTotal(BuildContext context) {
153 | return context.watch().totalProductsMoney > AppConstants.MIN_VALUE
154 | ? context.emptySizedHeightBoxLow3x
155 | : LocaleText(
156 | text: LocaleKeys.basket_minumumTotal,
157 | textStyle:
158 | context.textTheme.subtitle1.copyWith(color: context.colorScheme.error, fontWeight: FontWeight.w300),
159 | );
160 | }
161 | ```
162 |
163 | Şeklinde kullanıp User içindeki değişiklikten anlık haberdar olup kendini güncellemesini sağlıyoruz.(Burada sepete eklenen ürünlerde belirli bir fiyat baremi bekleniyor tutar ise başarılı text tutmaz ise boş bir alan gözüküyor.)
164 |
165 | > context.watch Provider.of(context,listen:true) anlamına gelmektedir farkı ise false göre; anlık değişiklikleri dinler ve kendini günceller listen true widgetlerin kendini yenilemesi için kullandığımız kısım gibi düşünebilirsiniz.
166 |
167 | Ve state yönetimini tamamladık şimdi gelin derslerine bakalım👀
168 |
169 | Ve ana modelimiz de hazır daha fazlası için 🥳
170 |
171 | | Konular | Açıklama |
172 | | ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
173 | | State Management | [](https://www.youtube.com/watch?v=eP2xfFylc24&list=PL1k5oWAuBhgV_XnhMSyu2YLZMZNGuD0Cv&index=3) |
174 | | Provider | [](https://www.youtube.com/watch?v=jQ8JuX5RpNc&list=PL1k5oWAuBhgV_XnhMSyu2YLZMZNGuD0Cv&index=4) |
175 |
--------------------------------------------------------------------------------
/src/core/theme_change.md:
--------------------------------------------------------------------------------
1 | # Tema Değişikliği
2 |
3 | 
4 |
5 | Tema konusu flutter da çok önemli bir yer tutuyor. Özellikle flutter'in bize vermiş olduğu en büyük güçlerden olan tema karanlık(dark) ve aydınlık(light) özelliği bize ilk olarak verilmektedir.
6 |
7 | ```dart
8 | MaterialApp(theme: ThemeData.dark()) // ThemeData.light()
9 | ```
10 |
11 | Örneğini yukarıdaki şekilde görebilirsiniz. Bizim yapacağımız adımla bu tema değişimini proje çalışırken yapmayı sağlayacağız.
12 |
13 | > Flutter bizim için ilk halinde bir [tema](https://flutter.dev/docs/cookbook/design/themes) sunuyor projelerimizde elle değer vermek yerine bu temayı kullanarak adım atabiliriz.
14 |
15 | Bunu yapmak yerine;
16 | `Text("VB",style:TextStyle(fontsize:35))`
17 |
18 | [Bu ve benzeri](https://material.io/design/typography/the-type-system.html#type-scale) mantığı kullanmalısınız;
19 |
20 | `Text("VB",style:Theme.of(context).textTheme.headline5)`
21 |
22 | Bu yapıyı kullanmak çok önemli isterseniz [panache](https://rxlabz.github.io/panache/#/) kullanarak kendi temanızı oluşturabilirsiniz bu konuda [bu içeriğe de göz](https://www.youtube.com/watch?v=Eve_oMoH_WM) atabilirsiniz..
23 |
24 | Şimdi gelelim asıl işimize bu tema nasıl olacak ve proje boyunca değişecek işte o noktada flutter projelerinde en çok kullanılan [provider](https://pub.dev/packages/provider) paketinden yararlanacağız.
25 |
26 | > Provider konusu state yönetimi dersinde de işleyeceğim ama özetle bilmeniz gereken provider bizim için proje en üstünde saklamak veya anlık değişlikler yapmak istediğimiz noktalarda kolayca erişme imkanı sunan bir paket.
27 |
28 | Burada ana amacımız bir tema sınıfı oluşturup bunu provider objemiz ile tanımlamak ve artık geri kalanını ona bırakmak olacak.
29 |
30 | Bir ThemeNotifier sınıfı oluşturuyor ve bu sınıfı ChangeNotifier dan türeterek bu sınıfın objelerine dinleyenlere anlık değişimlerde kendilerini yenileme haberi veriyoruz.
31 |
32 | `class ThemeNotifier extends ChangeNotifier {}`
33 |
34 | Ardından ilgili sınıfımzda şuanki temamızı tutan bir değişken tanımlıyoruz.
35 |
36 | `ThemeData _currentTheme = AppThemeLight.instance.theme;`
37 |
38 | Son olarak yapmamız gereken bu sınıftan türeyenlere değişikleri haber verecek kısım da
39 |
40 | ```dart
41 | void changeValue(AppThemes theme) {
42 | if (theme == AppThemes.LIGHT) {
43 | _currentTheme = ThemeData.light();
44 | } else {
45 | _currentTheme = ThemeData.dark();
46 | }
47 | notifyListeners();
48 | }
49 | ```
50 |
51 | > Bu kısımda ben cache yapımı da dahil edip değişiklikleri telefon hafızasında tutuyorum.İlk açıldığı anda değeri oradan tanımlayıp bu sayede son değişiklikle tekrar çalıştırmış oluyorum.
52 |
53 | Tema değişikliği özelliğimiz hazır yapmamız gereken bu değeri provider kısmında tanımlamak.
54 |
55 | ```dart
56 | List dependItems = [
57 | ChangeNotifierProvider(
58 | create: (context) => ThemeNotifier(),
59 | )
60 | ];
61 | ```
62 |
63 | İlgili provider obje sınıfını da main.dart dosyamızda çağırdıktan sonrasında projemizin herhangi bir yerinde bu objeye erişip temayı değiştirebiliriz.
64 |
65 | `MultiProvider( providers: [...ApplicationProvider.instance.dependItems],`
66 |
67 | Artık MaterialApp altındakı temayı şu şekilde tanımlıyoruz;
68 | `theme: Provider.of(context, listen: false).currentTheme,`
69 |
70 | Örnek kullanım ise;
71 | `Provider.of(context).changeValue(AppThemes.dark)`
72 |
73 | Diğer detaylara buradan erişebilirsiniz🥳
74 |
75 | [](https://www.youtube.com/watch?v=jQ8JuX5RpNc&list=PL1k5oWAuBhgV_XnhMSyu2YLZMZNGuD0Cv&index=4)
76 |
--------------------------------------------------------------------------------
/src/publish/android_publish.md:
--------------------------------------------------------------------------------
1 | # Android Uygulama Paket, Market Yönetimi ve Fastlane
2 |
3 | 
4 |
5 | Artık uygulamamızın mimarisini yazıp, başlayıp, bitirdik ve marketlerde görmek istiyoruz.Burada Android tarafı için yapmamız gereken süreçler ve bu süreçler sonunda Google Play Store tarafında görmüş olacağız.
6 |
7 | Peki Süreçler:
8 |
9 | - Test Süreci:
10 | - En sağlam ve güvenilir olarak [Google Play Console](https://play.google.com/console/u/0/signup) üzerinden bu işleri yönetiyoruz.
11 | - [Firebase App Distiribution](https://firebase.google.com/docs/app-distribution/android/set-up-for-testing) ise hızlı ve hiç beklemeden müşterilere sunmak için iyi ve yeni bir çözüm.
12 | - Canlı Yayın Süreci:
13 | - Artık test yaptık, ilgili [app bundle](https://developer.android.com/platform/technology/app-bundle) dosyamız hazır ve bu dosyayı ilgili store adımlarını tamamlayarak markete yüklüyoruz.
14 | - Geri Bildirim
15 | - Uygulama ilgili markete çıktıktan sonrasında gelen yorumları okuyup store üzerinden cevap vererek uygulamamızı daha popüler hale getiriyoruz.
16 |
17 | Biz bu mimari serisinde fastlane üzerinden daha çok gittik ama ilk sıfırdan nasıl bu süreçler olur merak edenler [**bu içerikten**](https://www.youtube.com/watch?v=RiuyVxte5vw) videoyu izleyip öğrenebilir.
18 |
19 | > Google Play son süreçlerde artık daha fazla dikkat ederek paketleri kontrol edip çıkmaya çalışıyor. Test için attığınız ilk paketin birkaç gün sonra görmeniz mümkün olabilir.
20 |
21 | > Canlı yayına geçerken ekran görüntüleri dahil olmak üzere her şeye takıyorlar.Ben genelde [buradan](https://www.appstorescreenshot.com/) yapıyorum siz de seçebilirsiniz.
22 |
23 | > Uygulamanızı çıkarken muhakkak önce internal test açıp ardından beta ve en son canlıya şeklinde gitmeyi unutmayın.
24 |
25 | Paketi çıkma işleminde ya manuel yöntemler videoda anlattığım gibi ya da şimdi anlatacağım fastlane gibi otomasyonlar ile doğrudan paketinizi canlıya çıkabilirsiniz.Bunun dışında paketinizi release modda çıkmış olmanız önemlidir.
26 |
27 | ## Fastlane
28 |
29 | Fastlane bizim için ara tüm işlemleri yapan kocaman bir app distribution uygulamasıdır.İçinde envayi çeşit yöntem ile paketimizi tek tuşla çıkma imkanı sunar.
30 |
31 | Bu paketlerden bazıları:
32 |
33 | - [Google Play Track Number](http://docs.fastlane.tools/actions/google_play_track_version_codes/#google_play_track_version_codes)
34 | - [Git push](http://docs.fastlane.tools/actions/push_git_tags/#push_git_tags)
35 | - [Slack Message](http://docs.fastlane.tools/actions/slack/#slack)
36 | - [Screen Shoot Upload](http://docs.fastlane.tools/getting-started/android/screenshots/#upload-screenshots-to-google-play)
37 |
38 | Buradaki amacımız bir hat kurarak işlemleri yapmasını sağlayıp markete doğrudan hiç uğraşmadan paket çıkmaktır.
39 |
40 | Örnek olarak bakacak olursak.
41 |
42 | ```sh
43 | desc "Deploy to internal test application"
44 | lane :internal do |options|
45 | versionNumberArrayLength = google_play_track_version_codes(track:INTERNAL)
46 | versionNumber = (versionNumberArrayLength.length > 0 ? versionNumberArrayLength[0] : 0).to_i + 1
47 | incerementVersion version: options[:version]
48 | setVersionNumber versionNumber: options[:versionNumber]
49 | versionName = getVersionName()
50 | flutter_build(versionName,versionNumber)
51 | buildStore(INTERNAL)
52 | end
53 | ```
54 |
55 | Bakın burada marketten ilgili son paketin numarasını alıp bir artırıp bununla paket çıkıp doğrudan test flight'a atıyor.Yorum satırı eğer yapsaydık doğrudan slack kanalınıza linki atıp teste hazırım diyebilirdi.
56 |
57 | Burdan sonrasında fastlane size verdiği nimetleri kullanarak kendi kurallarınıza göre yapacaksınız.
58 |
59 | > Eğer burada if else gibi bir yapı kurup kod yazmak isterseniz ruby diline bakıp burada kullanabilirsiniz.
60 |
61 | ```ruby
62 | private_lane :setVersionNumber do |options|
63 | if options[:versionNumber] != nil
64 | set_properties_value(
65 | key: ANDROID_VERSION_NAME,
66 | path: ENV_PATH,
67 | value: options[:versionNumber]
68 | )
69 | end
70 | end
71 | ```
72 |
73 | Buradaki gibi misal kendi kullandığım bir projede hazırlayıp kullanıcı farklı bir şey girerse standart olarak minoru alıyordum.Bu projede paket çıkmak için yaptığım tek adım ise şu şekilde:
74 |
75 | `cd android fastlane release env:patch(minor||major)`
76 |
77 | ---
78 |
79 | Ve ana modelimiz de hazır daha fazlası için 🥳
80 |
81 | [](https://www.youtube.com/watch?v=RiuyVxte5vw)
82 |
83 | [](https://www.youtube.com/watch?v=poog2mJ4Tko&list=PL1k5oWAuBhgV_XnhMSyu2YLZMZNGuD0Cv&index=13)
84 |
--------------------------------------------------------------------------------
/src/publish/ios_publish.md:
--------------------------------------------------------------------------------
1 | # IOS Uygulama Paket, Market Yönetimi ve Fastlane
2 |
3 | 
4 |
5 | Artık uygulamamızın mimarisini yazıp başlayıp bitirdik ve marketlerde görmek istiyoruz.Burada IOS tarafı için yapmamız gereken süreçler ve bu süreçler sonunda App Store tarafında görmüş olacağız.
6 |
7 | Peki Süreçler:
8 |
9 | - Test Süreci:
10 | - En sağlam ve güvenilir olarak [TestFlight](https://developer.apple.com/testflight/) üzerinden bu işleri yönetiyoruz.
11 | - [Firebase App Distiribution](https://firebase.google.com/docs/app-distribution/ios/set-up-for-testing) ise hızlı ve hiç beklemeden müşterilere sunmak için iyi ve yeni bir çözüm.
12 | - Canlı Yayın Süreci:
13 | - Artık test yaptık, ilgili [ipa](https://en.wikipedia.org/wiki/.ipa) dosyamız hazır ve bu dosyayı ilgili store adımlarını tamamlayarak markete yüklüyoruz.
14 | - Geri Bildirim
15 | - Uygulama ilgili markete çıktıktan sonrasında gelen yorumları okuyup store üzerinden cevap vererek uygulamamızı daha popüler hale getiriyoruz.
16 |
17 | Biz bu mimari serisinde fastlane üzerinden daha çok gittik ama ilk sıfırdan nasıl bu süreçler olur merak edenler [**bu içerikten**](https://www.youtube.com/watch?v=fACGunnRbzA) videoyu izleyip öğrenebilir.
18 |
19 | > Testflight üzerinde test açmanın internal testerler için doğrudan external testerler için her defasında bir review süreci olmaktadır.
20 | >
21 | > > Bu süreci aşmak için yöntem şudur: 1.0.1 diye versiyon çıkılır bir kereye mahsus review sürecine girer ardından o versiyonla ilgili her geliştirme versiyon numarası aynı kalmak şartıyla build number değiştirilerek atılır ve doğrudan güncellenmiş olur.
22 |
23 | > Canlı yayına geçerken ekran görüntüleri dahil olmak üzere her şeye takıyorlar.Ben genelde [buradan](https://www.appstorescreenshot.com/) yapıyorum siz de seçebilirsiniz.
24 |
25 | > Eğer uygulamanız herkesin girebileceği bir app değilse test bunu muhakkak belirtip test kullanıcısı vermeyi unutmayın.
26 |
27 | > Test kullanıcı verirken adı ve şifreyi doğru vermeyi unutmayın.Ben yanlışlıkla başına boşluk koyup vermiştim, backendde trim olmadan bakıldığı için veya mobilde yapmadığım için app kullanıcı şifre yanlış diye reject yemişliğim var.
28 |
29 | Paketi çıkma işleminde ya manuel yöntemler videoda anlattığım gibi ya da şimdi anlatacağım fastlane gibi otomasyonlar ile doğrudan paketinizi canlıya çıkabilirsiniz.Bunun dışında paketinizi release modda çıkmış olmanız önemlidir.
30 |
31 | ## Fastlane
32 |
33 | Fastlane bizim için ara tüm işlemleri yapan kocaman bir app distribution uygulamasıdır.İçinde envayi çeşit yöntem ile paketimizi tek tuşla çıkma imkanı sunar.
34 |
35 | Bu paketlerden bazıları:
36 |
37 | - [Store Build Number](https://docs.fastlane.tools/actions/app_store_build_number/)
38 | - [Git push](http://docs.fastlane.tools/actions/push_git_tags/#push_git_tags)
39 | - [Slack Message](http://docs.fastlane.tools/actions/slack/#slack)
40 | - [Version Number](http://docs.fastlane.tools/actions/ensure_xcode_version/#ensure_xcode_version)
41 |
42 | Buradaki amacımız bir hat kurarak işlemleri yapmasını sağlayıp markete doğrudan hiç uğraşmadan paket çıkmaktır.
43 |
44 | Örnek olarak bakacak olursak.
45 |
46 | ```sh
47 | desc "Push a new artifact build internal"
48 | lane :internal do |options|
49 | buildNumber = latest_testflight_build_number
50 | incrementBuildNumber(buildNumber)
51 | increment_version_number( bump_type: options[:versionType] )
52 | build_ios_app
53 | upload_to_testflight
54 | # sendMessageSlack()
55 |
56 | end
57 | ```
58 |
59 | Bakın burada marketten ilgili son paketin numarasını alıp bir artırıp bununla paket çıkıp doğrudan test flighta atıyor.Yorum satırı eğer yapsaydık doğrudan slack kanalınıza linki atıp teste hazırım diyebilirdi.
60 |
61 | Burdan sonrasında fastlane size verdiği nimetleri kullanarak kendi kurallarınıza göre yapacaksınız.
62 |
63 | > Eğer burada if else gibi bir yapı kurup kod yazmak isterseniz ruby diline bakıp burada kullanabilirsiniz.
64 |
65 | ```ruby
66 | def semanticValue(variable)
67 | if variable == "major" || variable == "minor" || variable=="patch"
68 | return variable
69 | else
70 | print(variable+" can not right paramater.")
71 | return "minor"
72 | end
73 | end
74 | ```
75 |
76 | Buradaki gibi misal kendi kullandığım bir projede hazırlayıp kullanıcı farklı bir şey girerse standart olarak minoru alıyordum.Bu projede paket çıkmak için yaptığım tek adım ise şu şekilde:
77 |
78 | `cd ios fastlane internal version:patch(minor||major)`
79 |
80 | ---
81 |
82 | Ve ana modelimiz de hazır daha fazlası için 🥳
83 |
84 | [](https://www.youtube.com/watch?v=fACGunnRbzA)
85 |
86 | [](https://www.youtube.com/watch?v=6RK45v7M1wQ&list=PL1k5oWAuBhgV_XnhMSyu2YLZMZNGuD0Cv&index=14)
87 |
--------------------------------------------------------------------------------
/src/screens/features.md:
--------------------------------------------------------------------------------
1 | # Geliştirmeler(Features)
2 |
3 | 
4 |
5 | Projelerimizde iki adımlı geliştirmeler genelde oluyor.Bir tarafta ana kısımlarımız diğer tarafa ise bu ana kısımlarımızdan beslenen ekranlarımız ve geliştirmelerimiz bulunuyor. Bu gelişmeler neler olabilir diye düşünecek olursak;
6 |
7 | - Doğrulama
8 | - Giriş
9 | - Kayıt Olma
10 | - Şifremi Unuttum
11 | - İki Adımlı Doğrulama
12 | - Ana Ekranlar
13 | - Ürünler
14 | - Haritalar
15 | - Kategoriler
16 | - Ayarlar
17 | - Şifre Güncelleme
18 | - Kullanıcı Güncelleme
19 | - Proje Ekranları
20 | - Sıkça Sorulan Sorular
21 | - Lisans Sözleşmesi
22 | - Gizlilik Sözleşmesi
23 | - Uygulama Ekranları
24 | - Tema Değiştirme
25 | - Dil Değiştirme
26 |
27 | Gibi hemen hemen bir uygulamanın tüm modülleri buradaki şekilde gelişmektedir. Bu gelişmeyi yaparken buradan herhangi birisi için şu şekilde ilerliyoruz: `Features/Authentication/Login`. Bu şekilde tanımlama yaptıktan sonrasında artık ekranlarımız belirli bir yapıda gitmiş olacağız.
28 |
29 | 
30 |
31 | 
32 |
33 | > Buradaki amacımız geliştirmeleri gruplayıp yeni geleceklerin yerini net olarak belirlemek olacak.
34 |
35 | Buradaki klasör yapısında tabiki hemen akla gelen ortak modeller ne olacak bunları da yine features klasörümüzün altında yer alıyor.
36 |
37 | - \_component
38 | - Burada atomic widgetlarımızın iş kuralları olan halleri bulunuyor.(FaceBookButton var diyelim bunun VeliButton olan hali facebook logini yapıp servise istek atıyor gibi.)
39 | - \_model
40 | - Burada kullanıcı gibi ürünler gibi ortak kullanılan modellerimi konumlandırıyorum.
41 | - \_service
42 | - Burada ise ortak servislerimi konumlandırıp çağırmam gerektiğinde buradan kullanmış oluyorum.
43 |
44 | 
45 |
46 | Misal bir **\_compenent** klasörümüz içerisinde şunları içerebilir.
47 |
48 | 
49 |
--------------------------------------------------------------------------------
/src/screens/mvvm_struct.md:
--------------------------------------------------------------------------------
1 | # MVVM Yapısı
2 |
3 | 
4 |
5 | MVVM gibi yaklaşımların temel amacı aslında test yazmayı veya parçalamayı artırmaktır. Birçok yapı mevcut olup basitten karmaşığa doğru şöyle kabaca sıralamak istersek;
6 |
7 | [MVC](https://www.tutorialsteacher.com/mvc/mvc-architecture#:~:text=MVC%20stands%20for%20Model%2C%20View,data%20retrieved%20from%20the%20database.) -> [MVVM](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93viewmodel) -> [Clean Architecture(Viper)](https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html)
8 |
9 | Şimdi burada bu bundan iyi demek çok doğru bir yaklaşım değildir.Test yazdığımız sürece zaten bizi ilgili mimari kendisine çekecektir.Bu proje için MVVM yapısını ele alıp oldukça basit ama etkili kullanmayı işleyeceğim.
10 |
11 | ## View
12 |
13 | İçerisinde ana ekran modüllerimizin olduğu ve ekran çizimlerimizi yaptığımız ana kısım olarak görebilirsiniz. Burada diğer atomlarımız ile birleştirip işlediğimiz bir noktadır. Burada kurguladığım bir baseView yapısı ile herhangi bir ekran yapılırken muhakkak bir viewModel tanımlayarak sayfanın buradan türemesini ve tüm sayfaların ortak bir katmanda toplanmasını sağlıyorum.
14 |
15 | > Bu ne işe yarayacak diyebilirsiniz. Misal bir gün projemde internet olmadığında her sayfamda offline mod olması veya pop-up çıkması gibi bir seneryo olmuştu. Bunu doğrudan tüm ekranlarıma değilde bu katmanımda yapıp değişikliğe göre sayfayı durdurup bu hata mesajını çıkarmıştım.
16 |
17 | ```dart
18 | @override
19 | Widget build(BuildContext context) {
20 | return BaseView(
21 | viewModel: LoginViewModel(),
22 | onModelReady: (model) {
23 | model.setContext(context);
24 | model.init();
25 | viewModel = model;
26 | },
27 | onPageBuilder: (BuildContext context, LoginViewModel value) => buildScaffold(context),
28 | );
29 | }
30 | ```
31 |
32 | [Login sayfamızı](https://github.com/VB10/flutter-architecture-template/blob/master/lib/view/authenticate/login/view/login_view.dart) inceleyecek olursak bir ekran çizimi için her şey orada iskelet olarak mevcut. Önceki yazılarda ele aldığım mobx ile birlikte tüm değişimler için observer bir yapı kurup hayata devam ediyorum.
33 |
34 | ## ViewModel
35 |
36 | Projemizin iş yapan kısmına geldik.Özelikle temiz kod ve iş kurallarımızı tanımlamamız açısından en önemli kısım burasıdır.Burada vscode üzerindeki [mobx extensionu ](https://marketplace.visualstudio.com/items?itemName=Flutterando.flutter-mobx)ile view modelimizi oluşturup önceki yazılarda ki gibi içeriğini oluşturuyoruz.
37 |
38 | ```dart
39 | part 'login_view_model.g.dart';
40 |
41 | class LoginViewModel = _LoginViewModelBase with _$LoginViewModel;
42 |
43 | abstract class _LoginViewModelBase with Store, BaseViewModel {
44 | void setContext(BuildContext context) {
45 | this.context = context;
46 | }
47 |
48 | void init() {}
49 |
50 | @observable
51 | String name;
52 |
53 | @action
54 | void changeName(String name) {
55 | this.name = name;
56 | }
57 | }
58 | ```
59 |
60 | Burada artık tüm iş yükünü tanımlayıp hayatımıza başlıyoruz.
61 |
62 | ## Model
63 |
64 | Ekranlarımız için gereken sınıflarımızın olduğu ana noktadır.Burada [json serilization](https://pub.dev/packages/json_serializable) kütüphanesi ile ilgili metodlarımızı üretiyor ve devamında network katmanımızın gerekliliğine uymak için adımlarımızı yapıyoruz.
65 |
66 | ```dart
67 | @JsonSerializable()
68 | class TestModel extends BaseModel {
69 | int userId;
70 | int id;
71 | String title;
72 | bool completed;
73 |
74 | TestModel({this.userId, this.id, this.title, this.completed});
75 |
76 | Map toJson() {
77 | return _$TestModelToJson(this);
78 | }
79 |
80 | @override
81 | TestModel fromJson(Map json) {
82 | return _$TestModelFromJson(json);
83 | }
84 | }
85 | ```
86 |
87 | Json paketi google'in parse paketi olup çok fazla güzel özellikleri barındırıyor. Misal işte tüm sınıfı pascal case parçalamak için (yani servisiniz cevabı {"NAME":"Veli"} gibi dönüyor ise illaki size Name yazmak zorunda olmadan [annotation](https://pub.dev/packages/json_serializable#annotation-values) ile yapabilirsiniz.). Buradaki önemli olan BaseModel ile de bu modellerimizin network katmanımıza uygun olmaını sağıyoruz.
88 |
89 | > Json Serializable paketi aynı mobx gibi bir g.dart dosyası üretiyor.Bu işlem için ya mobx yazısındaki gibi build scriptini çalıştıracağız veya mobx extensionu eğer açık ise alt kısımda her kayıt aldığınızda kendisi otamatik üretecektir.
90 |
91 | ## Service
92 |
93 | Genelde projelerimde servis kısımlarımı da ayırma ve ara işlemleri burada yapmayı doğru buluyorum.Gerek test etmek açısından gerek servis kısımlarının ekran ile bağımlılığını azaltmak için kullanıyorum diyebilirim.
94 |
95 | Servis kısmımı hem bağımlılıkları hemde test için ilk olarak bir arayüz sınıfı yaparak bağımlıklarını hazırlıyorum.
96 |
97 | ```dart
98 | abstract class ISplashService {
99 | Future fetchSocialData();
100 | }
101 | ```
102 |
103 | Ardından ilgili servis sınıfımı tanımlayıp içerisine ağ değişkenini alıp tamamlayıp ekrana geri döndürüyorum.
104 |
105 | ```dart
106 | class SplashService extends ISplashService {
107 | final INetworkManager _manager;
108 | SplashService(this._manager);
109 |
110 | @override
111 | Future fetchSocialData() async {
112 | final response = await _manager.fetch(RoutePath.ADRESS_SOCIAL.rawValue,
113 | parseModel: Social(), method: RequestType.GET);
114 |
115 | return response.data;
116 | }
117 | }
118 | ```
119 |
120 | > Hem videolardan hem de gelecek olan api ve ekran bağlama derslerimde bu kısımları çok daha iyi anlayacaksınız.
121 |
122 | ---
123 |
124 | Ve ana modelimiz de hazır daha fazlası için 🥳
125 |
126 | [](https://www.youtube.com/watch?v=OxdgMVg6yl0&t=604s)
127 |
128 | [](https://www.youtube.com/watch?v=LSiHLLMBkjQ&list=PL1k5oWAuBhgV_XnhMSyu2YLZMZNGuD0Cv&index=12)
129 |
--------------------------------------------------------------------------------
/src/screens/theme_generate.md:
--------------------------------------------------------------------------------
1 | # Tema Yönetimi
2 |
3 | 
4 |
5 | Projelerde çok değerli bir kısıma geldik.Özellikle bu kısım projelerin renk, stil gibi özelliklerini belirlediğimiz kısım olacak.
6 |
7 | Birçok projede gördüğüm her widget için ayrı bir style yapılıyor.Örneğin;
8 |
9 | ```dart
10 | Text("Veli",style:TextStyle(fonSize:35))
11 |
12 | FloatingActionButton(color:Colors.red)
13 | ```
14 |
15 | Bu şekilde bir yaklaşım anlık iyi gibi gözükmüş olsa da özellikle proje geliştikçe size hantallık ve ne neredeydi gibi sorularla karşılaşmanıza yol açacaktır.**Flutter** sizin için ilk anında aslında [bir tema ](https://flutter.dev/docs/cookbook/design/themes)veriyor.Bu özelliği ile aslında hiçbir işlem yapmadan size vermiş olduğu bu temayı kullanarak kodlarınızı mimarisel yazmış olabilirsiniz.
16 |
17 | 
18 |
19 | Örnek olarak incelersek;
20 |
21 | ```dart
22 | Text("Veli",style:Theme.of(context).textTheme.headline5)
23 |
24 | FloatingActionButton(color:Theme.of(context).primaryColor)
25 | ```
26 |
27 | Buradaki mantık ya bize Flutter'in vermiş olduğu tema dosyasını kullanmak ya da kendi tema dosyalarımızı oluşturmak ve bu oluşturma kapsamında projelerimizin renk paletlerini buradan belirlemek.
28 |
29 | > Projeleri düşündüğümüzde çok fazla renk görmeyiz.Genelde belirli renkler üzerinden ve fontlardan giderek olur. Ondan dolayı burada ana bir tema dosyası yapıp bundan sonra gelenleri buradan türeterek yapmak çok mantıklı olacaktır.
30 |
31 | Peki nasıl kendi projelerimizi tema dosyamız ile yönetebiliriz:
32 |
33 | - [Panache](https://rxlabz.github.io/panache/#/)(Tema kodu üreten bir site ilk giriş için mantıklı) 🛑
34 | - Custom Theme (Kendi tema sınıfızı oluşturmak) ✅
35 | - Her yerde tek tek tanımlamak (Bunu ele dahil alamıyorum oldukça zayıf ve kod gelişimine engel olan bir yöntem.) ❌
36 |
37 | ## Panache İle Başlamak
38 |
39 | [Panache](https://rxlabz.github.io/panache/#/) bize belirli bir palette kod tema dosyası üretip doğrudan projeye vererek kullanma imkanı sunuyor. Bu üretilen kodu doğrudan kopyalayıp projemize atarak kullanabilirsiniz.Burada istediğimiz rengi seçerek misal yeşil renk ana olarak olduğu tema oluşturuyoruz.
40 |
41 | 
42 |
43 | Örnek olarak üretilen koda bakacak olursak elimizde bu şekilde oluşacak.Kodu projemize attıktan sonra theme kısmına myTheme değerimizi verip projemizde rahatlıkla kullanabiliriz.
44 |
45 | ```dart
46 | final ThemeData myTheme = ThemeData(
47 | primarySwatch: Colors.blue,
48 | brightness: Brightness.light,
49 | primaryColor: Color( 0xff2196f3 ),
50 | primaryColorBrightness: Brightness.dark,
51 | primaryColorLight: Color( 0xffbbdefb ),
52 | primaryColorDark: Color( 0xff1976d2 ),
53 | accentColor: Color( 0xff2196f3 ),
54 | accentColorBrightness: Brightness.dark,
55 | canvasColor: Color( 0xfffafafa ),
56 | );
57 |
58 | class MyApp extends StatelessWidget {
59 | @override
60 | Widget build(BuildContext context) {
61 | return MaterialApp(
62 | title: 'Flutter Demo',
63 | debugShowCheckedModeBanner: false,
64 | theme: myTheme,
65 | home: Column(children:[
66 | Container(color:Theme.of(context).primaryColorDark)
67 | ]),
68 | );
69 | }
70 | }
71 | ```
72 |
73 | Örnekteki kullanımla artık doğrudan myTheme içinden değerlerle widgetlerimizi tasarlayıp geliştirebiliyoruz.Buradan sonrasında diğer kodlarıda inceleyerek istersek kendimize göre tanımlayıp renkleri olsun değerleri olsun bitirip geliştirmiş olacağız.
74 |
75 | >Panache sitesinde dikkat etmeniz gereken 3-4 defa bir yere dokunduğunuzda sayfa donuyor ondan dolayı elinizi hızlı tutup seçip kodu oluşturup projenizde kullanabilirsiniz.
76 |
77 | > Siteden üretilen kodlarda eski yapılar var headline gibi zaten eklediğinizde hataları göreceksiniz.Ben bunları düzelttiğim örneği buradan erişip kullanabilirsiniz.
78 | > Siteden üretilen kodlarda çok fazla satır olması tabii ki karmaşa yol açabiliyor bir de dark olanı geçtiğiniz zaman daha çok zorlaştırıyor.Ben ilk yaptığımda kullandıklarımın yanına comment ile x atarak dark veya başka tema için sadece o, x olanları değişterek yapıyordum.
79 |
80 | ```dart
81 | myTheme = ThemeData(
82 | primarySwatch: Colors.blue,
83 | brightness: Brightness.light,//xx
84 | primaryColor: Color( 0xff2196f3 ))
85 |
86 | myThemeBlack = ThemeData(
87 | primarySwatch: Colors.blue,
88 | brightness: Brightness.dark,//xx
89 | primaryColor: Color( 0xff2196f3 ))
90 | ```
91 |
92 | ## Kendi Tema (Custom Theme)
93 |
94 | En güzeli ve [en sevdiğim yöntemdir](https://github.com/VB10/flutter-architecture-template/blob/master/lib/core/init/theme/app_theme_light.dart).Bu sayede hem gereksiz kod tekrarından uzaklaşıyoruz hemde sadece bizim belirlediğimiz yapılar olacağı için rahatlıkla kullanmış olacağız.Aslında aynı mantıkla ilerliyor tek farkı kendi sınıfımızı yapılır.
95 |
96 | ```dart
97 | // ThemeData get theme => redTheme;
98 | ThemeData get theme => ThemeData(
99 | fontFamily: ApplicationConstants.FONT_FAMILY,
100 | colorScheme: _appColorScheme(),
101 | textTheme: textTheme(),
102 | floatingActionButtonTheme: ThemeData.light().floatingActionButtonTheme.copyWith(),
103 | tabBarTheme: tabBarTheme(),
104 | );
105 |
106 | TabBarTheme tabBarTheme() {
107 | return TabBarTheme(
108 | labelPadding: insets.lowPaddingAll,
109 | unselectedLabelStyle: textThemeLight.headline4.copyWith(color: colorSchemeLight.red),
110 | );
111 | }
112 |
113 | TextTheme textTheme() {
114 | return TextTheme(
115 | headline1: textThemeLight.headline1, headline2: textThemeLight.headline2, overline: textThemeLight.headline3);
116 | }
117 | ```
118 |
119 | Bunuda bir lazy singleton yapımızı kullanarak tek bir değer üretiyoruz.
120 |
121 | ```dart
122 | class AppThemeLight extends AppTheme with ILightTheme {
123 | static AppThemeLight _instance;
124 | static AppThemeLight get instance {
125 | if (_instance == null) _instance = AppThemeLight._init();
126 | return _instance;
127 | }
128 | ```
129 |
130 | Ardından projemizin main.dart dosyasında bu değeri verip kullanmaya başlıyoruz.
131 |
132 | ```dart
133 | class MyApp extends StatelessWidget {
134 | @override
135 | Widget build(BuildContext context) {
136 | return MaterialApp(
137 | title: 'Flutter Demo',
138 | debugShowCheckedModeBanner: false,
139 | theme: AppThemeLight.instance.theme,
140 | home: Column(children:[
141 | Text("Veli",style:Theme.of(context).headline1),
142 | Container(color:Theme.of(context).colorScheme.onError),
143 | ]),
144 | );
145 | }
146 | }
147 | ```
148 |
149 | Şeklinde tanımlamış ve bundan sonraki değerleri buradan yönetmiş oluyoruz.Amacımız AppThemeLight dosyasında light tema uygun değerleri doldurup projemizi bitirimiş olacağız.
150 |
151 | > Diyelim ki bir text widgete renk vermek istiyorsunuz. Text("Veli",style:Theme.of(context).headline1.copyWith(color:Theme.of(context).primaryColor)) diyerek o texte bu şekilde tüm renkleri veya yapıları vermiş oluyoruz.
152 |
153 | ---
154 |
155 | Ve ana modelimiz de hazır daha fazlası için 🥳
156 | [](https://www.youtube.com/watch?v=8JD7ZTtZDUU&list=PL1k5oWAuBhgV_XnhMSyu2YLZMZNGuD0Cv&index=10)
157 |
--------------------------------------------------------------------------------
/src/screens/unit-test.md:
--------------------------------------------------------------------------------
1 | # Birim Testi (Unit Test)
2 |
3 | 
4 |
5 | Birim testi yani unit test konusu oldukça değerli ve bir yazılımın kalitesi için olmazsa olmaz bir konudur.Mobil kısımda aslında çok büyük unit testler yazılmıyor ve genelde gördüğüm kadarıyla yazılım disiplini fark etmeden her zaman testlerimizi yazabiliriz.
6 |
7 | Bir mobil uygulamanın kalitesini ne kadar az cihaz üzerinde sabit kod (client static code) yazılırsa o kadar iyi olduğu anlamına gelir.Yani bağımlılık tam olarak servis katmanınıza bağımlı olup değişikliklere göre buradan yönetilirse uygulama oldukça o kadar yönetilebilir olur.
8 |
9 | > Burada cliente(yani doğrudan statik kod) kod yazmamaktan kastım iş kuralları olan kodların backendde yönetilmesi gerekiyor yani misal çok basitce bir dolar kuruna göre hesaplama yapıyorsanız bunu gidip dolar=10 alıp yapmak doların artışı azalışına göre her defasında kod yazmanız gerektiğine çıkacaktır.
10 |
11 | Şimdi biz mobil uygulamalarda şu durumlarla karşılaşıyoruz:
12 |
13 | - Servis Testleri
14 | - Bu testler normalde ekiplerde test developer arkadaşlar tarafından yapılıyor ama yine de ben uygulamamda apiden gelen cevapları direk ekranda değil testlerde görüp ilgili senaryolarımı modellerimi oluşturuyorum.
15 | - Birim Testleri
16 | - App içerisindeki tüm iş yükü olabilecek örneğin bir bilgiyi saklayıp sonra var olması kontrolü veya işte gelen değere göre sayfada bir değerin gözükmesi gibi senaryoların var olduğu.
17 | - Ekran Testleri
18 | - Bu testler ui test olarak geçmekte ve projeyi yazan değil proje dışı ekiplerin genelde yaptığı işte buraya dokunduğunuzda bu olur gibi senaryoları ele alındığı durumdur.([Selenium](https://www.selenium.dev/) ve [PlayWright](https://github.com/microsoft/playwright) çok başarılı frameworkler muhakkak bir bakın.)
19 |
20 | > Burada bizi özellikle ilk iki kısım oldukça fazla ilgilendiriyor üçüncü kısım genelde en son olarak yapılan test olarak düşünebiliriz.
21 |
22 | ## Servis Testleri
23 |
24 | > Bu kısımda swagger kullanıyorsanız eğer[ swagger-code-gen çok](https://swagger.io/tools/swagger-codegen/) işinize yarayabilir.
25 |
26 | Bir mobil uygulama geliştirirken bize backend(yazılımların iş yapan ve ortaklaştıran birimi) yazan arkadaşlar tarafından bize verilen [swagger](https://swagger.io/) veya [postman collection ](https://www.postman.com/)incelenerek bunu kendi uygulamamıza dahil etmemiz gerekiyor.
27 |
28 | > Özellikle bu ikisinden birisi olması çok önemli döküman veya mesaj ile bir servis nasıl kullanılır diye almak çok yoracaktır muhakkak talep edin arkadaşlarınızdan.
29 |
30 | Diyelim ki onboard sayfamızda bir servisten bilgi çekeceğiz bunu yapmak için şu şekilde bir tanımlama yapmış olalım:
31 |
32 | ```dart
33 | Future onBoardGetModels() async {
34 | final response =
35 | await coreDio.fetch, PostModel>("/posts", type: HttpTypes.GET, parseModel: PostModel());
36 |
37 | if (response.data is List) {
38 | onBoarModel = response.data.map((e) => OnBoardModel(stringHelper.toUpper(e.title))).toList().cast();
39 | }
40 | }
41 | ```
42 |
43 | Bu metod [servisimizden](https://jsonplaceholder.typicode.com/) cevabı çekip ekranda gösterecek diyelim. Bunu denemek için gidip ekrana bir buton koyup çağırmıyoruz, doğrudan [test sınıfını](https://github.com/VB10/flutter-architecture-template/blob/master/test/feature/onboard/onboard_test.dart) yazıp çok hızlıca çalışıtırıp değerimizi kontrol ediyoruz.
44 |
45 | ```dart
46 | test("OnBoard Get Models", () async {
47 | await mockViewModel.onBoardGetModels();
48 | expect(mockViewModel.onBoarModel, isNotEmpty);
49 | });
50 |
51 | ```
52 |
53 | > Burada dikkat etmeniz gereken test sınıflarını yazarken isim_test.dart şeklinde olması gerektiğidir.
54 |
55 | ## Birim Testleri
56 |
57 | Birim testleri için tabii ki çok daha geniş örnekler yapılar olabilir ama buradaki temel amaç şu olmalı; hiçbir sınıf kendi başına kalmamalı yani hepsinin bir arayüz katmanları olmalı.
58 |
59 | Bu arayüz katmanları bize geçici(mock) sınıf yapma imkanı verecek. Neden mock yapıyoruz derseniz bu sınıfın tüm özelliklerini mock sınıflarda test edip başarılı olduktan sonra gerçek kodumuza alıyoruz.
60 |
61 | > TDD yaklaşımın en baş noktası olan red yellow green buradan gelmektedir.Burada her feature için ilk yazılıp green yani başarılı elde edilir, her yeni gelen bu özelliklere eklenerek önce red olup ardından doğru seneryolar ile green hale getirilip kod gerçek kısma alınır.
62 |
63 | Projemizde StringHelper diye bir özelliğimiz olsaydı bunun birim testi için önce bir arayüze ve ardından bu arayüzü test eden mock sınfımızı yazmalıyız.
64 |
65 | ```dart
66 | abstract class IStringHelper {
67 | String toUpper(String data);
68 | }
69 | ```
70 |
71 | Ve bu sınıfın mock sınıfın oluşturup;
72 |
73 | ```dart
74 | class MockStringHelper extends IStringHelper {
75 | @override
76 | String toUpper(String data) {
77 | return data.toUpperCase();
78 | }
79 | }
80 | ```
81 |
82 | Bu şekildede testini yazıp özelliğimizi başarı ile kullanmış oluruz.
83 |
84 | ```dart
85 | test("String Helper Upper Case", () {
86 | String text = " Helelo";
87 | text = stringHelper.toUpper(text);
88 | expect(text.contains(RegExp("[A-Z\s]+")), true);
89 | });
90 | ```
91 |
92 | Projemizdeki OnBoard sayfamızın bir ViewModel iş katmanı bulunmaktadır.Bunu eğer test etmek isteseydik ilk önce bir arayüz sınıfını veya doğrudan bu [sınıfı kopyalayarak](https://github.com/VB10/flutter-architecture-template/blob/master/test/feature/onboard/onboard_mock_view_model.dart) bir mock sınıfı yazmış olmalıyız.
93 |
94 | ```dart
95 | class OnBoardMockViewModel implements OnBoardViewModel {
96 | @override
97 | BuildContext context;
98 |
99 | @override
100 | ICoreDio coreDio;
101 |
102 |
103 | @override
104 | int currentPageIndex;
105 |
106 | bool isLoading = false;
107 |
108 | @override
109 | List onBoarModel;
110 |
111 | @override
112 | void init() {
113 | coreDio = CoreDio(BaseOptions(baseUrl: "https://jsonplaceholder.typicode.com"));
114 | stringHelper = MockStringHelper();
115 | }
116 |
117 | @override
118 | void onPageChanged(int value) {
119 | currentPageIndex = value;
120 |
121 | }
122 | }
123 | ```
124 |
125 | Ardından bu sınıfımızın testini yazıp testi başarı ile bitirdikten sonra ana sınıfımızı güncelleyebiliriz.
126 |
127 | ```dart
128 | main() {
129 | OnBoardMockViewModel mockViewModel;
130 |
131 | setUp(() {
132 |
133 | mockViewModel = OnBoardMockViewModel();
134 | mockViewModel.init();
135 | });
136 |
137 | test("OnBoard Get Service Request", () async {
138 | expect(mockViewModel.isLoading, false);
139 | mockViewModel.getServiceRequest();
140 | expect(mockViewModel.isLoading, true);
141 | });
142 | }
143 | ```
144 |
145 | Burada biz sayfada bir istek atıldığında isLoading değerini test eden bir birim test yazmışız birçok farklı yöntem ile bu testler yazılıp OnBoardViewModel hazırlanmış olur.
146 |
147 | >Burada bir interface yapıp OnBoardViewModeli özelliklerini belirleyebilirdik ben ilk örnek olduğu için bu detaya girmedim ama yapıp IOnBoardViewModel den türetmek daha doğru olurdu.
148 |
149 | ## Ekran Testleri
150 |
151 | Bu nokta artık projenin en lüks kısmı olmakta çünkü birim testleri ve servis testleri yapıldıktan sonra geliştiricinin bir de bunu yapması çok fazla zaman alacağı için ben de çok fazla girmiyorum.Yukarıda paylaştığım gibi selenium ve playwright tarzı çözümler ile testlerinizi yazıp proje kodu bağımsız kontrol edebilirsiniz.
152 |
153 | > Özellikle bu testler projenin doğrudan apk veya ipa üzerinden dahil yapılabilir hiçbir kural bilmeden doğrudan gerçek kullanıcı testi gibi düşünebilirsiniz.
154 |
155 | ---
156 |
157 | Ve ana modelimiz de hazır daha fazlası için 🥳
158 |
159 | [](https://www.youtube.com/watch?v=4mYDEJlbejQ)
160 |
161 | [](https://www.youtube.com/watch?v=1a5VeHQlo0Q&list=PL1k5oWAuBhgV_XnhMSyu2YLZMZNGuD0Cv&index=15)
162 |
--------------------------------------------------------------------------------
/src/structure/atomic.md:
--------------------------------------------------------------------------------
1 | # Atomic Tasarım ve Düşünce
2 |
3 | Ve vee en can alıcı noktadayız. Atomic yaklaşım sadece bir parça değil bir düşüncedir ve bu düşünce proje genelinde daima önemli bir yer tutacaktır.
4 |
5 | 
6 |
7 | Konuya başlamadan önce özellikle [bu siteyi](https://bradfrost.com/blog/post/atomic-web-design/) incelemeyi unutmayın.
8 |
9 | Aslında resimdeki gibi amacımız tamamıyla şu olmalı;
10 |
11 | - En küçük parça hazırlanmalı (Normal Button, Facebook Login Text)
12 | - Ardından bunlar birleştirilmeli (FacebookButton),
13 | - Ardından bu katmanın üzerine diğer atomlar eklenmeli (FacebookForm, FacebookButton)
14 | - Yine devamında bir taslağımız elimize geçmeli ve (FacebookFormView) oluşmalı
15 | - Son olarak bu view bir sayfayla birleşip sonuca ulaşmalıdır. (Login View)
16 |
17 | ---
18 |
19 | Veee bitti atomic tasarım bu kadar demek isterdim ama bu ne yazık ki gerçek hayat hiç böyle işlemiyor gelin bir de gerçek hayata göre bunu kurgulayalım.
20 |
21 | 
22 |
23 | - Proje başlar ve doğrudan bir sayfa gelir
24 | - Sayfa tasarlanır ve aslında yukarıdaki piramitin çok uzağına geçmiş oluruz.
25 | - Atomic design biter tatlı son :)
26 |
27 | 
28 | Peki gerçek hayat için çözüm nasıl olmalı;
29 |
30 | - Evet ilk sayfa gelir başlanır.
31 | - Genelde doğrudan proje ekranları olmaz agile yaklaşım gereği de doğru düşünülse de sorun şu diğer ekranları bilmediğimiz için ne atom ne değil tam karar verilemeyebilir.
32 | - Bu senaryolarda tahmin etmek ve diğer projelere de bakıp çıkabilecek olanları en küçük parçaya ayırmak gerekebilir.
33 | - Misal bir giriş(login) sayfasını yaptık bitti diğer sayfalara geçmeden önce o sayfadaki buttonu core altına taşıyabiliriz.
34 | - Yine login sayfasındaki misal e-mail girdiğimiz alanı dışarı çıkartabiliriz(**MailTextField** gibi)
35 | - Buradaki en güzel hareket sayfayı bitirdikten sonra hemen merge almadan çıkartmak ve sonuçlandırmaktır.
36 | - Burada yine dikkat edilecek hareket şu olmalıdır; **Ne, Nereye, Ne Zaman Gelecek?**
37 | - Login sayfası içindeki e-mail field doğrudan core/components altına alınmamalı buraya iş kodu olmayan (no-business) kısım bulunmalı yani e-mail alanının çıplak hali(Kontrol kodları, iconları ve texti olan)
38 | - Feature içindeki component katmanında ise proje için olacak e-mail field olmalı ve burada iş kodları da olmalı (Girilen e-mail'in servis tarafından kontrol edilip doğru ise alanın açık hale gelmesi gibi.)
39 |
40 | ```dart
41 |
42 | EmailField() -> Text,Icon,Validation
43 | ProjectEmailField(onComplete:(data){//result}) -> Business
44 | ```
45 |
46 | Bu yazıyı buradan incleyebilirsiniz 🥳
47 |
48 | [](https://www.youtube.com/watch?v=teyr-2tl1Wo)
49 |
--------------------------------------------------------------------------------
/src/structure/folder.md:
--------------------------------------------------------------------------------
1 | # Klasör Yapısı
2 |
3 | 
4 |
5 | Birçok projede ilk başlanılan nokta bence burasıdır. Bu noktada projenin gelişmesini ve gideceği noktanın basit ama en önemli yeri diyebilirim.
6 |
7 | Flutter projelerine gelecek olursak birkaç önemli nokta var. Birden çok projede kullanmak ve içerisinde çok az iş(business) kodumuzun bulunduğu kısım olarak düşünebilirsiniz
8 |
9 | Bu katman sayesinde biz projenin asıl hatlarını belirleyip yolunu çizmiş oluyoruz.
10 |
11 | > Gördüğüm en büyük hata bir yöntemi misal [bloc](https://pub.dev/packages/bloc), [redux](https://pub.dev/packages/redux) veya [mobx](https://pub.dev/packages/mobx) örneklerini inceleyip bunlara göre bir mimari yapmaya çalışmak. Burada dikkatli olmalıyız. Bizim gördüklerimiz sadece örnek bunları kendi katmanlarımıza dahil edebilirsek tüm yönetim bize geçecektir.
12 |
13 | ## Ana Katman (Core)
14 |
15 | Dediğim gibi bu katman bizim asıl iş yapacak işleri yönetecek veya yapılacak işlere ön ayak olacak kısım. Gelin alt dallarına birlikte bakalım:
16 |
17 | ##### Base
18 |
19 | İçerisinde tüm sayfalara eşlik edecek modellerimi ekliyorum bununla birlikte view ve state gibi öncülük edecek katmanlarım burada.
20 |
21 | Örneğin tüm sayfalarımın bir iş yapan katmanı (View-Model) için bir base yapısını burada tanımlamak, tekrar tekrar bu özelikleri yapmamak ve yönetimi artırmak olarak düşünebilirsiniz.
22 |
23 | ```dart
24 | abstract class BaseViewModel {
25 | BuildContext context;
26 |
27 | ICoreDio coreDio = NetworkManager.instance.coreDio;
28 | void setContext(BuildContext context);
29 | void init();
30 | }
31 | ```
32 |
33 | ##### Atomlar (Components)
34 |
35 | Her proje kendi içerisinde bir hikaye barındırır ama bu hikayeleri flutter projelerinde özellikle parçalayabildiğimiz kadar parçalamalıyız ki elimizden geldiğince o hikayelerden başka projelerde okuyabileceğimiz kısımları ayırmış olalım.
36 |
37 | Özetle bu katmana iş kuralı olmayan sadece tek başına çalışabilecek widget'lar yer almalıdır.
38 |
39 | `Text("Selam")`
40 |
41 | Text widget hiçbir kurala bağlı olmadan her yerde kullanılabilir bizim bu katmanımızdaki her widget da böyle olmalıdır.
42 |
43 | Biz bir örnek yapsaydık:
44 |
45 | ```dart
46 | class NormalButton extends StatelessWidget {
47 | final Widget child;
48 | final VoidCallback onPressed;
49 | const NormalButton({Key key, this.child, this.onPressed}) : super(key: key);
50 | @override
51 | Widget build(BuildContext context) {
52 | return RaisedButton(
53 | padding: EdgeInsets.all(15),
54 | elevation: 10,
55 | onPressed: this.onPressed,
56 | child: child,
57 | );
58 | }
59 | }
60 | ```
61 |
62 | Hazırlayıp bu normal button widgetini istediğim projede çıkartıp kullanabilecek olacağım.
63 |
64 | ##### Sabitler ve Uzantılar
65 |
66 | Özellikle sabit değerlerimiz(constants) ve uzantılar(extension) projenin en üst düzeyinde tanımlanmalı ki bu değerler proje boyunca manupüle edilemesin veya üzerine bir şey koyacağımız zaman tekrar düşünülsün.
67 |
68 | Örnek verecek olursam misal projenin hayatında hep sabit olacak ve değişmesi mümkün olmayacak değerleri bu şekilde saklıyorum.
69 |
70 | ```dart
71 | class ApplicationConstants {
72 | static const LANG_ASSET_PATH = "asset/lang";
73 | static const IPAD_NAME = "IPAD";
74 | static const FONT_FAMILY = "POPPINS";
75 | static const COMPANY_NAME = "HWA";
76 | }
77 | ```
78 |
79 | > Burada normal bir tanımlama yaparken [magic number](https://help.semmle.com/wiki/display/JAVA/Magic+numbers#:~:text=A%20magic%20number%20is%20a,for%20other%20programmers%20to%20understand.) mantığını uyguluyorum ama diyelim ki proje hayatında sıklıkça kullanacağım bir değer var bunuda [lazy veya eager singleton](https://www.journaldev.com/1377/java-singleton-design-pattern-best-practices-examples) deseni ile sarmalıyorum.
80 |
81 | ##### Yükleme Alanı(Init)
82 |
83 | Bu katmanı tek tek inceleyeceğiz ama klasör mantığındaki çok önemli bir yer tutuyor. Özellikle iş katmanlarının saklama, yönlendirme, tema, dil gibi birçok nokta burada hayatına başlıyor ve buradan çağrılmaya başlanıyor.
84 |
85 | > Bu katman biraz iş kuralı içerebilir ama sorun teşkil etmez asıl olayımız burada onların temelini hazırlamaktır.
86 |
87 | ```dart
88 | class LocaleManager {
89 | static LocaleManager _instance = LocaleManager._init();
90 |
91 | SharedPreferences _preferences;
92 | static LocaleManager get instance => _instance;
93 |
94 | LocaleManager._init() {
95 | SharedPreferences.getInstance().then((value) {
96 | _preferences = value;
97 | });
98 | }
99 | }
100 | ```
101 |
102 | Belki en çok kullandığım ve mobil projelerde olmazsa olmaz kısımlardan olan saklama(cache) için burada konumlandırıyorum ve buradan sonrasında hayatını çiziyor.
103 |
104 | Yine burada [state yönetimi](https://github.com/VB10/flutter-architecture-template/blob/master/lib/core/init/notifier/provider_list.dart) için hazırladığım katmanda yine bu mantıkla kurgulayıp burada içerisini dolduruyor ve tek bir yerde merkezi olarak yönetmiş oluyorum.
105 |
106 | ## Ekranlar (Views)
107 |
108 | Ve proje hayatına başlar. Buradaki klasör yapısında **"feature base"** dediğim yapıda gidiyorum yani müşterimin istediği her modülü kendi içinde ayırıyorum ve her modül kendinden sorumlu oluyor.
109 |
110 | Diyelim ki en bilindik giriş(login) işlemi yapacağım ve girişten sonrada ürünlerime giden bir yol var bu durumda düşüncem şu şekilde oluyor
111 |
112 | - Login
113 | - Model
114 | - View
115 | - View Model
116 | - Service
117 | - Product
118 | - Model
119 | - View
120 | - View Model
121 | - Service
122 |
123 | Şeklinde ilerleyip elimden geldiğince sınıflarımı parçalamış ve test yazmak içinde rahat bir hale getiriyorum.
124 |
125 | ##### Proje Özel Katman(\_widget,\_model etc.)
126 |
127 | Burada ben projenin genelinde kullanacağımız ve ana mimariyi ilgilendirmeyen sadece projenin kullanacağı katmanı tanımlıyorum. Örneğin kullanıcımız(user) proje boyu her yerde olabilir veya projenin harita modülü olabilir bu da her zaman kullanılacak diye düşünürsek bunu core altına değil bu katmanda tanımlıyorum.
128 |
129 | > Projelerimde genelde basitten karmaşığa doğru bir mimari belirlerim. Bu mimari sırası mvc-mvvm-clean arch olarak gidiyor. Bu tarz bir proje için hem de hızlı olmaı için mvvm tercih ettim.
130 |
131 | 
132 |
133 | Bir örnek verecek olursak giriş widget'imiz olsun ve basıldığında bize başarılı olan bir senaryomuz ile dönüş yapmış olsun.
134 |
135 | ```dart
136 | class MVVMLoginButton extends StatelessWidget {
137 | final Function(String data) onComplete;
138 |
139 | const MVVMLoginButton({Key key, this.onComplete}) : super(key: key);
140 | @override
141 | Widget build(BuildContext context) {
142 | return IconNormalButton(
143 | icon: Icons.access_alarm,
144 | onPressed: () {
145 | onComplete("OKEY");
146 | // BUSINESS CALL
147 | },
148 | );
149 | }
150 | }
151 | ```
152 |
153 | Basitçe burada şunu yapmış oluyorum, bu kadar kod satırını giriş sayfamda değil burada yönetiyorum ve giriş sayfam sadece şunu yaptığında hiç bu kodu bilmeden doğru kullanabilecek oluyor.
154 |
155 | `MVVMLoginButton(onComplete:(data){})`
156 |
157 | ##### Proje Katmanı
158 |
159 | Burada yukarıda bahsettiğim gibi view, view-model, model, service olarak ayrıştırıp içerisini doldurmak üzere oluşturuyorum.
160 |
161 | 
162 |
163 | ---
164 |
165 | Bu yazıyı buradan incleyebilirsiniz 🥳
166 |
167 | [](https://www.youtube.com/watch?v=Xn8q9ywXKDc&list=PL1k5oWAuBhgV_XnhMSyu2YLZMZNGuD0Cv)
168 |
--------------------------------------------------------------------------------
/src/structure/names.md:
--------------------------------------------------------------------------------
1 | # İsimlendirme
2 |
3 | 
4 |
5 | Ve geldik yine benim en değer verdiğim konuya isimlendirme yaparken nelere dikkat etmeliyiz neler önemli.
6 |
7 | > Bir projede her şey belirli bir düzende ilerleyebilir ama özellikle kodun okunması, yeri veya anlamı gibi konular ilk isimlendirmelerle başlar.
8 |
9 | ## Klasörler
10 |
11 | - Ana katmana kod yazmak istiyorsak;
12 |
13 | `core/KATMANLAR`
14 |
15 | - Ekran geliştirmek istiyorsak;
16 |
17 | `features/GELİŞTİRMELER`
18 |
19 | - Ana katmana modül eklemek istiyorsak;
20 |
21 | `core/base/Modüller`
22 |
23 | `core/init/Modüller`
24 |
25 | `core/constants/Modüller`
26 |
27 | `core/components/Modüller`
28 |
29 | `core/extensions/Modüller`
30 |
31 | - Bir ekran geliştirmesine parça yapmak için;
32 |
33 | `features/login/model`
34 |
35 | `features/login/view`
36 |
37 | `features/login/view-model`
38 |
39 | `features/login/service` (isteğe bağlı ama ayırmayı severim)
40 |
41 | ## Dosya İsimlendirme
42 |
43 | Yine burada en iyi kullanım olarak [camel case pattern ](https://www.geeksforgeeks.org/convert-camel-case-string-to-snake-case-in-java/)tercih ediyorum.
44 |
45 | - Bir geliştirmenin alt dallarını yaparken;
46 |
47 | `features/login/model/login_model.dart`
48 |
49 | `features/login/view/login_view.dart`
50 |
51 | `features/login/view-model/login_view_model.dart`
52 |
53 | `features/login/service/login_service.dart`
54 |
55 | - Bir atomic widget yaparken;
56 |
57 | `ATOMADI_YAKINLIK.dart` örneğin `facebook_text.dart`
58 |
59 | - Eğer bir yönetim sınıfı yapıyorsak ise bu şekilde gidebiliriz;
60 |
61 | `network_manager.dart`
62 |
63 | `locale_manager.dart`
64 |
65 | `state_manager.dart`
66 |
67 | ## Değişkenler ve Sabitler
68 |
69 | Yine çok fazla önemli olan bir konuya geldik. Burada tercih de var ama tabiki lint kuralları da göz önüne alınarak seçimler var.
70 |
71 | - Proje boyunca değişmeyecek ve değerini bir çok yerde kullanacağımız bir değişkene ihtiyacımız varsa "[Magic Number](https://help.semmle.com/wiki/display/JAVA/Magic+numbers#:~:text=A%20magic%20number%20is%20a,for%20other%20programmers%20to%20understand.)" tercih ediyorum.
72 |
73 | `static const PROJECT_NAME = "HWA"`
74 |
75 | - Proje içinde sadece sınıf içinde değişmeyecek bir değişken kullanıyorsak;
76 |
77 | `final String userName = "Veli"`
78 |
79 | > Genel olarak isimlendirmede [camelCase](https://techterms.com/definition/camelcase) tercih ediyorum ama sabitlerde bu durumu değiştriyorum.
80 |
81 | - Bir sınıf tanımlarken;
82 |
83 | `class User{} or class UserDetail{}`
84 |
85 | - Bir sıralama sınıfı kullanmak istersek;
86 |
87 | `enum TimeValues {MIN,NORMAL,MAX}`
88 |
89 | > Burada enumlarımıza extension yazarak ona güç kazandırabiliriz.
90 | > Örnek olarak extension TimeValuesExtension on TimeValues { String get name => this.toString() } gibi.
91 | > Bu konuyu extension başlığında inceleyeceğiz.
92 |
--------------------------------------------------------------------------------
/src/support/me-about.md:
--------------------------------------------------------------------------------
1 | # Benim Hakkımda
2 |
3 | 
4 |
5 | Yaklaşık 4-5 yıldır aktif olarak yazılımın her türlü alanında paylaşım yapan bu işlere öğrencilikten başlayan genç, hızlı ve Türkiye'deki monolithic developer kavramına karşı olarak devam eden birisiyim.Her zaman için paylaşmayı seven ve mimarisel düşünceyi üründen önce planlayıp bunları esas alan birisiyim.
6 |
7 | > Monolithic tek bir dil ve bu dille bağlantılı framework öğrenip yılları aşkın süre diğerlerini takip etmeden, para kazanan geliştirici.
8 |
9 | Geliştiricilik hayatımda temel olarak:
10 |
11 | - IOS Development
12 | - Flutter Development
13 | - Mobile DevOps
14 | - Git
15 | - Mobile Test(Unit & UI )
16 | - Youtube Creator
17 | - Medium&Blog Writer
18 |
19 | Konularında profesyonel olarak çalışıyorum ve bunların yanında:
20 |
21 | - Android Development
22 | - Xamarin,React Native Development
23 | - Backend Stack(NodeJS, GO , .net Core)
24 |
25 | Yazıp, takip eden ve versiyonlama sistemlerini olmadan yaşamayan birisiyim.
26 |
27 | > Özellikle daha sayamadğım selenium java s.e gibi react gibi front-end dahil olmak üzere yazdım okuyor veya tartışmalarını global seviyede(o bundan iyi çünkü daha hızlıdan ziyade bench marklar projeler kodlarla) takip edip okuyorum.
28 |
29 | Bundan sonraki hayatımda da severek okuyup tüm teknoloji birimlerini takip edip daha çok ürün ve mimarisel geliştirmeler yapıp tüm arkadaşlarıma dostlarıma bir ücret olmadan paylaşmak, gençlere yaşadığımı yaşamamalarını ve daha güçlü olmalarının yolunu açmayı hedefliyorum.
30 |
31 | Takip etmek isteyenler için şöyle paylaşayım:
32 |
33 | Github : https://github.com/VB10
34 |
35 | Twitter : https://twitter.com/10VBacik
36 |
37 | Medium : https://medium.com/@vbacik.10
38 |
39 | Linkedin: https://www.linkedin.com/in/veli-bacik-345978a9/
40 |
--------------------------------------------------------------------------------
/src/support/projects.md:
--------------------------------------------------------------------------------
1 | # Projeler
2 |
3 | 
4 |
5 | Baştan sona tüm içerikler aslında yazmış olduğum projelerde sık sık kullanmış olduğum çözümler.Bu yüzden ele aldığım tüm konu gerçek hayatı size gösteriyor.
6 |
7 | > Özellikle youtube üzerinde ve yazdığım yazılarda dikkat etmeye çalıştığım konu gerçek hayatı referans alması çünkü biliyorum ki gerçek çözümler gerçek hayattaki yaşanan sorunlarla çıkar.
8 |
9 | Özellikle ilk yazmış olduğum KHEV projesininin yeri oldukça fazla. İlk flutter projesi olmamasına rağmen her toplantımızda yöneticilerimiz, benimle birlikte olan arkadaşım tester arkadaşlar(tek tarafı test edip iki taraftada fix olmasından ötürü :)) herkes oldukça beğenip çok değerli bir yer tutmuştu.
10 |
11 | Gerek yazmış olduğum gerek destek vermiş olduğum projelerin bazıları şu şekilde:
12 |
13 | | Proje | Store Linki |
14 | | ---------------- | ---------------------------------------------------------------------------------------------- |
15 | | Koç Emekli Vakfı | [Google Play ](https://play.google.com/store/apps/details?id=com.koc.kocemekli) |
16 | | Eureko Mobile | [Google Play](https://play.google.com/store/apps/details?id=com.eurekosigorta) |
17 | | Cumhuriyet | [App Store ](https://apps.apple.com/tr/app/cumhuriyet/id1503350537) |
18 | | Feast Kapında | [App Store](https://apps.apple.com/us/app/feast-kap%C4%B1nda/id1534525320?ign-mpt=uo%3D2) |
19 | | İzmir Tarih | [ Google Play ](https://play.google.com/store/apps/details?id=net.andromedya.izmirtarih&hl=en) |
20 |
21 | > Tüm hepsinin ios,android versiyonları Cumhuriyet ise [huawei mobile service](https://appgallery.huawei.com/#/app/C103001211) de bulunmaktadır.
22 |
23 | Tüm uygulamalarda CD hatları fastlane ile birlikte yapılmıştır.
24 | Bir çoğunda store görselleri yine benim [tarafımdan hazırlanmıştır](https://www.appstorescreenshot.com/).
25 |
26 | Hepsinin bir anısı, acısı ve tatlı yönleri oldu elbet ama dünden bugüne flutter frameworkü ile bu kadar ürün geliştirip dönüp baktığımda neredeyse hatasız bir şekilde hayatıma devam ettiğimi söyleyebilirim.
27 |
28 | > Bir çok hata benim eksikliğimden kaynaklandı veya bir arkadaşım dev de iken bir arkadaşım stabil versiyonunda olaması ama onun dışında aradğım tüm sorunlarda cevap göremedim.
29 |
30 | Bu mimari şuanki halinin daha eksik halleriyle bu projeleri kaldırdı ve geliştirmek için oldukça esnek ortam sundu.Önümüzdeki zamanlarda hep daha üzerine koyarak devam edeceğiz.
31 |
--------------------------------------------------------------------------------
/src/support/supports.md:
--------------------------------------------------------------------------------
1 | # Gönüllü Takımımız
2 |
3 | ## Beyza Karadeniz
4 |
5 | 
6 |
7 | > Bilgisayar mühendisi adayı olarak devam ettiğim öğrencilik hayatımda her zaman daha çok çalışarak ve en iyisini öğrenme isteğiyle hem kendime hem de yardımımın dokunabileceği herkese faydalı olmak amacıyla çalışmalarıma devam etmekteyim.
8 |
9 | Linkedln :https://www.linkedin.com/in/krdnzbeyza1999/
10 |
11 | Medium :https://medium.com/@byzakrdnzz
12 |
13 | Github:https://github.com/Krdnzbyza
14 |
--------------------------------------------------------------------------------