12 Kasım 2017 Pazar

macOS'da boşluklarla dock düzenleme - Organizing dock with blank icons


Ayrılın ayrılınn.

Terminal'e sırayla aşağıdaki kodları yazınca dock'a bir boşluk ekleniyor.;

defaults write com.apple.dock persistent-apps -array-add '{"tile-type"="spacer-tile";}'
killall Dock
Boşluklu Dock
gibi.

Şuracıkta dursun lazım olur ^^




22 Temmuz 2017 Cumartesi

.net Core MVC ile basit bir Workplace Bot deneyimleme (macos - VS Code)


Bot dünyasına şöyle bir giriş yapmak için şöyle basit bir .net core MVC projesi oluşturdum. :)

vs code terminal'den dotnet build ve dotnet run dedim ve projemin localhost:5000 'de koştuğunu gördüm.

Workplace üzerinde çalışmaya başlamak için öncelikle localimi tünelledim. Bu da ne demek?
Yerel makinanızı tünellek;  size bir subdomain vererek - yerelinizi internet üzerinde yayınlamanıza yardımcı olan bir eylemdir. Bu sayede yerel makinanızda çalışan bir uygulamayı uzakta bulunan müşterinize veya ekip arkadaşınıza çalışır halde göstermek için bir yerlere deploy etmenize gerek kalmaz.(https://www.serhatdundar.com/tag:ngrok)
Bu işlemi yapmak için araçlar var. Bunlardan en yaygını ngrok diye bir araç. Diğeri de https://localname.io/ diye şirin bir araç. localname.io'nun macos uygulaması da var ve subdomain vermenize izin veriyor. İkisi de iş görüyor.

Daha yaygın diye ngrok üzerinden gideyim.

1. Öncelikle download edelim;
https://ngrok.com/download
2. Şimdi login olup auth_token'ınımızı öğrenelim ve terminalimizden ngrok'un olduğu dizinde ngrok komutlarını çalıştırmaya başlayalım.
./ngrok authtoken authtokenım
3. Şimdi de 5000 portumu tünelliyorum çünkü uygulamam orada koşuyor.
./ngrok http 5000
Bana tünellediği adresi verdi;
https://fakirdomaini.ngrok.io
artık bu adres üzerinden workplace ile bağlantı kurmaya hazırız.

Şimdi workplace'de sol menü'den Integrations kısmına girip en alttaki "Create Custom Integration" butonuna tıklayalım.





Botumuza isim verip oluşturuyoruz ve id'si, token'ı vs oluşuyor. İzinleri kafadan attım hangileri lazımsa onlar seçilmeli..




Buraya kadar kolay geldik. Şimdi ise yazdığımız uygulama ile workplace'i tanıştırmamız lazım. Bunu bize webhook sağlayacak.

Webhooks sekmesine gelip uygulamamızın adresini veriyoruz. Yazdığımız adresin workplace'e success dönüyor olması gerek..

Bunun için WorkplaceController'ımda bir methodum var;

[HttpGet]
public string Get()
{
var query = Request.Query;

if (query["hub.mode"] == "subscribe" &&
query["hub.verify_token"] == "bot_verify_token")
{
var retVal = query["hub.challenge"];
return retVal.ToString();
}
else{
return Request.Query["hub.challange"];
}
}


dotnet build , dotnet run .. çalışıyor. O halde webhook'u ayarlayabilirim;


Kabul etti.. :)

Şimdi workplace'le iletişelim.. Diğer metodları yazalım, hatta direkt tüm controller'ı paylaşayım.. Bizim uygulamamız papağan misali sadece bizim ona yazdığımız şeyi bize dönüyor. Aşağı yukarı şöyle birşey;

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;

namespace botapp.Controllers
{
[Route("[controller]")]
public class WorkplaceController : Controller
{
[HttpGet]
public string Get()
{
var query = Request.Query;

if (query["hub.mode"] == "subscribe" &&
query["hub.verify_token"] == "weather_bot_verify_token")
{
var retVal = query["hub.challenge"];
return retVal.ToString();
}
else{
return Request.Query["hub.challange"];
}
}

[ActionName("Receive")]
[HttpPost]
public async Task<ActionResult> ReceivePost([FromBody]BotRequest data)
{
await Task.Factory.StartNew(async () =>
{
foreach (var entry in data.entry)
{
foreach (var message in entry.messaging)
{
if (string.IsNullOrWhiteSpace(message?.message?.text))
continue;

var msg = "You said: " + message.message.text;
var json = $@" {{recipient: {{ id: {message.sender.id}}},message: {{text: ""{msg}"" }}}}";
await PostRaw($@"https://graph.facebook.com/v2.6/me/messages?access_token=accesstokenim", json);
}
}
});

return new StatusCodeResult((int)System.Net.HttpStatusCode.OK);
}

private async Task<string> PostRaw(string url, string data)
{
var request = (HttpWebRequest)WebRequest.Create(url);
request.ContentType = "application/json";
request.Method = "POST";

var requestStream = await request.GetRequestStreamAsync();
using (var requestWriter = new StreamWriter(requestStream))
{
requestWriter.Write(data);
}

var responseStream = await request.GetResponseAsync();

var response = (HttpWebResponse)responseStream;
if (response == null)
throw new InvalidOperationException("GetResponse returns null");

using (var sr = new StreamReader(response.GetResponseStream()))
{
return sr.ReadToEnd();
}
}
}
}


Burada bir adet BotRequest modeli görüyoruz.. Bunu da aşağıda kaynağını verdiğim arkadaş yazmış. Onun örneğinden kopya çektim bayağı.

https://tutorials.botsfloor.com/facebook-chatbot-in-asp-net-2f9379a238b0


BotRequest ;

using System.Collections.Generic;

namespace botapp
{

public class BotRequest
{
public string @object { get; set; }
public List<BotEntry> entry { get; set; }
}

public class BotEntry
{
public string id { get; set; }
public long time { get; set; }
public List<BotMessageReceivedRequest> messaging { get; set; }
}

public class BotMessageReceivedRequest
{
public BotUser sender { get; set; }
public BotUser recipient { get; set; }
public string timestamp { get; set; }
public BotMessage message { get; set; }
public BotPostback postback { get; set; }
}

public class BotPostback
{
public string payload { get; set; }
}

public class BotMessageResponse
{
public BotUser recipient { get; set; }
public MessageResponse message { get; set; }
}

public class BotMessage
{
public string mid { get; set; }
public List<MessageAttachment> attachments { get; set; }
public long seq { get; set; }
public string text { get; set; }
public QuickReply quick_reply { get; set; }
}

public class BotUser
{
public string id { get; set; }
}

public class MessageResponse
{
public MessageAttachment attachment { get; set; }
public List<QuickReply> quick_replies { get; set; }
public string text { get; set; }
}

public class QuickReply
{
public string content_type { get; set; }
public string title { get; set; }
public string payload { get; set; }
}

public class ResponseButtons
{
public string type { get; set; }
public string title { get; set; }
public string payload { get; set; }
public string url { get; set; }
public string webview_height_ratio { get; set; }
}

public class MessageAttachment
{
public string type { get; set; }
public MessageAttachmentPayLoad payload { get; set; }
}

public class MessageAttachmentPayLoad
{
public string url { get; set; }
public string template_type { get; set; }
public string top_element_style { get; set; }
public List<PayloadElements> elements { get; set; }
public List<ResponseButtons> buttons { get; set; }
public string recipient_name { get; set; }
public string order_number { get; set; }
public string currency { get; set; }
public string payment_method { get; set; }
public string order_url { get; set; }
public string timestamp { get; set; }
public Address address { get; set; }
public Summary summary { get; set; }
}

public class PayloadElements
{
public string title { get; set; }
public string image_url { get; set; }
public string subtitle { get; set; }
public List<ResponseButtons> buttons { get; set; }
public string item_url { get; set; }
public int? quantity { get; set; }
public decimal? price { get; set; }
public string currency { get; set; }
}

public class Address
{
internal string street_2;

public string street_1 { get; set; }
public string city { get; set; }
public string postal_code { get; set; }
public string country { get; set; }
public string state { get; set; }
}
public class Summary
{
public decimal? subtotal { get; set; }
public decimal? shipping_cost { get; set; }
public decimal? total_tax { get; set; }
public decimal total_cost { get; set; }
}

}

dotnet build
dotnet run

hadi yazışalım :)


Biraz daha yaratıcı hale getirmek artık kodlamaya kalmış olduu :) Birşeyler deneyeceğim kendi çapımda bakalım.. Gerçi,, başka ne olabilir ki? :PPP



20 Temmuz 2017 Perşembe

npm ERR! missing:


Merhaba Cinlerim..

.net core mvc ile ufak çaplı bir projeye başlamışken bootstrap'i jquery'yi fln npm'den eklemeye kalktım pratik olur diye. :) Yine mono laneti vuku bulup sorun çıktığı için çok da pratik olduğu söylenemez ama birşey daha tecrübe etmiş oldum.

Sıkıntı şöyle başladı, vs'den "Add New Item" deyip "npm Configuration File" seçtim. Sonra oluşan package.json dosyama aşağıdaki gibi paketleri ekledim, kaydettim.

"dependencies": {
"bootstrap": "3.3.7",
"jquery": "3.2.1",
"jquery-validation": "1.16.0",
"jquery-validation-unobtrusive": "3.2.6"
}

bu işlemi yaptıktan sonra "node_modules" diye bir klasör oluşup paketlerimin içine yüklenmesi gerekiyordu normalde ama eklenmedi. Paketlerin yanında yüklenmediğini belirten işaretler uyarılar vardı. Ardından Visual Studio üzerinden node.js Interactive Window'u açıp .npm komutlarını çalıştırmayı denedim.

Birkaç sitede çözüm olarak ".npm init -y" komutunun durumu düzelteceği yazıyordu. Olmadı, bende şöyle bir hata verdi;
Please specify a valid Node.js project or project directory. If your solution contains multiple projects, specify a target project using .npm [ProjectName or ProjectDir] <npm arguments> For example: .npm [MyApp] list

Dediğini yaptım..
.npm [ProjeminAdı] list
Yine bana aynı çıktıyı verdi; :(
+-- UNMET DEPENDENCY bootstrap@3.3.7
+-- UNMET DEPENDENCY jquery@3.2.1
+-- UNMET DEPENDENCY jquery-validation@1.16.0
`-- UNMET DEPENDENCY jquery-validation-unobtrusive@3.2.6
npm ERR! missing: bootstrap@3.3.7, required by asp.net@1.0.0
npm ERR! missing: jquery@3.2.1, required by asp.net@1.0.0
npm ERR! missing: jquery-validation@1.16.0, required by asp.net@1.0.0
npm ERR! missing: jquery-validation-unobtrusive@3.2.6, required by asp.net@1.0.0
[ProjeminAdı] list completed with errors
Sonra birkaç şey daha denedim, biraz daha araştırdım derken şu paketi buldum;

https://www.npmjs.com/package/npm-install-missing

Hadi bunu da deneyeyim bari;

 .npm install -g npm-install-missing

Bu paketi kurduktan sonra kullanmam lazım tabi, işte şöyle;


.npm [ProjeminAdı] npm-install-missing

Sonunda bir succesful mesajı görebildim :) Sonrasında tekrar şu komutu çalıştırdım;
.npm [ProjeminAdı] install
Oldu ve hasretle yolunu gözlediğim klasörüm geldi. Ve paketlerim yüklendi. Aferim, bugün de iyi eğlendik. :)
 








17 Şubat 2017 Cuma

Nahoş bir girişimcilik hikayesi; ofisinizin tuvalet bekçisi; "Gorilla"! (Bitemedi :P)


Sevgili cinlerim.. Sizinle bugün bağrımızda sürekli kanayan bir yara olan ofisimizdeki tuvalet sorununu paylaşacağım. :( Tuvalet manzaralı bir yerim var ve o tuvaleti kullanmaya çalışanları gördükçe içim parçalanıyor. Rüşvet, adam kayırma, kaynak yapma, tehdit, itişme, torpil.. Bilimum yasa dışı durum yaşanıyor ve ofisçe bunun ilerlemesinden korkuyoruz :S Baktık bu böyle olmayacak, önlemimizi alalım dedik.

Bu sorunla ilgili tüm binanın orijinal fikirleri vardı uzun süredir konuşulan. Ama bu fikirler hiçbir zaman geyikten öteye gidememişti. Ama biz aksiyon insanları bu fikirlerin bir kısmını hayata geçirmeye karar verdik. Daha doğrusu uzmanımız ilk adımı attı. Eğer bu proje hayata geçerse çok dua alacağından eminiz. Hayata geçmese de biz bayağı birşey öğrenmiş olacağız :)

Öncelikle projemize bir isim vermemiz gerekiyordu. Tuvalet Bekcisi dediler itiraz etmedik. Gülmekle çalışmak arasında kala kala projeyi şekillendirmeye başladık. Sonra isim değişti, Gorilla oldu :)) Buna da güldük ne alaka diye, bekçi manası içerdiği için bu ismi de bağrımıza bastık.

Projenin amacı legal bir tuvalet sırası oluşturmak ve tuvaletin boş mu dolu mu olduğunu yerimizden kalkmadan öğrenmek özetle. Başka pek çok özellik eklenebilir de, ilk aşamada bu kadarı pek çok suçun önüne geçecektir diye tahmin ediyoruz. Her şey ofisimizin huzuru için. Ağzımızın tadı bozulmasın.

Tuvaletimizin kilidi sürgülü. O halde sürgünün kapalı olduğunu tespit edebilirsek tuvaletin dolu olduğunu da anlayabiliriz. O halde gerekli malzemeleri temin etmeye başlayalım. Robotistan.com'dan sipariş etmişler, muhtemelen elektirikçilerden vs de temin edilebilecek şeylerdir :)

1 Adet Orange Pi,
6-7 adet fotosel (ışık ölçen bir sensör),
32'lik bir hafıza kartı,
Uzatıcı kablolar vs

Bu alet edevat edinildikten sonra toplanıldı. Öncelikle 3 gruba ayrıldık. İsimleri atıyorum :p

1. Al gülüm: Linuxcular, yani Orange Pi'ye Linux kurup fotosellerle bağlantı kurup tuvaletin durumunu bize bildirecek arkadaşlar. (2 kişi)
2. Ver gülüm: Tuvalet Bot'u oluşturup tuvalet talebi alıp bunu anlamlandıracak olan arkadaşlar. (2 kişi)
3. Al gülüm Ver Gülüm: Al gülüm ve Ver gülüm ü iletiştirecek API'ci arkadaşlar. (ki ben bu gruptayım) (3 kişi)

 "Pair programming" yöntemi ile geliştirmeye başladık.

Al gülüm grubu Orange Pi'ye hafıza kartını takıp bu karta linux kurulumu yapmaya başladılar.

Ver gülüm grubu https://api.ai/ kullanarak tuvalet taleplerini nasıl anlamlandıracakları ile ilgili çalışmaya başladılar.

Bizim grup ise .Net Core ve MongoDB kullanarak bir web api yazmaya başladı.

Tüm gruplar kendi alanlarında acemiler aslında, bu yüzden çok hızlı bir başlangıç yapamadık. Ben daha önce MongoDb ve core kullanmadım mesela :)

Neyse bu yazı uzun başladı, bu girişi olsun. Diğer aşamalarını detaylandırmak için sonraki blog postlarımı bekleyelim ;) (Bitemedi :P)

Büyüğe de saygımız olsa mı bu arada? Bu da fikirler arasında. :P




Taam Taam gittim.



14 Şubat 2017 Salı

macOS'ta .Net Core'la ve Docker'la tanışma "Hello Core!" with mssql ;)



.Net Core ile tanışmam elimde olan ya da olmayan nedenlerden ötürü bir şekilde gecikmiş olsa da geç olsun güç olmasın mantığıyla ufaktan birbirimizi tanımaya başladık. ;)

Öncelikle .net core sdk'sını mac'imize kurmamız gerek;

https://www.microsoft.com/net/core#macos

Buradaki anlatımı yapan hanım pek şirin :) Ben buradaki sadece 2. adımla ilgilendim çünkü diğer adımları yaptırmak için farklı uygulamalar kullanacağım. Bir önceki postumda kurduğum Yeoman gibi. Yeoman'i yeni uygulama oluştururken kullanacağız.

Terminal'imizi açıp fishimize

~ sudo npm install -g yo generator-aspnet bower


paketlerini ekleme komutlarımızı yazıyoruz. Bunlar Yeoman'in uygulama oluşturucusu ve npm gibi bir paket yöneticisi olan bower'ı kurmak için.

Şimdi uygulamamızı oluşturabiliriz;

~ yo aspnet

yazarız ve karşımıza aşağıdaki gibi bir uygulama seçim ekranı çıkar.


Kullanmak istediğimiz UI Framework'ü seçeriz;

Ve tabii ki uygulamamıza isim veririz;

Uygulamamız oluştu. Yeyyyy :)



Uygulamayı oluşturduğumuz dizine
~ cd "HelloCore"
komutuyla gidip projeyi
~ dotnet restore
~ dotnet build
~ dotnet run
komutlarıyla derleyip geliştirmeye hazır hale getiriyoruz.


dotnet run komutumuzdan sonra "Now listening on: http://localhost:5000" uyarısını gördükten sonra tarayıcıya  http://localhost:5000 adresini yazdığımızda sitemizi görebiliyor olmamız lazım. İşte şöyle; 



Projemiz geliştirmeye hazır ama nerede geliştirsek? Ben çoğu yazılımcının olduğu gibi bir Visual Studio fanı olarak Visual Studio Code'da geliştirmek istedim. (Duyduğum kadarıyla Visual Studio for Mac'in daha çok yolu varmış.)

Bunun için Visual Studio Code'dan oluşturduğum uygulamanın dizinini açıyorum;



Tatlış ekranımız geldi. Peki neden tatlış böyle renkli renkli? Çünkü Code'a vscode-icons diye eklenti kurduk :)

Artık kodlamaya başlayabiliriz. Ne kodlasak ki? Ne yapsaaak ne yapsaaak.. Bir db kullansak, vee bu mac üzerinde mssql olsa :) Mümkün mü? Docker'la mümkün. (reklammlarr)

Docker'la da daha önce havalı havalı kullananları görmüş ama hiç kullanmamış biri olarak tanışma vesilemi .net core yapayım dedim mssql'i işin içine katarak.

https://blog.kodcu.com/2015/06/docker-nedir-neden-kullanilir/
"Docker işletim sistemi imajlarını versiyonlayan, Apache versiyon 2 lisanslı, Go dili ile yazılmış bir sanallaştırma ve konteyner teknolojisidir.

İşletim Sistemi İmajı Nedir?

Docker Linux türevinden işletim sistemleri üzerinde çalışan bir uygulamadır. Buradaki söylenen imaj ise, Linux türevi işletim sistemlerinden türetilmiş, boyut olarak küçültülmüş, Docker sanallaştırma ortamında çalışabilir işletim sistemi birimleridir."
Bu güzel buluşu kurup işimize başlayalım madem;
https://docs.docker.com/docker-for-mac/

Download linki;
https://download.docker.com/mac/stable/Docker.dmg

Kurduktan sonra terminalimizden docker üzerinden mssql'i şu kodla kurabiliriz;

~ docker run -e 'ACCEPT_EULA=Y' -e 'SA_PASSWORD=defineYourPassw0rd' -p 1433:1433 -d microsoft/mssql-server-linux
Kuruldu :)

Şimdi dbmize bağlanalım;


~ mssql -u SA -p defineYourPassw0rd
Artık bir db'miz var..



Şimdi Db'mizi projemizde kullanalım.

Bu adresteki 2. adımda nasıl kullanacağımız çok güzel anlatılmış.
https://www.microsoft.com/en-us/sql-server/developer-get-started/csharp-mac


// Build connection string
SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder();
builder.DataSource = "localhost";   // update me
builder.UserID = "sa";              // update me
builder.Password = "defineYourPassw0rd";      // update me
builder.InitialCatalog = "master";

// Connect to SQL
Console.Write("Connecting to SQL Server ... ");
using (SqlConnection connection = new SqlConnection(builder.ConnectionString))
{
    connection.Open();
    Console.WriteLine("Done.");
}

Ben Program.cs class'ımda yeni db oluşturma kısmını ve tablolara kayıt ekleme kısımlarını yaptım, çalıştırdım, oldu.

Faydalı bir eklenti olarak mssql eklentisini code'a kurdum. Şöyle faydalı bir arkadaş;





İşte böyle.. Bundan iyisi işe yarar bir proje :p Onu da yapacağız inşallah ;) 

Aşağıdaki linklerden de güzel faydalandım;

https://social.technet.microsoft.com/wiki/contents/articles/36247.net-core-on-mac-building-an-asp-net-core-app-with-web-api-ef-postgresql-and-running-it-on-docker.aspx

https://docs.microsoft.com/en-us/sql/linux/sql-server-linux-develop-use-vscode 


Bu yazımı bu özel günde paylaşıyor olmam mesleğimi ne kadar sevdiğimin göstergesi aslında, altını çizerim :p Kendime bu kafam kadar karışık blog yazısını verdiğim için teşekkür ederim :))




8 Şubat 2017 Çarşamba

macOS'da "Developer Friendly" Terminal ortamı oluşturma

Terminal'imi güzelleştirme ihtiyacım .Net Core öğrenesim geldiğinde başladı. İlk olarak güzel bir ortam oluşturup sonra başlarsam .Net Core'a daha hızlı ve zevkli adapte olurum diye uzmanımdan tavsiyelerle ortamımı kurmaya başladım.

Ortamı macOS'da kurduğumu belirteyim. 

Daha iyi bir terminal deneyimi için iTerm'i indirip kurduk. Arka plan resmi verebilmeyi çok sevdim :P Ben arka plana "Bender" ı koydum :) 

O zaman Renk!


https://www.iterm2.com/downloads.html

Terminalimize aşağıdaki kodu yapıştırarak Brew kurduk.. :)  Brew nedir; "Homebrew Mac OS X işletim sistemi üzerinde yazılım kurulumunu kolaylaştıran bir paket yönetim sistemidir."


/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
http://brew.sh/ 

Ardından Node.js i kurduk. Node.js nedir; "Javascript ile server side uygulamalar yazabileceğimiz bir framework'tür". 
https://nodejs.org/en/

~brew install node.js

Bu sayede npm'imiz  de oldu. npm nedir;
"Npm aynı Nuget’de olduğu gibi Node.js için çeşitli scriptleri otomatik olarak sisteme yüklemek, listelemek, silmek, update etmek gibi işlere yarıyan, command prompt’tan çalışan bir uygulamadır. Eğer Npm makinada yok ise Node.js‘in yüklenmesi ile Npm de otomatik olarak gelmiş olur."

Node.js'i kurduktan sonra npm metodlarını kullanarak yo 'yu kurduk. Yo yani Yeoman nedir? "Yeoman, her tür uygulamayı oluşturmaya olanak tanıyan genel bir iskele sistemidir. Yeoman command-line arayüzü ile node.js kullanan yo komutu ile pluginleri çağıran google tarafından geliştirilmiş bir uygulamadır."

sudo npm -g install yo
Buradaki "sudo" ifadesi yönetici yetkileriyle komutu çalıştırmak demek. 
"-g" ise bu uygulamaya global olarak heryerden erişebileceğimiz anlamına geliyor. 


Sonra programlanabilirlik, auto compilation, smart history gibi avantajlarından dolayı "fish" adında bir shell tercih ettik.
https://fish.sh/

Bunu kurmak için de şu kodu çalıştırdık;

brew install fish

Fish'i varsayılan shell yapmak için öncelikle mevcut shell'lerin içine fish'in yolunu tanımlamamız gerekiyor. Bunun için öncelikle shell'lerin listesini çekiyoruz;

sudo nano /etc/shells
listeye 
/usr/local/bin/fish 
ekleyip kaydediyoruz.

bu işlemi tamamladıktan sonra fish'e geçmek için terminal'i kapatıp açmamız yeterli. Ya da direk bash ekranına fish yazarsak da geçiş yapabiliyoruz :)

Sonra google amcaya "fisher install" yazıp fishermanin sitesine girip bulduğumuz install komutuyla fisherman'i yükledik. Fisherman nedir; "fish için eklenti yöneticisidir."


curl -Lo ~/.config/fish/functions/fisher.fish --create-dirs git.io/fisher

fisher z yapıp ilk plugin'imizi yükledik. Detaylar için;
https://github.com/fisherman/fisherman/wiki/T%C3%BCrk%C3%A7e

Asıl bu zamandan sonra herşey renklendi. Tüm komutlar renklendi ben leb deyince çorum demeye fln başladı Terminal. Sevdim. Rengi verdik. .Net Core'da da dans ederiz umarım. 

Bu arada bu ortamla ilgili tek sevmediğim yan ilk terminal açılışında beni karşılayan ayıplı kelime :P 

O zaman work!



7 Kasım 2016 Pazartesi

Xamarin.Forms Simple Popup Layout

Hi there, I needed Popup in my project, but I couldn't find a simple solution for Xamarin.Forms. So me and my friend developed a simple PopupLayout for us. It is a quick solution until find a better one. Maybe it can help you too;

Let's create a class in Forms project.



using System.Threading.Tasks;
using Xamarin.Forms;

namespace MyProject
{
    public class PopupLayout : RelativeLayout
    {
        private View _content;
        private View _popup;
        private RelativeLayout _backdrop;

        protected override void OnChildAdded(Element child)
        {
            base.OnChildAdded(child);
        }

        public View Content
        {
            get { return _content; }
            set {
                if (_content != null)
                    Children.Remove(_content);
                    _content = value;
                    Children.Add(_content, () => Bounds);
            }

        }

        public bool IsPopupActive
        {
            get { return _popup != null; }
        }

        public async Task<bool> ShowPopup(View popupView, string title = null)
        {
            await DismissPopup();

            _popup = popupView;

            _popup.VerticalOptions = LayoutOptions.CenterAndExpand;

            if (_content != null)
                _content.InputTransparent = true;

            var backdrop = new RelativeLayout
            {
                BackgroundColor = Color.FromRgba(0, 0, 0, 0.4),
                Opacity = 0,
                GestureRecognizers = { new TapGestureRecognizer() },
                Padding = new Thickness(20),
                VerticalOptions = LayoutOptions.CenterAndExpand
            };

            var clickArea = new RelativeLayout
            {
                BackgroundColor = Color.Transparent,
                Opacity = 0
            };

            var tap = new TapGestureRecognizer();
            tap.Tapped += Tap_Tapped;
            clickArea.GestureRecognizers.Add(tap);

            var w = Constraint.RelativeToParent(p => p.Width - 40);
            var h = Constraint.RelativeToParent(p => p.Height - 40);
            var zero = Constraint.Constant(20);

            var sl = new StackLayout
            {
                Orientation = StackOrientation.Vertical,
                HorizontalOptions = LayoutOptions.FillAndExpand,
                VerticalOptions = LayoutOptions.CenterAndExpand,
                Spacing = 0
            };

            var csl =new StackLayout
            {
                Orientation = StackOrientation.Vertical,
                HorizontalOptions = LayoutOptions.FillAndExpand,
                VerticalOptions = LayoutOptions.CenterAndExpand,
                Spacing = 0
            };


            if (!string.IsNullOrEmpty(title))
            {
                //This is a FontAwesome Label. We made it. You can use anything you want instead of this.
                var closeLabel = new FALabel 
                {
                    Text = FAIcon.Times, //this it fontawesome icon Unicode
                    HorizontalOptions = LayoutOptions.EndAndExpand,
                    VerticalOptions = LayoutOptions.StartAndExpand,
                    TextColor = Color.White,
                    VerticalTextAlignment = TextAlignment.Center,
                    FontSize = 22
                };                

                closeLabel.GestureRecognizers.Add(tap);

                var slTitle = new StackLayout
                {
                    HorizontalOptions = LayoutOptions.FillAndExpand,
                    VerticalOptions = LayoutOptions.Center,
                    Orientation = StackOrientation.Horizontal,
                    Children =
                    {
                        new Label
                        {
                            HorizontalOptions = LayoutOptions.StartAndExpand,
                            VerticalOptions = LayoutOptions.Center,
                            Text = title,
                            TextColor = Color.White
                        },
                        closeLabel
                    },

                    Padding = new Thickness(8, 5, 8, 5),
                    BackgroundColor = Color.FromHex("#D10000")
                };

                csl.Children.Add(slTitle);
            }

            csl.Children.Add(_popup);
            sl.Children.Add (csl);

            backdrop.Children.Add(clickArea, Constraint.Constant(0), Constraint.Constant(0), Constraint.RelativeToParent(p => p.Width),
                Constraint.RelativeToParent(p => p.Height));

            backdrop.Children.Add(sl,
                zero,
                zero,
                w,
                h);

            _backdrop = backdrop;

            Children.Add(backdrop,
                Constraint.Constant(0),
                Constraint.Constant(0),
                Constraint.RelativeToParent(p => p.Width),
                Constraint.RelativeToParent(p => p.Height)
            );

            UpdateChildrenLayout();

            return await _backdrop.FadeTo(1);
        }

        private async void Tap_Tapped(object sender, System.EventArgs e)
        {
            await DismissPopup();
        }

        public async Task DismissPopup()
        {

            if (_popup != null)
            {
                await Task.WhenAll(_popup.FadeTo(0), _backdrop.FadeTo(0));
                _backdrop.Children.Remove(_popup);
                Children.Remove(_backdrop);
                _popup = null;
            }

            if (_content != null)
            {
                _content.InputTransparent = false;
            }
        }
    }
}






How to use it in xaml page;


<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" 
        xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
        x:Class="MyProject.SamplePopup" 
        xmlns:l="clr-namespace:MyProject;assembly=MyProject">
    <ContentPage.Content>
        <l:PopupLayout x:Name="plDefault" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
            <StackLayout x:Name="slMain" Orientation="Vertical" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand">

                .

                .

                .

                .

            </StackLayout>
        </l:PopupLayout>
    </ContentPage.Content>
</ContentPage>





You should set your PopupLayout from .cs too;

Appearing class;


    plDefault.Children.Remove(slMain);
    plDefault.Children.Add(slMain, Constraint.Constant(0), Constraint.Constant(0), Constraint.RelativeToParent(p => p.Width), Constraint.RelativeToParent(p => p.Height));




override OnSizeAllocated class for issues;



        protected override void OnSizeAllocated(double width, double height)
        {
            base.OnSizeAllocated(width, height); //must be called    

            slMain.WidthRequest = width;
            slMain.HeightRequest = height;

        }




How to open/close it;


   var popupMainStack = new StackLayout
   {
      VerticalOptions = LayoutOptions.FillAndExpand,
      HorizontalOptions = LayoutOptions.FillAndExpand,
      BackgroundColor = Color.White
   };
//You can add anything you want to main stack as children.
   await Popup.ShowPopup(popupMainStack,"Popup Title");






await Popup.DismissPopup(); //Close popup




Simple ;)