Podsumowanie konkursu – DSP#22

Udało się! Dotrwałem do końca konkursu, spełniłem podstawowe założenie. Jestem naprawdę szczęśliwy, że w tym repozytorium jest gotowa do użycia, opublikowana i ukończona biblioteka. Nie było łatwo, ale dla tego kawałka kodu: compile 'com.github.migellal:dayview:0.0.1′  było warto, a oto małe podsumowanie.

Założenia

Założeniami do biblioteki o których pisałem w drugim wpisie były:

użycie Kotlina, material design, miły dla oka design, prawdziwa dokumentacja (opis całego API, etc), prawdziwy open-source (z ładnym, pokazującym działanie biblioteki na gifach plikiem README), odrobina reklamy, chcę, żeby inni również z niej skorzystali

dobre testy, continous – co się da

Tych przekreślonych osiągnąć się niestety nie udało, nie mniej jestem bardzo dumny z tego co zostało napisane. A tak miała wyglądać pierwotna wersja biblioteki. Miała, ale spisałem wymagania i w ogóle do nich nie zajrzałem (powinienem był zaglądać). Dlatego z pamięci stworzyłem coś innego, co również jest ładne oraz na szczęście spełnia założenia.

Posty

W czasie trwania konkursu pisałem nie tylko o projekcie, założyłem sobie, że posty nieparzyste będą ogólniej o IT, a te parzyste o bibliotece (co działało prawie do samego końca końca projektu). Tak wygląda lista tematów które poruszyłem w ramach konkursu:

A tak komplet postów o tworzeniu biblioteki:

Plus oczywiście ten post, zachęcam oczywiście do odwiedzania linków z powyższej listy, starałem się, żeby było ciekawie i różnorodnie.

Daty

A tak prezentowały się daty publikacji poszczególnych postów w widoku kalendarza

Niebieski kolor oznacza dwa posty dziennie. I teraz konia z rzędem temu kto mi powie, czy to jest w 100% zgodne z regulaminem, na slacku co chwilę pojawia się dyskusja na ten temat. Licząc od piątku wychodzi 10 tygodni po dwa posty w każdym, ale..

Statystyki

Zgodnie z informacjami dostarczonymi mi przez toggl praca nad projektem zajęła mi ponad 80 godzin.

Z kolei liczba odwiedzin w czasie trwania konkursu przekroczyła 10 500

Za które serdecznie dziękuję 😉

Muszę szczerze dodać na koniec, że w tym roku było zdecydowanie trudniej. Miałem mniej czasu, dużo więcej obowiązków rodzinnych, oraz służbowych (więcej projektów również). Tym bardziej jestem szczęśliwy, że udało mi się dojść aż tutaj.

Co dalej?

Chwila przerwy 😉 Lojalnie też informuję, że w czerwcu tempo pisania nowych postów zdecydowanie spadnie – chcę trochę odpocząć od bloga, przeczytać kilka zaległych książek i ogólnie odpocząć, ostatnio miałem całe mnóstwo pracy nie tylko w związku z konkursem, ale również ogromem innych projektów. Ale nowe posty się pojawią, mam kilka fajnych draftów, oraz sporo spisanych pomysłów. Tylko nie mogę zaproponować żadnej daty, kiedy to będzie.

Stay tuned!

Publikacja biblioteki cz. 2 – DSP#21

W poprzedniej części tego wpisu wykonaliśmy sporo operacji w bibliotece, żeby umożliwić jej publikację, konfiguracyjne niemalże wszystko co było wymagane. Na ten moment zostało więc nam przygotowanie reszty, kliknięcie magicznego publikuj, oraz podzielenie się ze światem tym co udało mi się przez te kilka tygodni napisać. Zatem do dzieła!

Finalna konfiguracja

Finalnej konfiguracji niestety nie pokażę 🙂 Chodzi o to, że brakującymi elementami są hasła, użytkownicy, etc, czyli:

  • NEXUS_USERNAME , NEXUS_PASSWORD
  • signing.keyId, signing.password
  • signing.secretKeyRingFile
  • org.gradle.daemon=true

Dopisujemy te parametry w tym pliku. Po dopisaniu (i jeśli zadanie na na jirze zostało oznaczone jako rozwiązane, to istotne) wreszcie można kliknąć wyślij aplikację na serwer. Ale gdzie to kliknąć? Otóż jest to zadanie dla systemu Gradle.

Chodzi oczywiście o zadanie upload archives. Jeśli wszystko przebiegło poprawnie to znajdziemy naszą bibliotekę w tzw „stagingRepos”. Prawdopodobnie na samym dole.

Trzeba tam kliknąć przycisk „close”, poczekać trochę na wykonanie wszystkich operacji. A następnie, finalnie, przycisk „release”. Tutaj znajduje się kompletna dokumentacja do tych operacji. Po kliknięciu release należy poczekać kilka minut i jeśli wszystko przebiegło poprawnie, znajdziemy naszą bibliotekę np w serwisie gradle, please.

To oznacza, że udało mi się spełnić główne założenie konkursu, czyli opublikować bibliotekę. Wymagań względem siebie miałem o wiele więcej, ale i tak uważam to za spory sukces. Na podsumowania przyjdzie jeszcze czas (w następnym, ostatnim wpisie). Ostatnim punktem związanym z publikacjami jest aktualizacja statusu zgłoszenia i oznaczenie go, że biblioteka została już udostępniona w ramach maven central.

Publikacje

Do opublikowania zostało nam kilka rzeczy, między innymi aplikacja demo w klepie Play, aplikacja demo w repozytorium, a także wieńcząca projekt finalna publikacja linku do repozytorium w readme. Do tego oczywiście zgłoszenie biblioteki na stronie android-arsenal. Generujemy więc podpisaną aplikację, wrzucamy są do sklepu w kategorii: „Biblioteki oraz wersje demo”. Swoją drogą sklep Play przeszedł ostatnio mały redesign, doszło sporo nowych funkcji, wszystko jest zdecydowanie ładniejsze oraz bardziej przejrzyste.

No i stało, aplikacja została opublikowana w sklepie Play pod tym adresem, do tego można sobie pobrać to demko bezpośrednio z repo, a także oczywiście zapraszam wszystkich do używania biblioteki:

compile 'com.github.migellal:dayview:0.0.1′

Została również zgłoszona do android-arsenal i aktualnie oczekuje na akceptację.

Update:

Została opublikowana w Android-Arsenal, można ją podejrzeć tutaj.

To tyle, jeśli chodzi o bibliotekę, naprawdę jestem szczęśliwy, że finalnie udało mi się domknąć ten projekt 🙂 Przejście przez wszystkie procedury było złożone i czasem czasochłonne, ale fajnie, że już jest i każdy może z niej skorzystać. Pozostało nam jeszcze małe podsumowanie udziału w konkursie, na które zapraszam już w najbliższy czwartek od 8:00.

Publikacja biblioteki cz. 1 – DSP#20

Planowałem rozbić publikację aplikacji na dwa etapy, wrzucenie do jakiegoś repozytorium bibliotek, oraz aktualizacje pliku README, publikacja na stronie android-arsenal. Niestety nie można zrobić jednego bez drugiego, dlatego też podzielę wpis na dwie części, w pierwszej dodamy pliki umożliwiające publikację do biblioteki, dopiszemy README, wybierzemy repozytorium, oraz zgłosimy chęć dodania projektu. W drugiej wrzucimy aplikację do repo, sklepu, oraz na stronę android-arsenal.

Wybór hostingu biblioteki

Bardzo popularnym swego czasu repozytorium dla bibliotek androidowych była strona jitpack.io. Mi jednak zależało na tym, żeby maksymalnie uprościć korzystanie, jeśli użyłbym jitpacka dochodzi jeszcze jedna linia konfiguracyjna po stronie klienta, mianowicie:

    allprojects {
		repositories {
			...
			maven { url 'https://jitpack.io' }
		}
	}

Dlatego wybrałem chyba najpopularniejsze repozytorium w świecie javowym: Maven central. O tym jak się do niego dostać w kolejnych akapitach.

Readme

Udało mi się również napisać dzisiaj readme, można je podziwiać tutaj. Mam nadzieję, że się podoba, chwilkę nad nim posiedziałem, to chyba mój pierwszy dokument tego typu w życiu. Skupiłem się na następujących punktach:

  • Overview
  • Screnshoots
  • Features
  • API
  • Examples
  • Download
  • License

Mam nadzieję, że uwzględniłem wszystko, ale jak coś, to komentarze są do dyspozycji.

Konfiguracja

Musiałem też wykonać trochę wstępnej konfiguracji, żeby móc opublikować bibliotekę. Listę zmian najlepiej obrazuje ten commit. Zmiany w plikach .kt są nieistotne z punktu widzenia sprawy. Jak widać, doszedł kolejny plik konfiguracyjny gradle.properties zawierający informacje o pomie. Podobnie znajduje się tam zupełnie nowy plik maven-push.gardle. W przypadku chęci opublikowania własnej biblioteki można stworzyć podobny komplet plików, zmieniając oczywiście adresy, nazwy, według własnych standardów.

Konfiguracja GPG

Chcąc wysłać swoją bibliotekę potrzebujemy skorzystać z GPG. Pierwszy raz zetknąłem się z tą technologią, niemniej nieoceniony okazał się program GPG4win. Bez potrzeby korzystania z linii komend wygenerował mi niezbędny klucz, który następnie mogłem wysłać razem z biblioteką.

Zgłoszenie

Po wykonaniu tych kroków zgłosiłem gotowość biblioteki do publikacji na jirze, w tym miejscu. Proces wygląda tak, że zakładamy konto na Sonatype, zgłaszamy chęć wydania biblioteki, oni rozwiązują to zadanie i podsyłają instrukcję jak publikować. U mnie potrwało to zaledwie minut, zresztą wystarczy spojrzeć tutaj.

Na ten moment to tyle, w następnej, przedostatniej części opiszę pozostałe kroki które będą odpowiadały za publikację i odrobinę rozpropagowanie aplikacji w sieci.

DayView demo – DSP#19

Jak pisałem poprzednim razem udało się już ukończyć bibliotekę, wszystko co chciałem zaimplementować udało się wdrożyć. Nie mniej przydała by się jakaś mała aplikacja która pozwoliła by pokazać jej możliwości. To właśnie taki jest kolejny krok i o tym dzisiaj napiszę.

Na początek kilka wymagań, chcę żeby aplikacja:

  • prezentowała możliwości API
  • posiadała odnośnik do źródeł biblioteki
  • oczywiście wyświetlała bibliotekę, przynajmniej w dwóch rozmiarach

Udało się tym wymaganiom sprostać, taki jest efekt końcowy:

Aplikacja będzie dostępna w sklepie Play o tutaj, a także na stronie githubowej. Ale to to wszystko dopiero jak uda mi się udostępnić bibliotekę, oraz napisać README, trochę ją wypromować. Tak wygląda kod źródłowy dla tego małego demka:

class MainActivity : AppCompatActivity() {

    var dayView: DayView? = null
    var dayView2: DayView? = null
    var applyBtn: Button? = null
    var borderBtn: Button? = null
    var backgroundBtn: Button? = null
    var textBtn: Button? = null
    var barBtn: Button? = null
    var dayEt: EditText? = null
    var monthEt: EditText? = null
    var borderColor: Int = Color.BLACK
    var backgroundColor: Int = Color.WHITE
    var textColor: Int = Color.BLACK
    var barColor: Int = Color.BLUE
    var date: Date = Date()
    var day: Int = 1
    var month: Int = 1
    val year: Int = 2016
    var url: TextView? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        dayView = findViewById(R.id.dayView) as DayView
        dayView2 = findViewById(R.id.dayView2) as DayView
        applyBtn = findViewById(R.id.apply_btn) as Button
        borderBtn = findViewById(R.id.borderColor_btn) as Button
        backgroundBtn = findViewById(R.id.backgroundColor_btn) as Button
        textBtn = findViewById(R.id.textColor_btn) as Button
        barBtn = findViewById(R.id.barColor_btn) as Button
        dayEt = findViewById(R.id.day_et) as EditText
        monthEt = findViewById(R.id.month_et) as EditText
        url = findViewById(R.id.url_tv) as TextView
        val toolbar = findViewById(R.id.toolbar) as Toolbar
        setSupportActionBar(toolbar)

        val pattern = Pattern.compile("https://github.com/migellal/DayView")
        Linkify.addLinks(url, pattern, "")

        applyBtn!!.setOnClickListener {
            if (dayEt!!.text != null && !dayEt!!.text.isEmpty()
                    && monthEt!!.text != null && !monthEt!!.text.isEmpty()) {
                day = dayEt!!.text.toString().toInt()
                month = monthEt!!.text.toString().toInt()
                month -= 1
            }
            date = Date(year, month, day)
            dayView!!.date = date
            dayView!!.borderColor = borderColor
            dayView!!.cardBackgroundColor = backgroundColor
            dayView!!.textColor = textColor
            dayView!!.barColor = barColor
            dayView2!!.date = date
            dayView2!!.borderColor = borderColor
            dayView2!!.cardBackgroundColor = backgroundColor
            dayView2!!.textColor = textColor
            dayView2!!.barColor = barColor
        }

        borderBtn!!.setOnClickListener {
            colorPicker(borderBtn as Button)
        }

        backgroundBtn!!.setOnClickListener {
            colorPicker(backgroundBtn as Button)
        }

        textBtn!!.setOnClickListener {
            colorPicker(textBtn as Button)
        }

        barBtn!!.setOnClickListener {
            colorPicker(barBtn as Button)
        }
    }

    private fun colorPicker(btn: Button) {
        ColorOMaticDialog.Builder()
                .initialColor(Color.BLACK)
                .colorMode(ColorMode.RGB)
                .indicatorMode(IndicatorMode.HEX)
                .onColorSelected {
                    btn.setBackgroundColor(it)
                    if (btn == borderBtn)
                        borderColor = it
                    else if (btn == backgroundBtn)
                        backgroundColor = it
                    else if (btn == textBtn)
                        textColor = it
                    else
                        barColor = it
                }
                .create()
                .show(supportFragmentManager, "ColorOMaticDialog")
    }

}

Kilka uwag do kodu, użyłem biblioteki color-o-matic do wyświetlania menu wyboru koloru. Android nie ma jej dostępnej natywnie, stąd mogłem albo użyć gotowej, albo pisać samemu. Dodatkowo kod listenerów w Kotlinie wygląda całkiem fajnie. Tzn, jeśli znajduje się tam tylko jedna metoda (np onClick()) to nie zapisujemy jej, tylko kod umieszczamy w nawiasach klamrowych. Kolejną ciekawostką jest słówko kluczowe it, które odnosi się do obiektu z którego korzystamy w danej metodzie. Na przykładzie implementacji color-o-matic, listener onColorSelected posiadał metodę onSelect, albo podobną. Nie trzeba jej wpisywać, żeby dostać się do parametru który jest tam podany, wystarczy użyć wspomnianego słówka kluczowego. Warto też wspomnieć, że do poziomego ułożenia telefonu został dopisany nowy layout dla demo, ponieważ domyślne ułożenie po obrocie mi się nie podobało. Poprawiłem też mały błąd, który powodował, że jeśli nie wstawiliśmy daty nic nie było wyświetlane, założeniem było, żeby wyświetlała się wtedy dzisiejsza data i tak teraz jest.

To tyle jeśli chodzi o demko, nie ma się tutaj co rozpisywać, najważniejsze, żeby pokazywało co biblioteka potrafi i wydaje mi się, że to zadanie zostało spełnione. Wszystkie zmiany zostały zaccomitowane i znajdują się tutaj. A następnym krokiem jest publikacja biblioteki.

Finalna wersja kartki z kalendarza – DSP#18

Udało się! Doszedłem do momentu w którym biblioteka została ukończona. Może trudno w to uwierzyć, ale z każdym postem dotyczącym aplikacji dodawałem tylko kilka linii kodu. Dlatego posty na temat biblioteki zebrane razem mogą stanowić całkiem ciekawy tutorial, gdzie wszystko jest pokazane, łącznie z moim potknięciami. Ale do rzeczy, tak wygląda finalna (na ten moment) wersja kartki z kalendarza.

Finalna wersja kartki z kalendarza

Piszę na ten moment, ponieważ możliwe, że będzie się rozwijała, albo, że pojawią się jakieś błędy o których nie mam pojęcia. Bądź co bądź wydaje mi się, że dużo można jeszcze tutaj dorobić. Np przycisk do przesuwania daty w lewo, w prawo, możliwość wyświetlenia roku, możliwość poszerzenia ramki, etc. Noo ale do rzeczy, oto jak wygląda kodzik który dopisałem tym razem.

    private fun drawTextCenter(canvas: Canvas?) {
        val shortMonthName = month.length <= 4
        val x = canvas!!.width.toFloat() / 2
        val y = (endY - barY) / 5
        textDayPaint.textSize = 2 * y
        canvas.drawText(day, x, barY + (2.5 * y).toFloat(), textDayPaint)
        if (shortMonthName) {
            textMonthPaint.textSize = y
            canvas.drawText(month, x, barY + (3.5 * y).toFloat(), textMonthPaint)
        } else {
            textMonthPaint.textSize = y / 2
            canvas.drawText(month, x, barY + (3.1 * y).toFloat(), textMonthPaint)
        }
    }

    private fun getMonth(month: Int): String {
        return DateFormatSymbols().months[month - 1]
    }

Mamy tutaj dwie metody, jedna służy do rysowania tekstu na środku ekranu, druga do pobierania nazwy miesiąca. Może najpierw o tej drugiej, jak widać wpada tutaj parametr int, na tej podstawie z klasy DateFormatSymbols jest pobierana nazwa według aktualnego Locale. Co ciekawe, Android ma swoją wersję tej metody, ale pojawiła się ona dopiero niedawno, dlatego nie zgadza się ze wszystkimi API które obsługuje. Główna metoda którą chciałem omówić jest nieco dłuższa, w niej wyliczana jest pozycja napisów, oraz są one drukowane na ekranie. Wyliczenie x to po prostu podzielenie rozmiaru płótna na pół, ustawienie formatowania tekstu, żeby wyświetlał się na środku, no i można wrzucać tekst. Z y problem jest nieco większy, tzn potrzeba nam dwóch wysokości, jednej dla dużej cyfry, drugiej dla napisu. Dlatego też dzielę pozostałe miejsce na 5. A następnie umieszczam cyfrę, oraz miesiąc na wysokości, która wizualnie najbardziej mi odpowiada (stąd te 3.1, 3.5 jako mnożniki). Znajduje się tam też jeden if, który na podstawie długości tekstu w miesiącu sprawdza na jaki rozmiar ustawić czcionkę dla miesiąca. Dla krótkich miesięcy wygląda to w ten sposób.

Finalna wersja kartki z kalendarza

To by było na tyle, finalna wersja biblioteki zrobiona. Noo dobra to nie jest tak do końca nomen omen koniec. Do zrobienia mam jeszcze małą aplikację demo gdzie będzie można sobie sobie wybrać kolor i datę i zobaczyć jak to wygląda (ta aplikacja trafi do sklepu Play). Do tego trzeba jeszcze zarejestrować bibliotekę tak, żeby była ogólnodostępna, oraz trochę ją wypromować, uzupełnić README na Githubie. A kod z związany z dzisiejszym wpisem dostępny jest tutaj.

W jaki sposób NFC może zautomatyzować nasze życie – DSP#17

Lubimy automatyzację. Po co przeklikiwać się przez formatki, skoro coś może dziać się samo, prawda? Jedną z rzeczy które mogą zautomatyzować nasze życie są tagi NFC. To takie fajne hardwarowe guziczki, które mogą zrobić to co chcemy. Technologia ma już kilka lat, jest bardzo przydatna, ale jednak nie stała się bardzo popularna, stąd właśnie pomysł na post, który trochę ją przybliża. Ponieważ mało kto wie, ale jest również prosta w użyciu, oraz tania – telefon z Androidem posiadającym NFC oraz TAGi, których koszt to kilka złotych (a dostępne są nawet na popularnym profilu aukcyjnym) – to wszystko czego potrzeba (iOS posiada NFC, niestety można nim tylko płacić, nie da się obsługiwać tagów, info stąd).

Breloki NFC

Breloki NFC

Technologia

Tagi NFC wyewoluowały z kart RFID które można kojarzyć np. z otwierania drzwi do biura 🙂 Chodzi mi o te karty które dostaje każdy pracownik i dzięki którym przestarzałe klamki nie muszą już być używane i podobno wpływa to na bezpieczeństwo. Nie będę się tutaj skupiał na specyfikacji technicznej i historii, ponieważ informacje o tym można bez problemu znaleźć w sieci. Tylko kilka najistotniejszych informacji.

  1. NFC nie jest wstecznie kompatybilne, czyli urządzeniem odczytującym NFC nie odczytasz, nie nagrasz RFID.
  2. Tagi mogą być odblokowane do zapisu, bądź zablokowane. Telefonem z Androidem możemy odczytać, nagrać, a także zablokować tag, ale nie da rady go później odblokować.
  3. Urządzenia korzystające dzielimy na dwie podstawowe grupy, aktywne oraz pasywne. Różnica między nimi jest taka, że pasywne nie posiadają żadnego zasilania, dlatego nie możliwa jest komunikacja na linii pasywne – pasywne, wszystkie inne drogi są jak najbardziej otwarte.
  4. Karty płatnicze również korzystają z technologii NFC, tzn, że można je odczytać! Ale zanim założymy czapeczkę z folii aluminiowej (oczywiście na naszą kartę) warto zdawać sobie sprawę z tego, że takiej odczytanej karty nie da się potem użyć, ponieważ wewnątrz nich znajduje się jeszcze jeden układ scalony który jest odpytywany – zabezpieczenie hardwarowe. W związku z tym możliwy jest tylko atak zwany przedłużeniem terminala (szczegóły tutaj). Nie mniej, jeśli przyłożysz telefon do swojej karty płatniczej, a telefon ma włączone NFC usłyszysz charakterystyczny dźwięk podłączenia. I jeśli ktoś zaszył w swojej aplikacji tą bibliotekę to co nie co może się dowiedzieć.
Nieco inne breloki NFC

Nieco inne breloki NFC

Konfiguracja

Wystarczy tej teoretycznej wiedzy, przejdźmy do działań. Ja osobiście korzystam z aplikacji Trigger, do obsługi NFC, ale sklep Play pełen jest aplikacji tego typu. ja, jak wiadomo – programuję na Androida. I tam czasem potrzeba aby ekran był cały czas włączony (ponieważ jeśli debuguje się jakąś aplikację, to jeśli telefon przygasi ekran, to uruchomi metody systemowe związane z eventem i coś się psuje).  Można głaskać telefon co 30 sekund, można wejść w ustawienia -> ekran -> wygaszanie i wybrać opcję 30 minut. Ale można też skonfigurować taga, który ustawi nam odpowiednie opcje wygaszenia. Aby to zrobić uruchamiam aplikację Trigger (proponuję od razu uruchomić triala, wystarczy do skonfigurowania wielu rzeczy, a jeśli się spodoba, a nie zdążymy zrobić wszystkiego co chcieliśmy to koszt aplikacji – 15pln), uruchamiam opcję Create a task, jako trigger wybieram NFC. Następnie znajduje się ekran specyfikujący kiedy ma działać dana akcja, w tym przypadku to jest bez znaczenia. Klikamy done i na następnym ekranie wybieramy akcję.

nfc

Warto zauważyć, że znajduje się tam też opcja Tasker -> run Task. Tasker to narzędzie do automatyzacji totalnej jeśli chodzi o Androida, jeśli nie znane to bardzo polecam, oferuje ogrom możliwości. Mnie osobiście interesuje Display -> Timeout, a także Messages -> Show Toast. Więc zaznaczam i przechodzę dalej. Wyskakuje okienko konfiguracji, wybieram opcję nigdy nie wyłączaj ekranu, oraz wpisuję wiadomość w Toast. Nadaję nazwę taska, klikam opcję dalej i mogę dodać kolejne działanie, co w tym przypadku mi się przyda, bo chcę, aby po ponownym zeskanowaniu taga ekran wracał do prawidłowych ustawień. Więc tworzę taki setup. Wyskakuje okienko nagraj. Podsuwamy taga z tyłu telefonu, charakterystyczny dźwięk i… nagrane. To tyle, wszystko gotowe, działa, można pracować. W ustawieniach aplikacji można jeszcze wyłączyć powiadomienie na pasku. Warto też tutaj zauważyć, że nie jako rozszerzyliśmy możliwości swojego telefonu, ponieważ w ustawieniach nie było możliwości nie wyłączaj ekranu w ogóle.

nfc

Wykorzystanie

Dobrze wiedzieć, że utworzoną w ten sposób instrukcję da radę odczytać tylko telefon mający zainstalowaną aplikację Trigger. Innymi słowy, jeśli zmieniacie telefon, wystarczy ponowna instalacja aplikacji, aby wszystko śmigało, schematy w razie czego można odczytać z tagów i edytować. Jednak istnieją tagi które nie wymagają instalacji tej aplikacji. Mogą przechowywać np dane kontaktowe, albo adresy email. Mogą otwierać stronę www, otwierać tworzenie wiadomości email (dyrektywa mail:to). Mam takiego przypiętego do kluczy, zamiast dyktować adres swojej strony czasem zbliżam go do czyjegoś telefonu i strona się otwiera.

nfc

Instrukcja przedstawiona powyżej dotyczyła tylko przełączania się pomiędzy czasem podświetlenia ekranu, ale nie trudno wyobrazić sobie o wiele więcej scenariuszy:

  • Włączanie WIFI, włączanie bluetooth, wyłączanie dzwonków i wyświetlanie powiadomienia „Witaj w domu mistrzu” po odczytaniu tagu przy drzwiach wejściowych, odwrotne kombo przy drugim odczytaniu (podczas wychodzenia), miałem nawet kiedyś stworzony taki tag.
  • Przywieszony przy łóżku włączający budzik i tryb nocny (np minimalne podświetlenie ekranu).
  • Przy miejscu pracy który włącza firmową pocztę i firmowy zestaw aplikacji.
  • Który znajduje się przy kluczach i aktywujemy przed bieganiem i uruchamia nam aplikację muzyczną, endomondo i co tam jeszcze potrzeba

Tak naprawdę każdą powtarzalną czynność da się otagować, aby nie musieć się przez nią przeklikiwać, tylko móc użyć zewnętrznego, hardwarowego wywołania.

naklejki NFC

naklejki NFC

Konkurs

Mam nadzieję, że macie już mnóstwo pomysłów jak można by wykorzystać takie tagi. Dlatego proponuję konkurs, rozlosuję zestaw 5szt. (do wyboru naklejek, lub breloków) wśród osób, które udostępnią ten wpis, oraz polubią moją stronę. Konkurs trwa od daty publikacji wpisu do 8 maja do godziny 23:59. Potem mogę pomóc w konfiguracji pod dowolne zadania, umowa stoi? 😉

Podsumowanie

Jak widać NFC może nam bardzo pomóc każdego dnia. Technologia jest trochę zapomniana, tym większy efekt WOW, kiedy przyłożymy komuś brelok do telefonu i powiemy niczym hakerzy z „Mission Impossible”: „Mój telefon znajduje się już w Twoich kontaktach”. A to tylko jedna możliwość, bo tak naprawdę możemy z tego standardu wyciągnąć bardzo, bardzo dużo.

Co jest trudnego w narysowaniu dwóch zaokrąglonych rogów? – DSP#16

Dzisiaj skupimy się tylko i wyłącznie na rogach w kalendarzu. Tak konkretnie, to na dwóch, znajdujących się u góry, półokrągłych.. Nie brzmi skomplikowanie, prawda? Wbrew pozorom, sprawiło mi naprawdę sporo problemu. Ale po kolei.

Te rogi były przedostatnią rzeczą którą mamy do zrobienia (ostatnią są napisy z aktualną datą), najpierw wybór rozwiązania, czyli zajrzyjmy do klasy Path, jakie oferuje sposoby rysowania kątów. Spora część zawartych tam metod doszła w API21, a aplikacja wspiera także wcześniejsze (od API15), po analizie okazało się, że najlepiej będzie zrobić to ręcznie, korzystając z metody cubicTo. No i się zaczęło 😉

Pierwsza próba wyglądała obiecująco:

path.cubicTo(startLeft, startBar, width/2, startTop, width+1, startBar)

Co jest trudnego w narysowaniu dwóch zaokrąglonych rogów?

Parametry które po kolei przyjmuje ta funkcja:

  • startowyX
  • startowyY
  • środkowyX
  • środkowyY
  • końcowyX
  • końcowyY

Ok, czyli dwa pierwsze parametry to miejsce startu rysowania, dwa środkowe to punkt odniesienia, dwa końcowe, to miejsce gdzie funkcja się kończy. Nie brzmi najgorzej.

Podejście pierwsze

Mój plan był taki:

  1. Po lewej stronie punkt styku pomiędzy obramowaniem a wysokością paska
  2. Wartość stała na wysokości paska i lewa strona
  3. Krzywa do wartości stałej na górnym pasku, środkowy parametr to róg kalendarza
  4. Prosta do drugiej wartości stałej na pasku
  5. Krzywa do wartości stałej na wysokości paska i prawej strony, prawy róg kalendarza to środkowy parametr
  6. Prosta do wysokości paska i prawej strony

Czyli podsumowując, rysowanie ciągiem od lewej do prawej strony. Musiałem zmienić ten plan. Nie zadziałała tutaj jedna rzecz, mianowicie rysując ścieżkę z osi y i skręcając w prawo odnosząc się do lewego rogu kalendarza otrzymałem inny kąt niż rysując z osi x i skręcając również w prawo, tym razem odnosząc się do prawego rogu. Gołym okiem widać było, że rogi są zupełnie różne i nie tędy droga.

Podejście drugie

Trzeba było zmienić założenia, skoro te rogi rysują się inaczej, to narysuję róg po lewej, następnie użyję metody moveTo, aby przeskoczyć na prawą stronę i narysuję róg po prawej, to zadziałało tak jak chciałem:

Co jest trudnego w narysowaniu dwóch zaokrąglonych rogów?

Więc dorysuję jeszcze tą pionową linię, znowu użyję metody moveTo, zamknę ścieżkę i skończone, prawda?

Co jest trudnego w narysowaniu dwóch zaokrąglonych rogów?

Ghrrr…

Podejście trzecie

Noo dobra, ale kąty mi się zgadzają, a to najważniejsze, więc może utworzę drugą metodę, która dorysuje mi ten brakujący trójkąt? Powinno zadziałać prawda? Geometrycznie działa, niestety wizualnie powstały artefakty (pewnie z powodu pikseli, na które musiała być przeliczona linia prosta) (poniżej powiększona grafika)

Co jest trudnego w narysowaniu dwóch zaokrąglonych rogów?

 

Podejście czwarte

Całkiem to jest zabawne prawda? Niby tylko narysowanie pół okręgu, ale ile przygód może człowieka spotkać? Noo dobra, kolejna zmiana podejścia, jak wiadomo piksele to kwadraty ułożone jeden przy drugim, w związku z tym narysujmy lewą część, a osobną ścieżką prawą część, tylko niech mają pionowe linie styku. Tym razem się wreszcie się udało. Poniżej działający kodzik.

    override fun onSizeChanged(xNew: Int, yNew: Int, xOld: Int, yOld: Int) {
        super.onSizeChanged(xNew, yNew, xOld, yOld)
        endX = xNew.toFloat()
        endY = yNew.toFloat()
        startX = paddingLeft.toFloat()
        startY = paddingTop.toFloat()
        endX -= paddingRight
        endY -= paddingTop
        barY = (endY - startY) / 6
        angleY = barY / 2
        angleX1 = startX + angleY
        angleX2 = endX - angleY
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
    }

    private fun makeBarLeftAnglePath(): Path {
        val pathLeftAngle = Path()
        pathLeftAngle.moveTo(startX, barY)
        pathLeftAngle.lineTo(startX, angleY)
        pathLeftAngle.cubicTo(startX, angleY, startX, startY, angleX1, startY)
        pathLeftAngle.lineTo(angleX2+1, startY)
        pathLeftAngle.lineTo(angleX2+1, barY)
        pathLeftAngle.close()
        return pathLeftAngle
    }

    private fun makeBarRightAnglePath(): Path {
        val pathRightAngle = Path()
        pathRightAngle.moveTo(endX + 1, barY)
        pathRightAngle.lineTo(endX + 1, angleY)
        pathRightAngle.cubicTo(endX + 1, angleY, endX + 1, startY, angleX2, startY)
        pathRightAngle.lineTo(angleX2, barY)
        pathRightAngle.close()
        return pathRightAngle
    }

Jak widać pozmieniałem też trochę nazwy zmiennych.

  • barY to wysokość paska na nosi Y
  • angleY to miejsce gdzie zaczynamy rysować kąt
  • axngleX1 to miejsce gdzie kończymy rysować kąt po lewej
  • angleX2 to miejsce gdzie kończymy rysować kąt po prawej

Podsumowując, nie wiedziałem, że po tylu latach problem sprawi mi narysowanie dwóch półokręgów w Androidzie. To była całkiem ciekawa przygoda, trochę nauczyła mnie pokory. Dlatego też ten wpis pojawia się w sobotę, ponieważ te wszystkie przygody zajęły mi o wiele więcej czasu niż myślałem. Ale cóż, tak to właśnie jest z przygodami, w następnej części zajmiemy się wyświetlaniem aktualnej daty na kalendarzu. Kod w aktualnej wersji jest dostępny na githubie.

Ten mityczny sukces – DSP#15

A czy Ty odniosłeś już sukces? Jeśli nie, to dlaczego? Czym jest ten mityczny, wymarzony, upragniony przez wszystkich sukces? A może w ogóle jest nieosiągalny i ci wszyscy mówcy motywacyjni tylko udają, że im się udało? Wpis jest nie jako rozwinięciem wpisu o piekle motywacji sprzed kilku tygodni, polecam się z nim zapoznać, żeby wyrobić sobie kontekst dla tego co będzie poniżej.

tl;dr -> patrz podsumowanie

Jak zmierzyć sukces?

To jest bardzo ważne pytanie na początek. W jaki sposób zmierzyć sukces? Zastanawiałeś się kiedyś co jest dla Ciebie sukcesem? Czy jest to może 15k na koncie co miesiąc, czy coś innego? Dochodzimy tutaj do bardzo ważnej rzeczy, mianowicie nie da się zrobić czegoś, co jest.. niezdefiniowane? Kilkukrotnie podchodziłem do kanału Miroburn i jego subskrypcji YouTube, materiały wrzucane codziennie muszą być dobre, jeśli decyduję się poświęcić na nie czas. I faktycznie, idzie mu to coraz lepiej i mnie przekonał, ja subskrybuję. Ale Mirek ma jeszcze jedną fajną rzecz, jest to strona trzypoziomy.pl. Już wiesz do czego zmierzam? Każdy sukces musi być konkretnie oznaczony, najlepiej z deadlinem. Dlatego też sukcesem nie jest zarabiać dużo pieniędzy. Sukcesem jest zarabiać 15k co miesiąc przez rok, jeśli w ten właśnie sposób definiujesz swoje „dużo pieniędzy”. A sukces zawodowy? Kiedy go osiągamy? Który awans jest tym ostatecznym sukcesem zawodowym? Czy to nie jest tak, że każdy kolejny awans, no ok, ale to tylko krok.. A latka lecą. Ale oto już za rogiem, już niedaleko czeka na nas ten mityczny sukces?

Ten mityczny sukces

Wystarczy zamienić koniec projektu na sukces i wszystko się zgadza.

Czy potrafisz wymienić swoje sukcesy?

Akapit powyżej to opis metody zarządzania znanej jako smart, tylko zamieniłem cel na sukces. Bieżący akapit jest ważny. Co z sukcesami które osiągnąłeś? Jesteś w stanie wymienić z głowy, albo może masz spisane.. jakiekolwiek? Noo właśnie.. To trochę przykro, że coś udaje się osiągnąć, wdrapuje się na jakąś górkę i zamiast wbić swój sztandar.. Zasuwa się dalej. Jeśli chodzi o mnie, to jeśli przewiniesz do góry, jest timeline (który muszę zaktualizować w ogóle). Albo nie, nie przewijaj, masz linka 😉 Mam tam rozpisane na linii czasu rzeczy które udało mi się osiągnąć. Jest to tylko półśrodek, myślę o czymś lepszym, w stylu moja własna „Hall of fame”, (żebym nie tylko zostawiał sztandar na każdej górce, ale budował własny fort), gdzie wszystko będzie opisane dokładnie. Ale to jest na liście pomysłów póki co. A jak wygląda to u Ciebie?

Ten mityczny sukces

Zdobyte certyfikaty to również Twoje sukcesy. Więc dlaczego nie wiszą na ścianie, żebyś codziennie mógł być z siebie dumny? Niestety powyższe zdjęcie, to rzadko spotykany widok.

Sukces maleje z czasem?

Patrząc wstecz i z całych sił starając się sobie przypomnieć co udało się osiągnąć zaczynamy dostrzegać małe, nieistotne coś, co wtedy nazwalibyśmy sukcesem. Ale dziś już nie. W temacie certyfikatów, pewnie każdy ma dyplom pasowania na ucznia z podstawówki. Śmieszne, prawda, nic nie znaczące? Ale gdybyśmy w podstawówce nie nauczyli się dodawać i mnożyć, to nigdy nie ukończyli byśmy studiów zdobywając tytuł inżyniera, prawda? Sukces się nie dezaktualizuje, po prostu z czasem wydaje nam się mały i nic nie znaczący. Ale to nic, wtedy liczenie i czytanie kosztowało nas sporo wysiłku, tak jak w tym momencie sporo wysiłku kosztuje nas zdobywanie kolejnych umiejętności. Warto zdawać sobie z tego sprawę, że za każdym sukcesem stoi jakiś wysiłek. I to właśnie on tak naprawdę jest dokumentowany przez sukces, a nie to, co tak naprawdę osiągnęliśmy.

Ten mityczny sukces

Żeby nie było 😉

Małe kroki

Jakiś czas temu Gutek zaczął wrzucać na swój profil facebookowy trzy rzeczy, które udały mu się danego dnia. To jest naprawdę świetny pomysł. Każdego wieczoru napisz co Ci się udało, w ciągu roku uzbiera się ponad tysiąc sukcesów, to więcej niż niejeden mówca motywacyjny! 😉 A tak serio, metoda małych kroczków jest dobra. Za każdym razem kiedy osiągniesz, cokolwiek choćbyś uczył się html i stworzył stronę z samouczka, to jest Twój sukces. Szanuj go i na nim buduj kolejne.

Ten mityczny sukces

Stockowa fotografia małych kroków, musi być, żeby wpis wyglądał pro.

Podsumowanie

Podsumowując, wszystko może być Twoim sukcesem, ale ważne jest, żeby być tego świadomym. Sukces jest wtedy kiedy coś sobie założysz, określisz ramy czasowe i zadaniowe, oraz doprowadzisz tą sprawę do końca tak jak chciałeś. A potem sobie to zapisz, najlepiej w widocznym miejscu i patrz na efekty swojej pracy często, a najlepiej codziennie. Eksponuj swój sukces, bo on pokazuje nie tylko to, czego dokonałeś, ale również to, ile pracy Cię to kosztowało.

Postscriptum

Wracając jeszcze do ściany dyplomów, mam jeszcze jedną myśl na ten temat. Z racji tego, że ostatnio urodziła mi się córa często bywam w laboratorium, krew, mocz, te historie. I spośród kilku w okolicy wybrałem to, w którym wszedłem i mogłem poczytać o ich osiągnięciach, bo w poczekalni mają ich całą ścianę. To naprawdę wygląda profesjonalnie, widzę, że starają się dbać o jakość swoich usług i ciągle uczą się czegoś nowego. Dalej było już tylko lepiej, pełen profesjonalizm i z czystym sumieniem mogę polecić SanteLab Wrocław, pomimo, że nikt mi za tą rekomendację nie zapłacił. Ale w mojej opinii, widać pasję, profesjonalizm, zaangażowanie w to co robią. I to widać od samego wejścia.

Nowe wymiary, ścieżki w Androidzie – DSP#14

Dzisiaj skupimy się na tym, jak rysować niestandardowe elementy w klasie View. Tzn, będziemy rysowali standardowe (póki co), ale w niestandardowy sposób, a konkretnie korzystając ze ścieżek. Zapraszam!

Ścieżki w Amdroidzie, czyli obiekty typu Path są tworzone ze zbioru kolejnych punktów. Na szczęście nie musimy ich kolejno wpisywać, możemy też użyć metod typu moveTo (przesunięcie), lineTo (narysowanie linii od miejsca gdzie się znajdujemy do podanych punktów), czy arcTo(narysowanie łuków), close (prowadzi do punktu gdzie zaczęliśmy) oraz podobnych. Dlatego też na początek skupmy się na nadaniu właściwych lokalizacji w naszym kalendarzu. Efekt wygląda tak:

Nowe wymiary, ścieżki w Androidzie - DSP#14

Z kolei kodzik potrzebny do narysowania, w ten sposób:

    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)
        canvas?.drawPath(makeBackgroundPath(), backgroundPaint)
        canvas?.drawPath(makeBorderPath(), borderPaint)
        canvas?.drawPath(makeBarPath(), barPaint)
    }

    override fun onSizeChanged(xNew: Int, yNew: Int, xOld: Int, yOld: Int) {
        super.onSizeChanged(xNew, yNew, xOld, yOld)
        width = xNew.toFloat()
        height = yNew.toFloat()
        startLeft = paddingLeft.toFloat()
        startTop = paddingTop.toFloat()
        width -= paddingRight
        height -= paddingTop
        startBar = height / 6
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
    }

    private fun makeBarPath(): Path {
        val path = Path()
        path.moveTo(startLeft, startBar)
        path.lineTo(startLeft, startTop)
        path.lineTo(width + 1, startTop)
        path.lineTo(width + 1, startBar)
        path.close()
        return path
    }

    private fun makeBorderPath(): Path {
        val path = Path()
        path.moveTo(startLeft, startBar)
        path.lineTo(startLeft, height)
        path.lineTo(width, height)
        path.lineTo(width, startBar)
        return path
    }

    private fun makeBackgroundPath(): Path {
        val path = makeBorderPath()
        path.close()
        return path
    }

Jak widać zaczyna to już powoli przypominać kształtem kalendarz. A co się tu dzieje? W metodzie onDraw() na płótnie zostaje wywołana metoda drawPath(), która oznacza rysowanie ścieżki między punktami. Za te ścieżki odpowiadają metody make, w których po kolei dokłada się do nich element. Jak widać ścieżka dla tła różni od ścieżki do obrysowywania tylko tym, że została zamknięta, dzięki temu tło będzie wypełnione i obramowane z trzech stron, z kolei do góry będzie znajdował się pasek. Dziwić mogą te wartości +1 i mówiąc szczerze, mnie też dziwią. Powstała przy rysowaniu mała niedokładność (być może wynikająca z Paint.STROKE), która sprawiała że obrysowanie wystawało o jeden piksel w prawo. Poprawiłem więc szerokość paska aby się dopasował. Ustawiłem nawet wymuszenie układu ekranu z prawej do lewej, żeby sprawdzić jak to się zachowa, ale wyglądało w porządku. W związku z czym zostawiam to przesunięcie o jeden piksel, ponieważ usuwa ono wizualny artefakt. Z pozostałych zmian od poprzedniej wersji, ustawiłem szerokość obramowania na jeden piksel (takie były założenia od początku, po prostu celem testów ta linia była szeroka), a także poprawiłem trochę obliczanie szerokości i wysokości, poprzednim razem podwójnie ucinał obraz z prawej strony. Doszła też nowa wartość startBar według której obliczane są wysokości dokąd namalować tło, oraz odkąd malować pasek. I to działa, bo jeśli usuniemy sobie metodę odpowiedzialną za rysowanie paska otrzymamy taki efekt:

Nowe wymiary, ścieżki w Androidzie - DSP#14

Zmiany do tego momentu są zaccomitowane jako paths.

To tyle na dzisiaj, dosyć krótko, ale zbliża się koniec konkursu, a do zrobienia zostało już tylko kilka elementów. W ramach rekompensaty zapraszam na kolejny post który pojawi się w ciągu 5 minut 😉 Będzie zdecydowanie dłuższy i ciekawszy. A w następnym poście projektowym obsłużymy odpowiednio zagięcia w rogach kalendarza, oraz dodamy wyświetlanie daty na środku.

Jak wykorzystać sztuczną inteligencję do rysowania, autodraw – DSP#13

Nigdy nie byłem szczególnie uzdolniony plastycznie. Już od czasów podstawówki moje oceny z plastyki jakoś szczególnie nie imponowały. Nie to, że nie chciałem ślicznie rysować, po prostu nie potrafiłem. Przyzwyczaiłem się do tego, świat wokół mnie również się przyzwyczaił. Było nam z tym dobrze, ale oto ostatnio pojawiło się coś, co zupełnie łamie zasady. I podoba mi się!

Autodraw

Z racji tego, że rozmawiamy o rysowaniu, to ja może pokażę, jak narysować samochód w czterech krokach:

Jak wykorzystać sztuczną inteligencję do rysowania, autodraw

Czyli rysujemy jedno koło, następnie drugie koło, karoserię i… wybieramy interesujący nas samochód. Kto narysował by właśnie w ten sposób? Jak widać, da się tutaj odnaleźć pewien schemat.. Narzędzie które tutaj opisuję nazywa się Autodraw i jest dostępne tutaj. Autodraw nie dlatego, że pozwala narysować tylko samochód, ale dlatego, że pozwala narysować bardzo dużo rzeczy w automatyczny sposób.

Jak wykorzystać sztuczną inteligencję do rysowania, autodraw

Całość działa w ten sposób, że na podstawie tego jak użytkownicy rysują daną rzecz program dedukuje co użytkownik miał na myśli i podpowiada gotowe rozwiązanie. Ale skąd program wie, jak użytkownicy rysują np ciastko, sklep, czy fortepian?

Quick, draw!

Tutaj należy wspomnieć o drugim eksperymencie Google, który jest dostępny o wiele dłużej. Nazywa się Quick, draw, podziałać w nim można w tym miejscu. Działa w ten sposób:

Jak wykorzystać sztuczną inteligencję do rysowania, autodraw

Dostajemy polecenie narysowania czegoś, a następnie sztuczna inteligencja musi rozpoznać co narysowaliśmy. Z racji tego, że projekt jest ogólnoświatowy powstaje tam sporo rysunków.

Jak wykorzystać sztuczną inteligencję do rysowania, autodraw

Na podstawie których jest prowadzone wnioskowanie w jaki sposób ludzie rysują konkretne przedmioty. I to podejrzewam stąd pochodzą dane do programu Autodraw.

Więcej

Piszę o tym z kilku powodów, po pierwsze uważam narzędzie Autodraw za bardzo przydatne. To jest bardzo fajny pomysł, żeby mój bohomaz przekształcić w coś ładnie narysowanego. Po drugie, mamy tutaj bardzo ciekawe zastosowanie sztucznej inteligencji, która uczy się jak ludzie rysują i na tej podstawie podpowiada konkrety. Więcej przykładów zabaw z AI można znaleźć np na tej stronie.

Reasumując, mam nadzieję, że z aplikacji Autodraw zacznę korzystać regularnie. Rozwiązuje jeden z moich problemów, czyli całkowity brak umiejętności rysowania. Myślę, że Tobie również się przyda. Dzięki za uwagę!

Jak wykorzystać sztuczną inteligencję do rysowania, autodraw