├── .gitignore ├── .gitmodules ├── .htaccess ├── .imgbotconfig ├── .vscode └── settings.json ├── README.md ├── config.toml ├── content ├── about.md └── post │ ├── 2012 │ ├── autocompletebox-for-windows-store-apps │ │ └── index.md │ ├── being-a-polyglot-programmer │ │ └── index.md │ ├── computing-hashes-in-winrt │ │ └── index.md │ ├── converting-hex-color-to-solidcolorbrush │ │ └── index.md │ ├── customizing-semantic-zoom-in-windows-8-apps │ │ └── index.md │ ├── encoding-two-ints-into-a-long-to-be-used-as-navigation-parameter │ │ └── index.md │ ├── fast-way-to-check-if-a-file-exists-in-winrt │ │ └── index.md │ ├── fun-with-f-type-providers-sql │ │ └── index.md │ ├── how-to-uniquely-identify-a-windows-8-device │ │ └── index.md │ ├── htc-8x-windows-phone-8-and-playing-music │ │ └── index.md │ ├── loading-xaml-components-at-runtime │ │ └── index.md │ ├── monotouch-ios-development-for-net-programmers │ │ ├── index.md │ │ └── monotocuh.png │ ├── processing-json-in-net │ │ └── index.md │ ├── store-region-messed-up-in-windows-phone-8 │ │ └── index.md │ ├── tampering-with-windows-store-apps-data │ │ └── index.md │ ├── updating-azure-toolkit-is-always-a-pain │ │ └── index.md │ ├── using-different-data-templates-with-gridview-in-windows-8-apps │ │ └── index.md │ ├── using-net-libraries-with-monotouch │ │ └── index.md │ ├── welcome │ │ └── index.md │ └── why-i-do-not-like-windows-phone-programming-anymore │ │ └── index.md │ ├── 2013 │ ├── appharbor-great-place-to-start-your-net-project │ │ └── index.md │ ├── beware-of-removing-localizations-from-your-windows-phone-apps │ │ └── index.md │ ├── creating-a-search-box-with-reactive-extensions-and-mvvm │ │ └── index.md │ ├── detecting-encoding-of-uploaded-file-in-asp-net-mvc │ │ └── index.md │ ├── developing-windows-store-apps-with-caliburn-micro-part-1-setup-and-first-view │ │ └── index.md │ ├── developing-windows-store-apps-with-caliburn-micro-part-2-navigation │ │ └── index.md │ ├── developing-windows-store-apps-with-caliburn-micro-part-3-saving-and-restoring-state │ │ └── index.md │ ├── developing-windows-store-apps-with-caliburn-micro-part-4-services-and-dependency-injection │ │ └── index.md │ ├── displaying-pdf-files-in-windows-store-apps │ │ └── index.md │ ├── do-you-need-to-create-a-special-windows-phone-8-build-of-your-windows-phone-app │ │ ├── index.md │ │ └── wp7header.png │ ├── f-on-azure-using-table-storage-for-logging │ │ └── index.md │ ├── few-thoughts-about-the-windows-phone-store-certification-process │ │ └── index.md │ ├── generating-all-permutations-of-a-list-how-hard-can-that-be │ │ └── index.md │ ├── getting-paid-for-your-windows-phone-apps-is-a-real-pain │ │ └── index.md │ ├── inotifypropertychanged-the-easy-way-in-windows-phone-and-windows-8 │ │ └── index.md │ ├── intercepting-methods-with-ninject-for-error-logging │ │ └── index.md │ ├── my-windows-phone-and-windows-8-mini-libraries │ │ └── index.md │ ├── reading-excel-sheets-using-f-without-com │ │ └── index.md │ ├── returning-files-in-nancyfx │ │ └── index.md │ ├── succinctly-series-of-free-books-for-programmers │ │ └── index.md │ ├── useful-tools-for-windows-store-developers │ │ └── index.md │ ├── using-custom-fonts-in-windows-phone-apps │ │ └── index.md │ ├── using-sublime-text-2-as-f-repl │ │ └── index.md │ ├── using-the-debuggerdisplay-attribute-for-better-debugging-experience │ │ ├── debug1.png │ │ ├── debug2.png │ │ └── index.md │ ├── visual-studio-achievements-a-bit-of-gamification-to-your-programming │ │ ├── VisualStudio_badges_2.jpg │ │ └── index.md │ ├── why-are-there-no-great-windows-8-apps-because-of-winrt-a-developers-view │ │ ├── index.md │ │ └── microsoft-surface-2-650x0.jpg │ ├── why-you-should-not-use-windows-store-for-in-app-purchases │ │ └── index.md │ ├── windows-phone-run-background-agent-every-minute │ │ └── index.md │ └── windows-store-limits-the-number-of-in-app-purchases-for-an-app │ │ └── index.md │ ├── 2014 │ ├── automatic-viewmodels-and-services-registration-for-not-only-caliburn-micro │ │ └── index.md │ ├── building-windows-phone-apps-with-fake │ │ └── index.md │ ├── c-scripting-console-for-asp-net-mvc-application │ │ └── index.md │ ├── changing-the-pivotitem-header-color-in-windows-phone-8-1-xaml │ │ ├── header78.png │ │ ├── header81.png │ │ └── index.md │ ├── converting-between-pixels-meters-and-map-coordinates-in-windows-phone │ │ ├── image_thumb_4_4.png │ │ └── index.md │ ├── crawling-mobile-app-stores-with-f │ │ └── index.md │ ├── creating-a-fake-splashscreen-for-your-universal-app │ │ └── index.md │ ├── detecting-tablets-and-smartphones-in-asp-net │ │ └── index.md │ ├── dialog-helper-for-universal-apps │ │ └── index.md │ ├── experience-with-being-featured-in-the-red-stripe-deal-promotion-on-windows-phone │ │ ├── index.md │ │ └── sk.png │ ├── free-services-to-help-you-develop-mobile-apps │ │ └── index.md │ ├── getting-contacts-on-windows-phone-the-asyncawait-way │ │ └── index.md │ ├── how-to-get-rid-of-the-strange-line-under-systray-in-windows-phone-8 │ │ ├── index.md │ │ └── line.png │ ├── ignoring-certificate-errors-in-windows-phone-8-1 │ │ └── index.md │ ├── making-your-windows-phone-silverlight-8-1-app-a-share-contract-target │ │ ├── index.md │ │ └── wp81.png │ ├── pock8-beautiful-pocket-client-for-windows-phone │ │ ├── index.md │ │ └── pocket.png │ ├── rest-service-base-class-for-windows-phone-8-1-xaml-apps │ │ └── index.md │ ├── testing-in-app-purchases-in-windows-phone │ │ └── index.md │ ├── tvtime-track-your-favorite-tv-shows-on-windows-phone │ │ ├── index.md │ │ └── tvtimepromo.jpg │ ├── visual-studio-template-for-caliburn-micro-windows-phone-apps │ │ └── index.md │ ├── what-to-put-on-the-about-screen-of-your-windows-phone-app │ │ ├── about1.png │ │ ├── about2.png │ │ └── index.md │ └── why-universal-apps-as-not-as-universal-as-you-may-think │ │ ├── 56995992.jpg │ │ └── index.md │ ├── 2015 │ ├── a-week-with-microsoft-band-2 │ │ ├── BandDashboard1.png │ │ ├── BandDashboard2.png │ │ ├── BandDisplay.jpg │ │ ├── BandGPS.png │ │ ├── BandSetup.png │ │ ├── BandSleep1.png │ │ ├── BandSleep2.png │ │ ├── BandSteps.png │ │ ├── BandUI1.png │ │ ├── BandUI2.png │ │ └── index.md │ ├── automatically-push-your-git-repos-before-computer-shutdown │ │ └── index.md │ ├── back-navigation-on-backspace-key-press-in-windows-8-1-apps │ │ └── index.md │ ├── custom-datetime-deserialization-with-json-net │ │ └── index.md │ ├── customizing-the-player-framework-ui │ │ └── index.md │ ├── detecting-gestures-over-webview-on-windows-phone │ │ └── index.md │ ├── enabling-and-disabling-hardware-devices-with-powershell │ │ └── index.md │ ├── going-static-from-wordpress-to-hugo │ │ └── index.md │ ├── highlighting-letters-in-textblock-in-windows-phone-8-1-and-windows-8-1 │ │ ├── highlighting.png │ │ └── index.md │ ├── implementing-google-login-in-universal-apps │ │ └── index.md │ ├── lenovo-why-do-you-screw-thinkpads-with-every-update │ │ └── index.md │ ├── leveraging-etag-caching-in-windows-phone-and-windows-apps │ │ └── index.md │ ├── measuring-and-recording-the-room-temperature-with-a-raspberry-pi │ │ ├── index.md │ │ ├── pi-history.png │ │ ├── pi-ui.png │ │ └── pitherm.jpg │ ├── mobilize-net-converting-windows-phone-apps-to-uwp │ │ ├── Windows10-Devices.png │ │ └── index.md │ ├── my-year-with-the-raspberry-pi-and-what-i-used-it-for │ │ ├── index.md │ │ ├── pi-ui.png │ │ └── pitherm.jpg │ ├── nancyfx-authentication-for-rest-api │ │ └── index.md │ ├── player-framework-localization │ │ └── index.md │ ├── problems-getting-paid-from-the-windows-store-again │ │ ├── index.md │ │ └── payout.png │ ├── quick-tip-showing-solution-branch-name-in-visual-studio-title │ │ ├── index.md │ │ ├── rename.png │ │ └── trayalya.png │ ├── removing-unused-strings-from-windows-phone-8-resx-files │ │ └── index.md │ ├── strange-combination-of-https-and-windows-phone-8-1-that-can-make-your-app-and-phone-freeze │ │ └── index.md │ ├── the-death-of-the-winrt-developer │ │ └── index.md │ ├── the-sad-state-of-dvlup-ms-tech-rewards │ │ └── index.md │ ├── using-etag-to-cache-responses-in-nancyfx │ │ └── index.md │ └── visual-studio-extensions-to-make-your-life-easier │ │ ├── asyncfixer-1.gif │ │ ├── guides.png │ │ ├── index.md │ │ ├── trayalya.png │ │ └── vscoloroutput.png │ ├── 2016 │ ├── about-the-decline-in-software-quality │ │ └── index.md │ ├── application-deployment-with-nsis-and-squirrel │ │ └── index.md │ ├── choosing-and-image-from-gallery-or-camer-in-uwp │ │ ├── index.md │ │ ├── uwp.gif │ │ ├── uwp2.gif │ │ └── wpa81.gif │ ├── creating-a-simple-windows-10-game-with-win2d │ │ ├── index.md │ │ ├── sokoban-dpad.png │ │ └── sokoban-gameplay.gif │ ├── creating-better-forms-in-windows-phone-apps │ │ ├── forms1.gif │ │ ├── forms2.gif │ │ └── index.md │ ├── fixing-first-annoyances-with-bash-on-windows │ │ ├── bash-cmder.png │ │ └── index.md │ ├── hacking-a-mobile-api-and-how-to-protect-yourself │ │ └── index.md │ ├── how-to-handle-localization-strings-provided-by-client │ │ ├── index.md │ │ └── languages.png │ ├── using-hockey-app-to-distribute-windows-phone-apps │ │ └── index.md │ └── using-tooltips-to-make-better-menus-in-windows-apps │ │ ├── index.md │ │ └── tooltips.gif │ ├── 2017 │ ├── changing-navigation-vs-tabbar-title │ │ └── index.md │ ├── creating-a-tv-schedule-grid-in-uwp │ │ ├── index.md │ │ └── tvgrid.gif │ ├── creating-animations-of-your-apps │ │ └── index.md │ ├── creating-navigationbar-dropdown-menu │ │ ├── dropdown.gif │ │ └── index.md │ ├── delaying-disqus-comments-to-save-requests │ │ ├── disqus.png │ │ └── index.md │ ├── filling-uitableview-from-bottom-top │ │ └── index.md │ ├── fixing-black-artifact-changing-large-tiles-mode │ │ ├── blackartifact.gif │ │ ├── index.md │ │ └── noartifact.gif │ ├── fixing-iphone-usb-tethering-on-macos │ │ ├── index.md │ │ └── tethering.png │ ├── formatting-swift-code-in-xcode │ │ ├── index.md │ │ └── swiftformat.png │ ├── generating-a-list-of-libraries-your-ios-app-uses │ │ ├── index.md │ │ └── licenses.gif │ ├── making-tableview-header-stickier │ │ ├── index.md │ │ └── stickyheader.gif │ ├── more-readable-xcodebuild-output │ │ ├── index.md │ │ ├── xcodebuild.png │ │ ├── xcpretty.png │ │ └── xcprettytests.png │ ├── my-experience-running-a-hackintosh │ │ ├── hackintosh.png │ │ └── index.md │ ├── my-experience-with-swift-after-9-months │ │ ├── index.md │ │ └── swift.png │ ├── my-experience-with-the-mvp-awards │ │ └── index.md │ ├── prevent-windows-drives-from-being-mounted-on-macos │ │ └── index.md │ ├── resigning-ios-apps │ │ ├── easyresigny.png │ │ └── index.md │ ├── simpler-and-safer-custom-cells │ │ └── index.md │ ├── solving-problems-after-mbr2efi │ │ └── index.md │ ├── using-data-binding-in-ios │ │ ├── index.md │ │ └── iosvalidation.gif │ ├── using-macos-with-a-windows-keyboard │ │ ├── index.md │ │ ├── macoskeymapping.png │ │ └── volumeshortcuts.png │ ├── using-mvvm-with-tables-in-ios │ │ ├── index.md │ │ └── iostablemvvm.gif │ ├── using-protocol-default-implementation │ │ └── index.md │ ├── using-vscode-as-git-merge-tool │ │ ├── index.md │ │ ├── merge-conflict.png │ │ └── tower-merge.png │ ├── workaround-for-didreceiveremotenotification-not-called-in-ios11 │ │ └── index.md │ └── xcode-wireless-debugging │ │ ├── index.md │ │ └── wifideploy.png │ ├── 2018 │ ├── add-mobile-iron-to-swift-app │ │ ├── index.md │ │ └── mobileiron.png │ ├── animating-tab-bar-buttons │ │ ├── index.md │ │ ├── tw-animation.gif │ │ └── twitter-animation.gif │ ├── architecting-ios-apps-coordinators │ │ ├── coordinators.png │ │ └── index.md │ ├── automating-ios-development-and-distribution-workflow │ │ ├── automate.png │ │ ├── fastlane_badge.png │ │ └── index.md │ ├── building-ios-depedencies-with-carthage │ │ ├── carthage-logo.png │ │ └── index.md │ ├── checking-for-missing-translations-in-ios │ │ ├── index.md │ │ └── verify-string-files-error.png │ ├── creating-your-own-xcode-templates │ │ ├── XcodeTemplates.png │ │ └── index.md │ ├── logging-ios-app-crashes │ │ └── index.md │ ├── unit-testing-memory-leaks │ │ └── index.md │ ├── using-clonezilla-for-hackintosh-backups │ │ ├── clonezilla.jpg │ │ └── index.md │ ├── using-ios-strings-in-a-safer-way │ │ ├── index.md │ │ └── iosstrings.png │ ├── workaround-for-faded-navbar-button │ │ ├── index.md │ │ └── ios112bug.gif │ └── writing-a-pascal-interpreter-in-swift │ │ ├── factorial.gif │ │ ├── index.md │ │ ├── lexer.png │ │ ├── parser.png │ │ └── playground.png │ ├── 2019 │ ├── adding-wifi-and-bluetooth-for-apple-features-to-hackintosh │ │ ├── card.jpg │ │ └── index.md │ ├── change-uiapplication-class │ │ └── index.md │ ├── changing-uialertaction-text-color │ │ ├── color.png │ │ ├── default.png │ │ └── index.md │ ├── creating-bootable-macos-backups │ │ ├── BootedBackup.png │ │ ├── Clone.png │ │ ├── Formatting.png │ │ ├── Schedule.png │ │ ├── index.md │ │ └── logo.png │ ├── creating-context-menu-with-highlight │ │ ├── DimEffect.png │ │ ├── HighlightEffect.png │ │ ├── Menu.png │ │ ├── TransparentWindow.png │ │ ├── animation.gif │ │ └── index.md │ ├── debugging-ios-network-traffic │ │ ├── cert.png │ │ ├── index.md │ │ ├── logo.png │ │ ├── mitmweb.png │ │ ├── proxy.png │ │ └── trust.png │ ├── detecting-click-on-a-nstableviewcell │ │ └── index.md │ ├── editing-macos-app-about-dialog │ │ ├── default-dialog.png │ │ ├── dialog.png │ │ └── index.md │ ├── faster-way-to-download-and-install-xcode │ │ ├── index.md │ │ ├── more.png │ │ └── xcode-icon-17.jpg │ ├── making-copy-paste-work-with-nstextfield │ │ └── index.md │ ├── simple-bindable-no-data-placeholder │ │ └── index.md │ ├── switching-my-hackintosh-from-nvidia-to-amd │ │ ├── index.md │ │ ├── logo.jpg │ │ └── mojave.png │ ├── using-pods-to-just-build-frameworks │ │ ├── index.md │ │ └── logo.png │ └── why-ios-gestures-lag-at-the-screen-edges │ │ ├── index.md │ │ ├── quick-recording-bottom.png │ │ └── quick-recording-middle.png │ ├── 2020 │ ├── animating-annotation-position-change-on-ios │ │ ├── MapJump.gif │ │ ├── MapSmooth.gif │ │ └── index.md │ ├── clustering-annotations-in-mkpampview │ │ ├── MapCluster.png │ │ └── index.md │ ├── converting-slow-motion-video-to-url-asset │ │ └── index.md │ ├── dealing-with-memory-limits-in-app-extensions │ │ └── index.md │ ├── determining-which-frameworks-use-uiwebview │ │ └── index.md │ ├── different-git-config-for-work-projects │ │ └── index.md │ ├── few-reasons-mkmapview-crashes │ │ └── index.md │ ├── generating-boilerplate-swift-code │ │ ├── BuildPhase.png │ │ └── index.md │ ├── logging-error-messages-from-assert-and-fatalerror │ │ └── index.md │ ├── using-custom-annotation-views-in-mkmapview │ │ ├── LiveLocationMap.jpg │ │ └── index.md │ ├── using-intel-wifi-bt-on-macos │ │ ├── BT.png │ │ ├── HeliPort.png │ │ ├── index.md │ │ └── itlwm_manual.png │ ├── web-scraping-with-swift │ │ └── index.md │ ├── workaround-for-swift-scripts-crash │ │ ├── Swift_logo.png │ │ └── index.md │ └── xcode-build-times │ │ ├── buildtimes.png │ │ └── index.md │ ├── 2021 │ ├── automatically-merge-xcode-project-conflicts │ │ ├── index.md │ │ └── kintsugi.png │ ├── dealing-with-microsoft-in-wp-times │ │ ├── e15.jpg │ │ ├── hn.jpg │ │ ├── index.md │ │ ├── lumia.jpg │ │ ├── tvtime.jpg │ │ ├── win8konference.png │ │ └── windows8.png │ ├── graying-out-images │ │ ├── flags-original.png │ │ ├── flags.png │ │ └── index.md │ ├── parallel-ui-test-runs │ │ └── index.md │ └── reading-environment-variables-from-unit-tests │ │ ├── index.md │ │ └── scheme.png │ ├── 2022 │ ├── correctly-playing-audio-in-ios-apps │ │ └── index.md │ └── using-swiftlint-for-gitlab-code-quality │ │ ├── index.md │ │ └── quality.png │ ├── 2023 │ ├── a-few-xcode-debugging-tips │ │ ├── didLoadBreakpoint.png │ │ ├── form.png │ │ ├── index.md │ │ └── return.png │ ├── tableviews-with-reorder-and-selection │ │ ├── index.md │ │ ├── reorder1.gif │ │ └── reorder2.gif │ └── using-critical-alerts-on-ios │ │ ├── alert.png │ │ ├── critical.jpg │ │ ├── index.md │ │ ├── notifications.jpg │ │ └── settings.png │ ├── 2024 │ ├── custom-areas-in-snapshots │ │ ├── index.md │ │ ├── locationAttachment.png │ │ └── locationAttachmentArea.png │ └── use-openvn-as-proxy │ │ ├── firefox.png │ │ └── index.md │ └── 2025 │ ├── migrate-pods-to-local-spm-in-monorepo │ └── index.md │ └── vscode-ios-setup │ ├── afterbuild.png │ ├── build.png │ ├── copilot.png │ ├── debugging.png │ ├── debugsetup.png │ ├── generateconfig.png │ ├── index.md │ └── selectworkspace.png ├── layouts ├── _default │ └── _markup │ │ └── render-image.html ├── robots.txt ├── rss.xml ├── shortcodes │ ├── github-repo.html │ └── vimeo.html └── sitemap.xml ├── netlify.toml ├── screenshot.png ├── static ├── _headers ├── _redirects ├── android-chrome-192x192.png ├── android-chrome-384x384.png ├── apple-touch-icon.png ├── browserconfig.xml ├── css │ └── custom.css ├── favicon-16x16.png ├── favicon-32x32.png ├── favicon.ico ├── images │ └── avatar.jpg ├── mstile-150x150.png ├── safari-pinned-tab.svg └── site.webmanifest └── themes └── hugo-paper ├── .gitignore ├── LICENSE ├── README.md ├── assets ├── app.css ├── custom.css └── main.css ├── i18n ├── ar.yaml ├── az.yaml ├── be.yaml ├── bn.yaml ├── de.yaml ├── en.yaml ├── es.yaml ├── fa.yaml ├── fr.yaml ├── he.yaml ├── id.yaml ├── it.yaml ├── ja.yaml ├── ko.yaml ├── oc.yaml ├── pl.yaml ├── pt.yaml ├── ru.yaml ├── sw.yaml ├── tr.yaml └── zh.yaml ├── images ├── pagespeed.png ├── screenshot.png ├── screenshot_dark.png ├── screenshot_mobile.png └── tn.png ├── layouts ├── 404.html ├── _default │ ├── baseof.html │ ├── list.html │ └── single.html ├── partials │ ├── footer.html │ ├── head.html │ ├── header.html │ ├── math.html │ └── mermaid.html └── shortcodes │ └── collapse.html ├── static ├── apple-touch-icon.png ├── bluesky.svg ├── favicon.ico ├── github.svg ├── highlight.min.js ├── instagram.svg ├── linkedin.svg ├── mastodon.svg ├── rss.svg ├── theme.png ├── theme.svg ├── threads.svg └── twitter.svg └── theme.toml /.gitignore: -------------------------------------------------------------------------------- 1 | /dploy.yaml 2 | /public 3 | /resources/_gen 4 | .DS_Store 5 | .hugo_build.lock 6 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/.gitmodules -------------------------------------------------------------------------------- /.htaccess: -------------------------------------------------------------------------------- 1 | RewriteEngine On 2 | RewriteBase / 3 | 4 | RewriteCond %{HTTP:X-Forwarded-Proto} =http 5 | RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301] 6 | 7 | RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC] 8 | RewriteRule ^(.*)$ https://%1/$1 [R=301,L] -------------------------------------------------------------------------------- /.imgbotconfig: -------------------------------------------------------------------------------- 1 | { 2 | "ignoredFiles": [ 3 | "*.svg" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "cSpell.enabled": true 3 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Coding Journal 2 | 3 | ![Hugo](https://img.shields.io/badge/Static%20site%20generator-Hugo-brightgreen.svg) 4 | ![Hosting](https://img.shields.io/badge/Hosting-Netlify-red.svg) 5 | [![Twitter](https://img.shields.io/badge/twitter-@igorkulman-blue.svg)](http://twitter.com/igorkulman) 6 | 7 | Source code for my programming blog located at [blog.kulman.sk](https://blog.kulman.sk). 8 | 9 | [![Coding Journal](screenshot.png)](https://blog.kulman.sk) 10 | 11 | ### Built With 12 | 13 | * [Hugo](http://gohugo.io) - Static site generator 14 | * [Paper](https://github.com/nanxiaobei/hugo-paper) - Theme 15 | * [Netlify](https://www.netlify.com/) - Hosting 16 | 17 | ### Author 18 | 19 | Igor Kulman - igor@kulman.sk 20 | -------------------------------------------------------------------------------- /config.toml: -------------------------------------------------------------------------------- 1 | baseurl = "https://blog.kulman.sk" 2 | languageCode = "en-us" 3 | title = "Igor Kulman" 4 | theme = "hugo-paper" 5 | enableRobotsTXT = true 6 | 7 | [markup] 8 | [markup.goldmark] 9 | [markup.goldmark.renderer] 10 | unsafe = true 11 | 12 | [permalinks] 13 | post = "/:slug/" 14 | 15 | [params] 16 | github = "igorkulman" 17 | rss = true 18 | comments = false 19 | showRelatedPosts = true 20 | color = 'light' 21 | mastodon = "https://hachyderm.io/@igorkulman" 22 | avatar = "igor@kulman.sk" 23 | name = 'Coding Journal' 24 | bio = 'Adventures in the world of Swift and iOS, reminiscing about the days of C#, F# and Windows development' 25 | disableHLJS = true 26 | linkedin = "igorkulman" 27 | 28 | [[menu.main]] 29 | name = "About me" 30 | url = "/about/" 31 | weight = 1 32 | 33 | [related] 34 | threshold = 80 35 | includeNewer = true 36 | toLower = true 37 | 38 | [[related.indices]] 39 | name = "keywords" 40 | weight = 150 41 | [[related.indices]] 42 | name = "tags" 43 | weight = 100 44 | 45 | -------------------------------------------------------------------------------- /content/about.md: -------------------------------------------------------------------------------- 1 | +++ 2 | date = "2015-12-22T15:44:50+01:00" 3 | title = "About me" 4 | subtitle = "Who am I?" 5 | 6 | +++ 7 | 8 | 📱 I’ve been developing mobile applications for over a decade, now **focused on iOS development** after the demise of Windows Phone. I contributed to privacy-focused applications as an **iOS developer** in the ProtonVPN team at [ProtonMail](https://www.protonmail.com) and helped build an industry-leading corporate secure messaging application at [Teamwire](https://www.teamwire.eu). 9 | 10 | 🎓 I hold a master's degree in **Computer Science** from Charles University in Prague (Faculty of Mathematics and Physics), specializing in **Software Engineering**. 11 | 12 | 🧑‍💻 This blog covers my **programming journey**, exploring **iOS and Swift** development alongside my past experiences with **Windows Phone and Windows development**. You’ll also find the occasional rant—because I dislike when things break. 13 | 14 | 🖥 Check out my [open-source software](https://github.com/igorkulman) to get a better sense of my work. 15 | 16 | 🇸🇰 I also write a [blog in Slovak about non-programming topics](https://www.kulman.sk). If you can read it, feel free to check it out. 17 | 18 | 🎤 Want to know more about how I work? Read my [interview about working from home](https://remotehabits.com/interview/interview-with-igor-kulman-a-software-engineer-building-ios-apps-remotely), explore my [macOS and iOS work setup](https://thesweetsetup.com/igor-kulmans-macos-iphone-and-watch-setup), or listen to a [podcast episode about my experience pitching a proposal for Swift](https://devchat.tv/iphreaks/ips-264-pitching-to-swift-with-igor-kulman/). 19 | 20 | ### Contact 21 | 22 | 📧 E-mail: igor@kulman.sk 23 | 🐘 Mastodon: [@igorkulman@hachyderm.io](https://hachyderm.io/@igorkulman) -------------------------------------------------------------------------------- /content/post/2012/autocompletebox-for-windows-store-apps/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "AutoCompleteBox for Windows Store apps" 3 | author = "Igor Kulman" 4 | date = "2012-11-29" 5 | url = "/autocompletebox-for-windows-store-apps/" 6 | categories = ["WinRT"] 7 | tags = ["Nuget","WinRT"] 8 | +++ 9 | There is no AutoCompleteBox control that can be used when building Windows Store apps in C# and XAML so I decided to create one, because I needed it for a project. Currently it supports only String collections and the selected value must be accessed using code behind, but this will hopefully change. 10 | 11 | The AutoCompleteBox uses [WinRT XAML Toolkit][1] to show the watermark and [Reactive Extensions][2] so the users does not need to press enter, the results will show after they stop typing for a second. 12 | 13 | The project is hosted on my Bitbucket so you can check it out at , forks and code contributions are welcomed. Nuget package is available at . 14 | 15 | Installation using Nuget: 16 | 17 | ``` 18 | Install-Package AutoCompleteBoxWinRT 19 | ``` 20 | 21 | 22 | 23 | {{% github-repo "igorkulman/AutoCompleteBox" %}} 24 | 25 | 26 | [1]: http://winrtxamltoolkit.codeplex.com/ 27 | [2]: http://msdn.microsoft.com/en-us/data/gg577609.aspx 28 | -------------------------------------------------------------------------------- /content/post/2012/computing-hashes-in-winrt/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Computing hashes in WinRT" 3 | author = "Igor Kulman" 4 | date = "2012-11-15" 5 | url = "/computing-hashes-in-winrt/" 6 | categories = ["WinRT"] 7 | tags = ["Csharp","Hashing","MD5","SHA1","WinRT"] 8 | +++ 9 | If you ever generated a MD5 or SHA hash in C# you problaby uset the classes from the System.Security.Cryptography namespace. This namespace is not available in WinRT, you have to use the Windows.Security.Cryptography.Core instead. This namespace contians a class called HashAlgorithmProvider that can be used to generate hashes using MD5 and SHA (SHA1, SHA256, SHA384, SHA512). A simple method to generate a hash for a string using a given algorithm may look like this 10 | 11 | ```csharp 12 | public static string GetHash(string algoritm, string s) 13 | { 14 | HashAlgorithmProvider alg = HashAlgorithmProvider.OpenAlgorithm(algoritm); 15 | IBuffer buff = CryptographicBuffer.ConvertStringToBinary(s, BinaryStringEncoding.Utf8); 16 | var hashed = alg.HashData(buff); 17 | var res = CryptographicBuffer.EncodeToHexString(hashed); 18 | return res; 19 | } 20 | ``` 21 | 22 | 23 | 24 | Specifing the algoritm by its string name is not a good idea in my opinion, although you can use the names from the HashAlgorithmNames class. I would rather make the GetHash method private and create public method for all the algorithms 25 | 26 | ```csharp 27 | public static string GetSha1(string s) 28 | { 29 | return GetHash(HashAlgorithmNames.Sha1, s); 30 | } 31 | 32 | public static string GetSha256(string s) 33 | { 34 | return GetHash(HashAlgorithmNames.Sha256, s); 35 | } 36 | 37 | public static string GetSha384(string s) 38 | { 39 | return GetHash(HashAlgorithmNames.Sha384, s); 40 | } 41 | 42 | public static string GetSha512(string s) 43 | { 44 | return GetHash(HashAlgorithmNames.Sha512, s); 45 | } 46 | 47 | public static string GetMD5(string s) 48 | { 49 | return GetHash(HashAlgorithmNames.Md5, s); 50 | } 51 | ``` 52 | -------------------------------------------------------------------------------- /content/post/2012/converting-hex-color-to-solidcolorbrush/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Converting HEX color to SolidColorBrush" 3 | author = "Igor Kulman" 4 | date = "2012-11-22" 5 | url = "/converting-hex-color-to-solidcolorbrush/" 6 | categories = ["WinRT"] 7 | tags = ["Csharp","WinRT"] 8 | +++ 9 | XAML supports stating color definitions as hexa strings (starting with #) but there is no built-in way to do it in C#, you must write your own method to do it, that might look like this 10 | 11 | ```csharp 12 | public static class ColorHelper 13 | { 14 | public static SolidColorBrush GetColorFromHexa(string hexaColor) 15 | { 16 | return new SolidColorBrush( 17 | Color.FromArgb( 18 | 255, 19 | Convert.ToByte(hexaColor.Substring(1, 2), 16), 20 | Convert.ToByte(hexaColor.Substring(3, 2), 16), 21 | Convert.ToByte(hexaColor.Substring(5, 2), 16) 22 | ) 23 | ); 24 | } 25 | } 26 | ``` 27 | 28 | 29 | -------------------------------------------------------------------------------- /content/post/2012/customizing-semantic-zoom-in-windows-8-apps/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Customizing semantic zoom in Windows 8 apps" 3 | author = "Igor Kulman" 4 | date = "2012-10-24" 5 | url = "/customizing-semantic-zoom-in-windows-8-apps/" 6 | categories = ["WinRT"] 7 | tags = ["Csharp","WinRT"] 8 | +++ 9 | Semantic zoom is an important part of all Windows 8 apps, it is a distinctive feature that differentiates them from other platforms. The SemanticZoom component works fine if you want the default experience, but if you want some customization you have to try a bit harder. 10 | 11 | The problem with the SemanticZoom component is, that as a child of it’s Semantic­Zoom.ZoomedIn­View and SemanticZoom.Zo­omedOutView elements, displaying the two states, you can use only two standard components; GridView and ListView. You cannot use the Grid and show mixed content. If you use one of these components, then clicking on any item in the zoomed out state shows you the group in the zoomed in state. You cannot implement any custom behaviour, the ItemClick event gets completely ignored. So how do you customize the SemanticZoom component? 12 | 13 | 14 | 15 | The key is to notice that both the GridView and the ListView components implement the ISemanticZoomIn­formation interface. Any component implementing this interface can be used as a child of the SemanticZoom.Zo­omedInView and SemanticZoom.ZoomedOutView elements. So lets implement an component called SemanticGrid that inherits from Grid and implements ISemanticZoomInformation 16 | 17 | ```csharp 18 | public class SemanticGrid: Grid,ISemanticZoomInformation 19 | { 20 | ... 21 | } 22 | ``` 23 | 24 | Let Visual Studio generate stubs for all the methods and properties in the ISemanticZoomIn­formation inteface. You do not need to implement them, just comment out the throw new NotImplementedException(); from all the methods and change the properties to 25 | 26 | ```csharp 27 | public bool IsActiveView 28 | { 29 | get; 30 | set; 31 | } 32 | 33 | public bool IsZoomedInView 34 | { 35 | get; 36 | set; 37 | } 38 | 39 | public SemanticZoom SemanticZoomOwner 40 | { 41 | get; 42 | set; 43 | } 44 | ``` 45 | 46 | And you are done. You can use this component with the SemanticZoom component instead of the GridView or the ListView and customize the semantic zoom according to your needs. Also if you wrap a GridView in this SemanticZoomGrid and place it in the SemanticZoom.ZoomedOutView element, the ItemClick handler in the GridView will work and you can implement custom actions. 47 | -------------------------------------------------------------------------------- /content/post/2012/encoding-two-ints-into-a-long-to-be-used-as-navigation-parameter/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Encoding two ints into a long to be used as navigation parameter" 3 | author = "Igor Kulman" 4 | date = "2012-12-05" 5 | url = "/encoding-two-ints-into-a-long-to-be-used-as-navigation-parameter/" 6 | categories = ["WinRT"] 7 | tags = ["WinRT"] 8 | +++ 9 | When navigating in a Windows Store app, you can specify a navigation parameter. This navigation parameter can be any object but there is a problem. When the application is suspended, this navigation parameter is saved by the LayoutAwarePage. This works only with primitive data types, unless you change the implementation of the class which instances you pass as the navigation parameter. 10 | 11 | I use mainly ints (article id, gallery id …) as navigation parameters but sometimes just on int is not enough. If I want to pass two int parameters, I “encode” them into an int and then “decode” back on the target page. I have a simple Utils class for this purpose. 12 | 13 | 14 | 15 | ```csharp 16 | public static class Utils 17 | { 18 | public static long MakeLong(int left, int right) 19 | { 20 | long res = left; 21 | res = (res << 32); 22 | res = res | (long)right; 23 | return res; 24 | } 25 | 26 | public static Tuple MakeTwoInts(long x) 27 | { 28 | int a = (int)(x & 0xffffffffL); 29 | int b = (int)(x >> 32); 30 | return Tuple.Create(b, a); 31 | } 32 | } 33 | ``` 34 | -------------------------------------------------------------------------------- /content/post/2012/fast-way-to-check-if-a-file-exists-in-winrt/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Fast way to check if a file exists in WinRT" 3 | author = "Igor Kulman" 4 | date = "2012-10-26" 5 | url = "/fast-way-to-check-if-a-file-exists-in-winrt/" 6 | categories = ["WinRT"] 7 | tags = ["Csharp","WinRT"] 8 | +++ 9 | The StorageFolder class does not containt any method to determine if a file with given name exists in that folder. There are at least two ways how to implement such method, let us call it ContainsFileAsync. 10 | 11 | The first method could take advantage of the GetFilesAsync method that returns a readonly list of all the files in a folder as StorageFile objects. The StorageFile contains a property called Name that you could compare with the given filename. The whole code would look like this 12 | 13 | ```csharp 14 | public async Task ContainsFileAsync(this StorageFolder folder, string filename) 15 | { 16 | var files = await folder.GetFilesAsync(); 17 | return files.Any(l=>l.Name==filename); 18 | } 19 | ``` 20 | 21 | 22 | 23 | This method looks fairly simple, elegant and works if the folder contains only a few files. When the folder contains tens or hundreds of files, this method gets very slow. In a folder with approximately 100 files the method takes about 1.5 seconds to return the result. 24 | 25 | There is faster way, that works in constant time (about 50ms) even in folders with hundred files, but it is not so elegant. The idea is simple, try to access the files and if you get an exception, just return false. 26 | 27 | ```csharp 28 | public async Task ContainsFileAsync(this StorageFolder folder, string filename) 29 | { 30 | try 31 | { 32 | var f = await folder.GetFileAsync(filename); 33 | return true; 34 | } 35 | catch 36 | { 37 | return false; 38 | } 39 | } 40 | ``` 41 | 42 | Although I am a big fan of elegance and readability when coding, I prefer and use the second method. 43 | -------------------------------------------------------------------------------- /content/post/2012/how-to-uniquely-identify-a-windows-8-device/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "How to uniquely identify a Windows 8 device" 3 | author = "Igor Kulman" 4 | date = "2012-11-08" 5 | url = "/how-to-uniquely-identify-a-windows-8-device/" 6 | categories = ["WinRT"] 7 | tags = ["Csharp","WinRT"] 8 | +++ 9 | When developing a Windows 8 app you may need to uniquely identify the device the app runs on. One reason may be the implementation of in-app purchases. 10 | 11 | The Windows.System.Profile namespace contains HardwareToken that you can get by calling HardwareIdentification.GetPackageSpecificToken(null) 12 | 13 | ```csharp 14 | var packageSpecificToken = Windows.System.Profile.HardwareIdentification.GetPackageSpecificToken(null); 15 | ``` 16 | 17 | This class contains a bunch of interesting fields 18 | 19 | ```csharp 20 | var hardwareId = packageSpecificToken.Id; 21 | var signature = packageSpecificToken.Signature; 22 | var certificate = packageSpecificToken.Certificate; 23 | ``` 24 | 25 | 26 | 27 | All of these fields are of type Windows.Storage.Stream.Ibuffer, therefore COM calls. To use a value useable with .NET you have to use the DataReader, I get the unique device identifier from the hardwareId 28 | 29 | ```csharp 30 | var dataReader = Windows.Storage.Streams.DataReader.FromBuffer(hardwareId); 31 | var array = new byte[hardwareId.Length];dataReader.ReadBytes(array) 32 | ``` 33 | 34 | The resulting byte array can be converted to an UTF8 string 35 | 36 | ```csharp 37 | string uuid = System.Text.Encoding.UTF8.GetString(array, 0, array.Length); 38 | ``` 39 | 40 | I prefer concatenating the bytes to a string 41 | 42 | ```csharp 43 | StringBuilder sb = new StringBuilder(); 44 | for (var i = 0; i < array.Length; i++) 45 | { 46 | sb.Append(array[i].ToString()); 47 | } 48 | string uuid = sb.ToString(); 49 | ``` 50 | 51 | **Update:** The hardware token of a device can change with hardware changes. Even small hardware changes like disabling Bluetooth can change the hardware token. You should generate it just once and save it. 52 | -------------------------------------------------------------------------------- /content/post/2012/loading-xaml-components-at-runtime/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Loading XAML components at runtime" 3 | author = "Igor Kulman" 4 | date = "2012-11-20" 5 | url = "/loading-xaml-components-at-runtime/" 6 | categories = ["WinRT"] 7 | tags = ["Csharp","WinRT","XAML"] 8 | +++ 9 | When I had to create a library to generate UI elements with animated image Ads I found out that creating complicated UI elements in code with bindings is not as easy as doing the same in XAML. A better way is to create your UI elements and bindings in a XAML file (if they are not very dynamic of course), load the XAML at runtime, parse it and set its DataContext. 10 | 11 | First you need to read the XAML file. You can use the standard API with Windows.ApplicationModel.Package.Current.InstalledLocation as the folder. The XAML file must be set to Build=Content in your project 12 | 13 | ```csharp 14 | var path = @"Templates\SkyScrapper.xaml"; 15 | var folder = Windows.ApplicationModel.Package.Current.InstalledLocation; 16 | 17 | var file = await _Folder.GetFileAsync(_Path); 18 | var template = await Windows.Storage.FileIO.ReadTextAsync(_File); 19 | ``` 20 | 21 | 22 | 23 | Once you have the XAML read as string, you can use the XamlReader and cast it to a DependencyObject. 24 | 25 | ```csharp 26 | var rootObject = XamlReader.Load(template) as DependencyObject; 27 | ``` 28 | 29 | or a more concrete class like UserControl if you know what the file contains. 30 | -------------------------------------------------------------------------------- /content/post/2012/monotouch-ios-development-for-net-programmers/monotocuh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2012/monotouch-ios-development-for-net-programmers/monotocuh.png -------------------------------------------------------------------------------- /content/post/2012/processing-json-in-net/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Processing JSON in .NET" 3 | author = "Igor Kulman" 4 | date = "2012-11-01" 5 | url = "/processing-json-in-net/" 6 | categories = ["WinRT"] 7 | tags = ["Csharp","JSON","WinRT"] 8 | +++ 9 | JSON is a very popular format for exchanging data, especially in the world of web technologies and JavaScript. The .NET platform contains a native support for this format but a better alternative is to use the JSON.NET library. 10 | 11 | **JSON.NET** 12 | 13 | [JSON.NET][1] is a flexible JSON serializer for .NET with LIQN support. The biggest reason for using this library is its performance in comparison to the standard DataContractJsonSerializer. The easiest way to use the library is to use the [Nuget package][2]. 14 | 15 | JSON.NET is very easy to use; first you create a JObject instance 16 | 17 | ```csharp 18 | JObject o = JObject.Parse(jsonString); 19 | ``` 20 | 21 | 22 | 23 | from which you can get a collection (in our example of type TicketViewModel) 24 | 25 | ```csharp 26 | Tickets = new ObservableCollection((o["tickets"].Select(ticket => new TicketViewModel(ticket)).OrderBy(l => l.City).ToList())); 27 | ``` 28 | 29 | filling the TicketViewModel instance from the JObject 30 | 31 | ```csharp 32 | public TicketViewModel(Newtonsoft.Json.Linq.JToken ticket) 33 | { 34 | _city = (string)ticket.SelectToken("city"); 35 | _cityCes = (string)ticket.SelectToken("city_ces"); 36 | _currency = (string)ticket.SelectToken("currency"); 37 | .... 38 | } 39 | ``` 40 | 41 | **DataContractJsonSerializer** 42 | 43 | If you do not want or cannot use JSON.NET you can use the already mentioned DataContractJsonSerializer. Before you use it, you have to create a class with the same structure as the JSON. You do not have to create it by hand; you can use the [json2csharp][3] utility. 44 | 45 | Using the DataContractJsonSerializer is a less readable than using JSON.NET 46 | 47 | ```csharp 48 | DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(Tickets)); 49 | Tickets tickets; 50 | using (MemoryStream stream = new MemoryStream(Encoding.Unicode.GetBytes(responseText))) 51 | { 52 | root = serializer.ReadObject(stream) as Tickets; 53 | } 54 | ``` 55 | 56 | [1]: http://james.newtonking.com/projects/json-net.aspx 57 | [2]: https://nuget.org/packages/Newtonsoft.Json 58 | [3]: http://json2csharp.com/ 59 | -------------------------------------------------------------------------------- /content/post/2012/store-region-messed-up-in-windows-phone-8/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Windows Phone Store region messed up in Windows Phone 8" 3 | author = "Igor Kulman" 4 | date = "2012-11-23" 5 | url = "/store-region-messed-up-in-windows-phone-8/" 6 | categories = ["Windows Phone"] 7 | tags = ["Windows Phone"] 8 | +++ 9 | If you use Windows Phone 7, your region for the Windows Phone Store is determined by the region of your Live ID you use with the phone. The region of your Live ID cannot be changed, so if you move to another country or just want to access apps that are not available in your country there is nothing you can to about it. Changing region in your phone does not help. 10 | 11 | The situation in Windows Phone 8 is different, more messed up. When I got my hands on the HTC 8X with Windows Phone 8, I logged with my Slovak LiveID. The Windows Phone Store showed apps available in Slovakia and I had no access to music or podcasts as expected. I listen to podcasts every day so I have an US Live ID I use with my Lumia 800 (and nowhere else and cannot be “merged” with my primary Live ID). 12 | 13 | 14 | 15 | I did a reset on the HTC 8X and logged with my US LiveID. I set the region in the phone to Slovakia. When I opened the Windows Phone Store, podcasts and music were there so I was satisfied. I started to browse the apps section and it seemed strange. I could not find the apps I use on my Lumia 800 with the same Live ID. These apss are not available in Slovakia. When I changed the region setting in the phone to US, then the Store started to show them. 16 | 17 | To sum it up, it looks like in Windows Phone 8 the services that are available to you (apps, games, music, podcasts) are determined from the region of your Live ID, but the games and apps that are shown to you are determined from the region setting in your phone. Pretty messed up if you ask me. 18 | -------------------------------------------------------------------------------- /content/post/2012/tampering-with-windows-store-apps-data/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Tampering with Windows Store apps data" 3 | author = "Igor Kulman" 4 | date = "2012-11-13" 5 | url = "/tampering-with-windows-store-apps-data/" 6 | categories = ["WinRT"] 7 | tags = ["Security","WinRT"] 8 | +++ 9 | Windows Store apps run in a sandbox with their data isolated from each other. So how secure is this storage from tampering by the user? It turns out not much. 10 | 11 | The only Windows Store app I use on my work notebook is WeatherFlow because of the live tile. The app allows you to add your city and view weather forecast for it. But there is now way to get rid of the default cities like New York, Tokyo, etc. that are in the app when you first run it. This realy annoyed me so I started to poke around. 12 | 13 | Using the debugger and checking the value of ApplicationData.Current.LocalFolder I found out that all the data of Windows Store apps are stored in AppData\Local\Packages in your profile (for me it is C:\Users\Igor\AppData\Local\Packages). The name of the directory for the app you are lookin for usualy contain its name, it is 08C8076A.WeatherFlow_gyyqpbm0tqk6g for WeatherFlow. The directory for each app contains a few subdirectories 14 | 15 | 16 | 17 | AC 18 | 19 | LocalState 20 | 21 | RoamingState 22 | 23 | Settings 24 | 25 | SystemAppData 26 | 27 | TempState 28 | 29 | The important directories are LocalState and RoamingState representing the local and roaming folder, where each application can store its files. WeatherFlow uses only LocalState where it stores one data.json file with its configuration. You can edit the file and remove the unwanted city, then run the application again and it still works, with the changes you made. 30 | 31 | Now imaging editing files of a game, giving yourself gold coins or armor, or copying files somewhere else, sharing … If you want the data of your Windows Store app to be secured, you have to do it by yourself. 32 | -------------------------------------------------------------------------------- /content/post/2012/updating-azure-toolkit-is-always-a-pain/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Updating Azure Toolkit is always a pain" 3 | author = "Igor Kulman" 4 | date = "2012-10-26" 5 | url = "/updating-azure-toolkit-is-always-a-pain/" 6 | categories = ["Windows Azure"] 7 | tags = ["Azure","Visual Studio"] 8 | +++ 9 | From time to time I need to develop or maintain a small Windows Azure project. This time I wanted to create the whole project in F#. The first thing I needed to to was to update the Azure toolkit 1.8 (October 2012) but updating Azure Toolkit is always a pain. I started Web Platform Installer, selected Azure Toolkit 1.8, Azure Tools 1.8 for VS2012 and installed everything including the dependencies. What was the result? The whole Azure integration in Visual Studio 2012 stopped working. The Azure templates completely disappeared and Visual Studio only offered me downloading the Azure Toolkit, which failed, because it was already installed. I ended up completely uninstalling everything with the name containing Azure and installing the Azure toolkit again using the link from Visual Studio. 10 | 11 | Why cannot this work better? 12 | 13 | 14 | -------------------------------------------------------------------------------- /content/post/2012/using-net-libraries-with-monotouch/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Using .NET libraries with MonoTouch" 3 | author = "Igor Kulman" 4 | date = "2012-12-28" 5 | url = "/using-net-libraries-with-monotouch/" 6 | categories = ["Programming in general"] 7 | tags = ["Csharp","iOS","Mono","MonoTouch"] 8 | +++ 9 | I have been [playing with MonoTouch][1] only for a few days when I already started to miss all the .NET libraries I commonly use. The first one I needed to get working with MonoTouch was [JSON.NET][2]. 10 | 11 | MonoDevelop does not support Nuget so you have to get your libaries the old way. I downloaded JSON.NET package from [Nuget.org][3], but it does not contain a DLL built for Mono. Harldy any Nuget package does. You can reference a DLL built for .NET, MonoDevelop will recognize it and even offer you IntelliSense but your project will not get built. 12 | 13 | The right way to get a .NET library working with MonoTouch is downloading its source code and building it yourself. You can use MonoDevelop to build the source codes. The only think you have to do (at least for JSON.NET) is to change the .NET profile to an equivalent Mono profile in the project settings. 14 | 15 | 16 | 17 | [1]: http://blog.kulman.sk/monotouch-ios-development-for-net-programmers/ 18 | [2]: http://james.newtonking.com/projects/json-net.aspx 19 | [3]: http://nuget.org/ 20 | -------------------------------------------------------------------------------- /content/post/2012/welcome/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Welcome" 3 | author = "Igor Kulman" 4 | date = "2012-10-24" 5 | url = "/welcome/" 6 | categories = ["WinRT"] 7 | +++ 8 | I have been playing with the idea of having a coding blog in English for some time now. I have written some posts about programming in C# and Windows Phone 7 on my Slovak web, but I wanted to address a wider audience. I plan to publish one post per week, mainly about WinRT programming. I want the posts to be useful and solve a particular problem I stumble upon in my work developing Windows Store apps. 9 | 10 | If you understand Slovak, definetely check my web [www.kulman.sk][1] 11 | 12 | 13 | 14 | [1]: http://www.kulman.sk 15 | -------------------------------------------------------------------------------- /content/post/2013/appharbor-great-place-to-start-your-net-project/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "AppHarbor: great place to start your .NET project" 3 | author = "Igor Kulman" 4 | date = "2013-01-08" 5 | url = "/appharbor-great-place-to-start-your-net-project/" 6 | categories = ["Programming in general","Windows Azure"] 7 | tags = ["Web","Csharp"] 8 | +++ 9 | If you want to host your .NET project on the Internet, there are classic ASP.NET webhosting on one side of the spectrum and Microsoft Azure on the other. If you are looking for something in the middle, take a look at [AppHarbor][1]. 10 | 11 | **AppHarbor** 12 | 13 | AppHarbor is a flexible and scalable .NET Platform-as-a-Service, that you can even [use for free][2], limited to one web or worker role. It runs in AWS and is quite similiar to Heroku. 14 | 15 | **Variety of Add-ons** 16 | 17 | There are [many add-on supported by AppHarbor][3], including SQL Server, MongoDB, RavenDB, MySQL, Memcacher … Many of these ad-ons offer free versions so you can test them for free. If you run into some problems, you can use [the support forums][4] or [StackOverflow][5]. 18 | 19 | 20 | 21 | **Flexible deployment** 22 | 23 | The thing I like best about AppHarbor are the deployment options. You can push your .NET code to AppHarbor using Git, Mercurial, Subversion or Team Foundation Server with the complimentary Git service or through integrations offered in collaboration with [Bitbucket][6], [CodePlex][7] and [GitHub][8]. 24 | 25 | When AppHarbor receives your code it will be built by a platform build server. If the code compiles, any unit tests contained in the compiled assemblies will be run. If the code builds and all tests execute successfully, the application is deployed to the AppHarbor application servers. 26 | 27 | **Compatibility** 28 | 29 | The majority of .NET code runs just fine in AppHarbor without any changes. If you use Nuget, you need to enabled Nuget Package Restore for your solution. 30 | 31 | Let the continous deployment begin … my first AppHarbor project is hosted at [http://myexpenses.apphb.com][9]. 32 | 33 | [1]: https://appharbor.com/ 34 | [2]: https://appharbor.com/pricing 35 | [3]: https://appharbor.com/addons 36 | [4]: http://support.appharbor.com/ 37 | [5]: http://stackoverflow.com/questions/tagged/appharbor 38 | [6]: http://support.appharbor.com/kb/api/integrating-with-bitbucket 39 | [7]: http://support.appharbor.com/kb/api/integrating-with-codeplex 40 | [8]: http://blog.appharbor.com/2011/10/13/announcing-github-support 41 | [9]: http://myexpenses.apphb.com/ 42 | -------------------------------------------------------------------------------- /content/post/2013/beware-of-removing-localizations-from-your-windows-phone-apps/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Beware of removing localizations from your Windows Phone apps" 3 | author = "Igor Kulman" 4 | date = "2013-06-05" 5 | url = "/beware-of-removing-localizations-from-your-windows-phone-apps/" 6 | categories = ["Windows Phone"] 7 | tags = ["Csharp","Windows Phone"] 8 | +++ 9 | 10 | When I released version 2.0 of my app Photo Timeline, some users reported updating problems. I finally found out what caused the problem and submited a new build to the Windows Phone store. 11 | 12 | In my app I had three localizations: en-US (default), en and cs. I do not exactly remember why I had English twice as localization. I decided to remove the en localization thinking that nothing will break and that was a mistake. 13 | 14 | **Once you add a localization to your app, never remove it!** If you do so, all the users who use your app with that localization will have update problems. 15 | -------------------------------------------------------------------------------- /content/post/2013/detecting-encoding-of-uploaded-file-in-asp-net-mvc/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Detecting encoding of uploaded file in ASP.NET MVC" 3 | author = "Igor Kulman" 4 | date = "2013-02-05" 5 | url = "/detecting-encoding-of-uploaded-file-in-asp-net-mvc/" 6 | categories = ["Programming in general"] 7 | tags = ["Web", "ASP","Csharp"] 8 | +++ 9 | Uploading a file in ASP.NET MVC is very easy, but there is no easy way to detect the encoding of a uploaded text file. However you can use the fact if you try to read the file with a wrong encoding, you get an DecoderFallbackException. So how do you put everything together? 10 | 11 | First, get a stream of the uploaded file. 12 | 13 | ```csharp 14 | [HttpPost] 15 | public ActionResult FromCSV(HttpPostedFileBase file) 16 | { 17 | if (file != null && file.ContentLength > 0) 18 | { 19 | var stream = file.InputStream; 20 | ... 21 | } 22 | } 23 | ``` 24 | 25 | 26 | 27 | Next, read the whole file to a byte array 28 | 29 | ```csharp 30 | public static byte[] ReadFully(Stream input) 31 | { 32 | byte[] buffer = new byte[16 * 1024]; 33 | using (MemoryStream ms = new MemoryStream()) 34 | { 35 | int read; 36 | while ((read = input.Read(buffer, 0, buffer.Length)) > 0) 37 | { 38 | ms.Write(buffer, 0, read); 39 | } 40 | return ms.ToArray(); 41 | } 42 | } 43 | ``` 44 | 45 | Finally the trick is to try all the encodings you think the file may be in and chech if if fails or not 46 | 47 | ```csharp 48 | private static string[] GetFileContent(Stream input) 49 | { 50 | Encoding[] encodings = new Encoding[]{ 51 | Encoding.GetEncoding("UTF-8", new EncoderExceptionFallback(), new DecoderExceptionFallback()), 52 | Encoding.GetEncoding(1250, new EncoderExceptionFallback(), new DecoderExceptionFallback()) 53 | }; 54 | var inputArr = ReadFully(input); 55 | String result = null; 56 | 57 | foreach (Encoding enc in encodings) 58 | { 59 | try 60 | { 61 | result = enc.GetString(inputArr); 62 | break; 63 | } catch (DecoderFallbackException e){} 64 | } 65 | 66 | return result; 67 | } 68 | ``` 69 | -------------------------------------------------------------------------------- /content/post/2013/do-you-need-to-create-a-special-windows-phone-8-build-of-your-windows-phone-app/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Do you need to create a special Windows Phone 8 build of your Windows Phone app?" 3 | author = "Igor Kulman" 4 | date = "2013-04-15" 5 | url = "/do-you-need-to-create-a-special-windows-phone-8-build-of-your-windows-phone-app/" 6 | categories = ["Windows Phone"] 7 | tags = ["Csharp","Windows Phone"] 8 | +++ 9 | If you create a Windows Phone app and you want it to be able to run on both Windows Phone 7 and Windows Phone 8, you target Windows Phone 7 and the app runs on Windows Phone 8 automatically. But is it really enough to create a Windows Phone 7 buíld? Not if you want to create a really well designed app. 10 | 11 | The problem with Windows Phone 8 from a designers point of view is that it introduces two new display resolutions. Windows Phone 7 supports just one resolution, WVGA of 800x480px. Windows Phone 8 adds WXGA (1280×768) and 720p (1280×720). If you run your Windows Phone 7 app on a WXGA device, the app is proportionally scaled by a factor of 1.6 to fill out the whole screen. As long as you provide all your images scaled by the same factor, the app looks ok. 12 | 13 | The problem is 720p, because it is a different aspect ratio (16:9 vs 15:9). Your Windows Phone 7 app running on a 720p app is first scaled by a factor of 1.5 to 1200×720 and the rest of the display (80px) is padded on top or bottom, depending on the VerticalAlignment. By default, the padding is added to the top of your app making your header 80px higher: 14 | 15 | ![Windows Phone 7 app header on Windows Phone 8 device](wp7header.png) 16 | 17 | 18 | 19 | This makes all the Windows Phone 7 apps look bad on a 720p devices like the HTC 8X I currently use. If you create a Windows Phone 8 project with exactly the same XAML, the app will look ok on a 720p device, no padding added to top or bottom. Another advantage of a special Windows Phone 8 build is that the app will start much faster. 20 | 21 | To sum it up, if you want your app to look great on all devices, always create a separate Windows Phone 8 build. It is usually as simple as creating a new Windows Phone 8 project and adding all the existing files as links. You can find more info about this technique on Nokia Dev Wiki. 22 | 23 | 24 | -------------------------------------------------------------------------------- /content/post/2013/do-you-need-to-create-a-special-windows-phone-8-build-of-your-windows-phone-app/wp7header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2013/do-you-need-to-create-a-special-windows-phone-8-build-of-your-windows-phone-app/wp7header.png -------------------------------------------------------------------------------- /content/post/2013/my-windows-phone-and-windows-8-mini-libraries/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "My Windows Phone and Windows 8 mini-libraries" 3 | author = "Igor Kulman" 4 | date = "2013-03-18" 5 | url = "/my-windows-phone-and-windows-8-mini-libraries/" 6 | categories = ["Windows Phone","WinRT"] 7 | tags = ["Csharp","Windows Phone","WinRT"] 8 | +++ 9 | I am a big fan of open-source software. I decided to make my mini-libraries, that I use for Windows Phone and Windows 8 development, available to everyone who would be interested. Both are basically a collection of useful utilities and components that I wrote myself or found on various forums and slightly modified. Source code is available on BitBucket and packages on Nuget. 10 | 11 | **Windows Phone** 12 | 13 | Code: 14 | 15 | Nuget: 16 | 17 | **Windows 8** 18 | 19 | Code: 20 | 21 | Nuget: 22 | 23 | My Windows 8 mini-library is best used with the [WinRTXAMLToolkit][1] that I contributed to once ot twice. 24 | 25 | **AutoCompleteBox for WinRT** 26 | 27 | Code: 28 | 29 | Nuget: 30 | 31 | 32 | 33 | [1]: https://nuget.org/packages/winrtxamltoolkit/ 34 | -------------------------------------------------------------------------------- /content/post/2013/reading-excel-sheets-using-f-without-com/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Reading Excel sheets using F# without COM" 3 | author = "Igor Kulman" 4 | date = "2013-02-06" 5 | url = "/reading-excel-sheets-using-f-without-com/" 6 | categories = ["Functional programming"] 7 | tags = ["Excel","Fsharp","Mono"] 8 | +++ 9 | I needed to create an utility that would read Excel 2010 files (.xlsx) and generate XML files from them according to some specific rules. The catch was that the utility needed to run on MacOS instead of Windows. 10 | 11 | Reading and writing Excel files from .NET is [very easy using the Microsoft.Office.Interop assemblies][1] but they use Excel through COM and that makes them unusable outside of Windows. I found some 3rd party libraries for working with Excel and analzyed them with [The Mono Migration Analzyer][2] (MoMA). MoMA is a handy tool that analyzes .NET assemblies and tells you if they will run on Mono. Many of the Excel libraries I found were unusable for my use-case because they were using PInvoke calls. Only the [ExcelPackage library][3] runs on Mono. 12 | 13 | I wanted to use the ExcelPackage from F# not C# so I wrote a [very simple F# wrapper][4], that you can freely use. For now it contains just a few methods 14 | 15 | 16 | 17 | Excel.getWorksheets 18 | 19 | Excel.getWorksheetByIndex 20 | 21 | Excel.getWorksheetByName 22 | 23 | Excel.getMaxRowNumber 24 | 25 | Excel.getMaxColNumber 26 | 27 | Excel.getContent 28 | 29 | Excel.getColumn 30 | 31 | Excel.getRow 32 | 33 | but I will be adding a few more soon. The usage is really simple. For example, if you want to read the whole sheet number 1 from a file called text.xlsx, use 34 | 35 | ```fsharp 36 | let data = 37 | "test.xlsx" 38 | |> Excel.getWorksheetByIndex 1 39 | |> Excel.getContent 40 | 41 | data 42 | |> Seq.iter (fun x-> printfn "%s" x) 43 | ``` 44 | 45 | **EDIT**: Now available as a Nuget package: 46 | 47 | ```powershell 48 | PM> Install-Package ExcelPackageF 49 | ``` 50 | 51 | {{% github-repo "igorkulman/ExcelPackageF" %}} 52 | 53 | 54 | [1]: http://blogs.msdn.com/b/jackhu/archive/2011/04/19/fsharp-amp-excel-io-reading-and-writeing-to-excel.aspx 55 | [2]: http://www.mono-project.com/MoMA 56 | [3]: http://excelpackage.codeplex.com/ 57 | [4]: https://github.com/igorkulman/ExcelPackageF 58 | -------------------------------------------------------------------------------- /content/post/2013/returning-files-in-nancyfx/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Returning files in NancyFX" 3 | author = "Igor Kulman" 4 | date = "2013-10-02" 5 | url = "/returning-files-in-nancyfx/" 6 | categories = ["Windows Azure"] 7 | tags = ["Azure","Csharp","NancyFX"] 8 | +++ 9 | In my current project, I have chosen [NancyFx][1] to implement a REST API. NancyFx is a .NET framework known for its “[super-duper-happy-path][2]“. 10 | 11 | In one use case I generate a ZIP file in the temp folder and I want the API to return this ZIP file. NancyFx contains a Responses.AsFile helper but it works only with paths relative to the application. 12 | 13 | If you have an absolute path of a file, you cannot use it. You need to create a StreamResponse and return the file as an attachment 14 | 15 | ```csharp 16 | var file = new FileStream(zipPath, FileMode.Open); 17 | string fileName = //set a filename 18 | 19 | var response = new StreamResponse(() => file, MimeTypes.GetMimeType(fileName)); 20 | 21 | return response.AsAttachment(fileName); 22 | ``` 23 | 24 | 25 | 26 | [1]: http://nancyfx.org/ 27 | [2]: https://github.com/NancyFx/Nancy/wiki/Introduction#the-super-duper-happy-path 28 | -------------------------------------------------------------------------------- /content/post/2013/useful-tools-for-windows-store-developers/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Useful tools for Windows Store developers" 3 | author = "Igor Kulman" 4 | date = "2013-04-18" 5 | url = "/useful-tools-for-windows-store-developers/" 6 | categories = ["Windows Phone","WinRT"] 7 | tags = ["Csharp","Windows Store","XAML","WinRT"] 8 | +++ 9 | I recently discovered two really neet tools that helped me with Windows Store app development. 10 | 11 | **Windows Store Icon Maker** 12 | 13 | When creating a Windows Store or Windows 8 apps, there are many icon sizes you have to provide. If you do nont wat to do all the resizing by yourself, you can use the [Windows Store Icon Maker][1]. It is a fork of the [Windows Phone Icons Maker][2] with added support for Windows Store apps. It takes a 300x300px icon as input and outputs all the square icons you need. 14 | 15 | 16 | 17 | **HAMMER.Pants** 18 | 19 | To brand Windows Store apps written in XAML, you need to override all the control styles. This sucks if you just want to change the colours to match your theme. [HAMMER.Pants][3] solves this, by auto-modifying all the coloured brushes so you don’t have to pick through them. Currently, you provide a “base” colour, and HAMMER.Pants modifies that based on the luminance variation found in the original styles. That is, if you pick red, all the purples will be replaced with reds, but they’ll change in brightness slightly just like the default purples do. 20 | 21 | [1]: https://github.com/DavidBurela/WindowsMarketplaceIconMaker 22 | [2]: http://wpiconmaker.codeplex.com/ 23 | [3]: https://github.com/Code52/HAMMER 24 | -------------------------------------------------------------------------------- /content/post/2013/using-custom-fonts-in-windows-phone-apps/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Using custom fonts in Windows Phone apps" 3 | author = "Igor Kulman" 4 | date = "2013-01-30" 5 | url = "/using-custom-fonts-in-windows-phone-apps/" 6 | categories = ["Windows Phone"] 7 | tags = ["Csharp","Windows Phone"] 8 | +++ 9 | Windows Phone allows yout to use custom TTF fonts in your apps. Using a custom font from XAML or C# is easy, but your run into troubles when you want to use if from a Background Agent (e.g: for updating a Live Tile). 10 | 11 | **Adding font to solution** 12 | 13 | The custom font must be a TTF, you can also use a ZIP file with multiple TTF files. You need to know the name of the font to identify it. Add the font file to your solution and set its build action to Content. 14 | 15 | **Custom font and XAML** 16 | 17 | Using a custom font in XAML is very straightforward. You just need to set the _FontFamily_ property to the font file path followed by a hash (#) and the font name: 18 | 19 | 20 | 21 | ```xml 22 | 23 | ``` 24 | 25 | **Custom font and C#** 26 | 27 | Using a custom font from C# follows the same principle. You just need to set the _FontFamily_ property to a new FontFamily instance created by the constructor that takes a font family name as a parameter: 28 | 29 | ```csharp 30 | textBlock.FontFamily = new FontFamily(".\Fonts\meteocons.ttf#Meteocons"); 31 | ``` 32 | 33 | **Custom font and Background Agent** 34 | 35 | Using a custom font from a Background Agent is a bit tricky. If you want to use it to render an image for your Live Tile, you will find out, that none of the before mentioned steps work. The font just does not get rendered. I suspect that the font does not get loaded because of some bug in the Silverlight runtime. 36 | 37 | A possible workaround is to to read the font file as a stream and set this stream to the TextBlock’s _FontSource_ property before setting the _FontFamily_ property: 38 | 39 | ```csharp 40 | var uri = new Uri("Fonts/meteocons.ttf", UriKind.Relative); 41 | var streamInfo = Application.GetResourceStream(uri); 42 | textBlock.FontSource = new FontSource(streamInfo.Stream); 43 | textBlock = new FontFamily("Meteocons"); 44 | ``` 45 | -------------------------------------------------------------------------------- /content/post/2013/using-the-debuggerdisplay-attribute-for-better-debugging-experience/debug1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2013/using-the-debuggerdisplay-attribute-for-better-debugging-experience/debug1.png -------------------------------------------------------------------------------- /content/post/2013/using-the-debuggerdisplay-attribute-for-better-debugging-experience/debug2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2013/using-the-debuggerdisplay-attribute-for-better-debugging-experience/debug2.png -------------------------------------------------------------------------------- /content/post/2013/using-the-debuggerdisplay-attribute-for-better-debugging-experience/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Using the DebuggerDisplay attribute for better debugging experience" 3 | author = "Igor Kulman" 4 | date = "2013-11-25" 5 | url = "/using-the-debuggerdisplay-attribute-for-better-debugging-experience/" 6 | categories = ["Programming in general"] 7 | tags = ["Csharp","Debug","Visual Studio"] 8 | +++ 9 | When debugging a C# program in Visual Studio, I tend to always hover over the variables to glance at their values and structure instead of explicitly writing their names into the watch window. If I want to explore say a collection, I need to unfold each of the items using the + button to get an idea about the data: 10 | 11 | ![Debugger view in Visual Studio](debug1.png) 12 | 13 | This is not very comfortable, so thankfully, there is a way to make this experience better, using the [DebuggerDisplay][2] attribute. This attribute can be applied to any class (and struct, enum, property, field, delegate, assembly) and allows you to define the information about the class you want to to see in the debugger. 14 | 15 | 16 | 17 | Give the attribute a string to be displayed and in this string you can reference any data from the class: 18 | 19 | ```csharp 20 | [DebuggerDisplay("ID = {ID} | Title = {Title}")] 21 | public class PocketItem 22 | { 23 | public int ID {get;set;} 24 | public string Title {get;set;} 25 | } 26 | ``` 27 | 28 | When you hover over the data now, you will see a nice readable "labels": 29 | 30 | ![Debugger view in Visual Studio with custom data](debug2.png) 31 | 32 | If you do not want to add the DebuggerDisplay attribute to all your classes manually, you can use the [Visualize][4] addin for [Fody][5]. Visualize will add the DebuggerDisplay attribute to all your classes, using all the classes' properties in the "label". 33 | 34 | **Warning**: showing this "labels" takes some time, so do not reference to many data fields. 35 | 36 | [2]: http://msdn.microsoft.com/en-us/library/system.diagnostics.debuggerdisplayattribute(v=vs.110).aspx 37 | [4]: https://github.com/Fody/Visualize 38 | [5]: https://github.com/Fody/Fody 39 | -------------------------------------------------------------------------------- /content/post/2013/visual-studio-achievements-a-bit-of-gamification-to-your-programming/VisualStudio_badges_2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2013/visual-studio-achievements-a-bit-of-gamification-to-your-programming/VisualStudio_badges_2.jpg -------------------------------------------------------------------------------- /content/post/2013/visual-studio-achievements-a-bit-of-gamification-to-your-programming/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Visual Studio Achievements: a bit of gamification to your programming" 3 | author = "Igor Kulman" 4 | date = "2013-01-03" 5 | url = "/visual-studio-achievements-a-bit-of-gamification-to-your-programming/" 6 | categories = ["Programming in general"] 7 | tags = ["Visual Studio"] 8 | +++ 9 | Gamification is a great concept that works really well for some people, including me. Gamification may very well be the reason for success of projects like [StackOveflow][1] or [Duolingo][2]. 10 | 11 | **Visual Studio Achievements** 12 | 13 | [Visual Studio Achievements][3] is Visual Studio plugin that rewards you for good practices like having 1000 localized values ([Localization Master][4]) and even for bad practices like writing a single line of 300 characters long ([Scroll Bar Wizard][5]). For some of the achievements you need to have FxCop installed, but the majority get awarded without the need for it. 14 | 15 | ![Visual Studio achievements](VisualStudio_badges_2.jpg) 16 | 17 | You can find out interesting information about your programming, check out [my profile][7]. 18 | 19 | 20 | 21 | [1]: http://stackoverflow.com/ 22 | [2]: http://duolingo.com/ 23 | [3]: http://visualstudiogallery.msdn.microsoft.com/bc7a433b-b594-48d4-bba2-a2f24774d02f 24 | [4]: https://channel9.msdn.com/achievements/visualstudio/MoreThan1000LOC 25 | [5]: https://channel9.msdn.com/achievements/visualstudio/LongerThan300LocAchievement 26 | [6]: http://visualstudiogallery.msdn.microsoft.com/site/view/file/63443/1/VisualStudio_badges_2.jpg 27 | [7]: https://channel9.msdn.com/niners/igorkulman/achievements/visualstudio 28 | -------------------------------------------------------------------------------- /content/post/2013/why-are-there-no-great-windows-8-apps-because-of-winrt-a-developers-view/microsoft-surface-2-650x0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2013/why-are-there-no-great-windows-8-apps-because-of-winrt-a-developers-view/microsoft-surface-2-650x0.jpg -------------------------------------------------------------------------------- /content/post/2013/windows-phone-run-background-agent-every-minute/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Windows Phone: run background agent every minute" 3 | author = "Igor Kulman" 4 | date = "2013-06-12" 5 | url = "/windows-phone-run-background-agent-every-minute/" 6 | categories = ["Windows Phone"] 7 | tags = ["Background agent","Csharp", "Windows Phone"] 8 | +++ 9 | In both Windows Phone 7 and Windows Phone 8 the background agent is executed approximately every 30 minutes. If you want to run your code more often, for example to create an app showing actual time on the live tile, you are out of luck. Are you? 10 | 11 | You can use [ScheduledActionService.LaunchForTest][1] to test your background agent without waiting 30 minutes for the system to run it. What if you use this method in the OnInvoke method of your background agent? 12 | 13 | 14 | 15 | ```csharp 16 | protected override void OnInvoke(ScheduledTask task) 17 | { 18 | ScheduledActionService.LaunchForTest(task.Name, TimeSpan.FromSeconds(60)); 19 | var toast = new ShellToast {Title = DateTime.Now.ToShortTimeString(), Content = "Task Running"}; 20 | toast.Show(); 21 | 22 | NotifyComplete(); 23 | } 24 | ``` 25 | 26 | Your background agent gets executed every minute! 27 | 28 | I wonder if this code would pass certification. Has anyone tried to use it? 29 | 30 | **Update:** it will **not** work, see [Windows Phone: Don’t call LaunchForTest in Release][3]. 31 | 32 | [1]: http://msdn.microsoft.com/en-US/library/windowsphone/develop/microsoft.phone.scheduler.scheduledactionservice.launchfortest(v=vs.105).aspx 33 | [2]: http://blog.kulman.sk/wp-content/uploads/2013/06/CSWP7ScheduledTaskAgent.zip 34 | [3]: http://blog.mjfnet.com/2013/01/10/windows-phone-dont-call-launchfortest-in-release/ 35 | -------------------------------------------------------------------------------- /content/post/2013/windows-store-limits-the-number-of-in-app-purchases-for-an-app/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Windows Store limits the number of in-app purchases for an app" 3 | author = "Igor Kulman" 4 | date = "2013-03-21" 5 | url = "/windows-store-limits-the-number-of-in-app-purchases-for-an-app/" 6 | categories = ["WinRT"] 7 | tags = ["Windows Store","WinRT"] 8 | +++ 9 | Windows 8 development has [many problems and pitfalls because of WinRT][1]. Windows Store, the only distribution channel for Windows 8 apps, has some problems too. One of them is really serious for everyone who wants to create a newspaper or newsreader app with in-app purchases. 10 | 11 | We developed a Windows 8 app for a local newspaper. The content consists of issues, there is one issue published each work day. The users can buy the issues using in-app purchases. The problem is that there is a limit of 100 200 in-app purchases that can be defined for a single app in Windows Store. I really do not know what would Microsoft impose such a limit. 12 | 13 | As far as I know there is no way around the limit. We need to either delete in-app purchases for old issues so user will no longer be able to buy them (which is stupid and as ot turns out not possible) or create new app with a different name and in-app purchases for another time period (which is even more stupid). 14 | 15 | 16 | 17 | Sure you can implement content purchasing using other ways, but they all have one big problem. There is no way your app can get the identity of the user. If you implement your own purchasing mechanism, you cannot pair the purchases with the user, only with the device. So the user would have to buy the same content on each device, if he reinstall his system, etc. That is usually not what you want. 18 | 19 | [1]: http://blog.kulman.sk/why-are-there-no-great-windows-8-apps-because-of-winrt-a-developers-view/ 20 | -------------------------------------------------------------------------------- /content/post/2014/building-windows-phone-apps-with-fake/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Building Windows Phone apps with FAKE" 3 | author = "Igor Kulman" 4 | date = "2014-03-31" 5 | url = "/building-windows-phone-apps-with-fake/" 6 | categories = ["Windows Phone"] 7 | tags = ["Fsharp","FAKE","Windows Phone"] 8 | +++ 9 | [FAKE][1] is a build automation system with capabilities which are similar to make and rake. It is using an easy domain-specific language (DSL) so that you can start using it without learning F#. If you need more than the default functionality you can either write F# or simply reference .NET assemblies. 10 | 11 | I have been using FAKE for quite some time now on some fairly complex projects for not only building but also running tests and creating and pushing Nuget packages and I really like. I decided to add FAKE build scripts to my Windows Phone apps to make the process of generating a XAP file for the Windows Phone Store easier. 12 | 13 | The FAKE script I use can by used with any Windows Phone app, it will build all the projects and copy the XAP file to a release directory. 14 | 15 | 16 | 17 | ```fsharp 18 | // include Fake lib 19 | #r @"tools\FAKE\tools\FakeLib.dll" 20 | open Fake 21 | 22 | RestorePackages() 23 | 24 | // Properties 25 | let buildDir = @".\build\" 26 | let packagesDir = @".\packages" 27 | let releaseDir = @".\release" 28 | 29 | // Targets 30 | Target "Clean" (fun _ -> 31 | CleanDirs [buildDir; releaseDir] 32 | ) 33 | 34 | Target "Build" (fun _ -> 35 | !! @"**/*.csproj" 36 | |> MSBuildRelease buildDir "Build" 37 | |> Log "AppBuild-Output: " 38 | ) 39 | 40 | Target "Deploy" (fun _ -> 41 | !! (buildDir + "*.xap") 42 | |> Copy releaseDir 43 | ) 44 | 45 | Target "Default" (fun _ -> 46 | trace "Build completed" 47 | ) 48 | 49 | // Dependencies 50 | "Clean" 51 | ==> "Build" 52 | ==> "Deploy" 53 | ==> "Default" 54 | 55 | // start build 56 | Run "Default" 57 | ``` 58 | 59 | To get the script started, you need a batch file 60 | 61 | ```batch 62 | @echo off 63 | cls 64 | "tools\nuget\nuget.exe" "install" "FAKE" "-OutputDirectory" "tools" "-ExcludeVersion" 65 | "tools\FAKE\tools\Fake.exe" build.fsx 66 | pause 67 | ``` 68 | 69 | and Nuget.exe in tools\NuGet directory. 70 | 71 | [1]: http://fsharp.github.io/FAKE/ 72 | -------------------------------------------------------------------------------- /content/post/2014/changing-the-pivotitem-header-color-in-windows-phone-8-1-xaml/header78.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2014/changing-the-pivotitem-header-color-in-windows-phone-8-1-xaml/header78.png -------------------------------------------------------------------------------- /content/post/2014/changing-the-pivotitem-header-color-in-windows-phone-8-1-xaml/header81.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2014/changing-the-pivotitem-header-color-in-windows-phone-8-1-xaml/header81.png -------------------------------------------------------------------------------- /content/post/2014/changing-the-pivotitem-header-color-in-windows-phone-8-1-xaml/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Changing the PivotItem header color in Windows Phone 8.1 XAML" 3 | author = "Igor Kulman" 4 | date = "2014-12-29" 5 | url = "/changing-the-pivotitem-header-color-in-windows-phone-8-1-xaml/" 6 | categories = ["Windows Phone"] 7 | tags = ["Csharp","Windows Phone","WinRT","XAML"] 8 | +++ 9 | Windows Phone 8.1 XAML contains a Pivot control that looks like the one from Windows Phone 7/8 and also should behave the same way, but does not. You will find the first problem with the new Pivot when you want to change the PivotItem header color. 10 | 11 | **Windows Phone 7/8** 12 | 13 | If you want to change the PivotItem header color in Windows Phone 7/8, you just define the color in the Header template: 14 | 15 | ```xml 16 | 17 | 18 | 19 | ``` 20 | 21 | This works great, changing the color of the active PivotItem Header to the color you want and applying some opacity to the inactive PivotItem Headers. 22 | 23 | ![Pivot header on Windows Phone 7 and 8](header78.png) 24 | 25 | 26 | 27 | **Windows Phone 8.1 XAML** 28 | 29 | If you apply the same Header template to PivotItem in Windows Phone 8.1 XAML, you will find that there is a bug in the control. The inactive PivotItem Headers do not get opacity change applied. 30 | 31 | ![Pivot header on Windows Phone 8.1 XAML](header81.png) 32 | 33 | This is obviously a problem, if you do not want to do same SelectedIndex manipulation to change the color programatically for all the inactive PivotItem headers. 34 | 35 | Luckily, there is a way to fix this. You can redefine the PivotHeaderForegroundUnselectedBrush and PivotHeaderForegroundSelectedBrush to the active and inactive colors of your choice. 36 | 37 | ```xml 38 | 41 | 44 | ``` 45 | -------------------------------------------------------------------------------- /content/post/2014/converting-between-pixels-meters-and-map-coordinates-in-windows-phone/image_thumb_4_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2014/converting-between-pixels-meters-and-map-coordinates-in-windows-phone/image_thumb_4_4.png -------------------------------------------------------------------------------- /content/post/2014/detecting-tablets-and-smartphones-in-asp-net/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Detecting tablets and smartphones in ASP.NET" 3 | author = "Igor Kulman" 4 | date = "2014-09-22" 5 | url = "/detecting-tablets-and-smartphones-in-asp-net/" 6 | categories = ["WinRT"] 7 | tags = ["ASP","Csharp"] 8 | +++ 9 | I recently worked on an ASP.NET application that needed to detect if users were coming from tablets or smartphones. The project used data from to do this detection, but the result were not really good. We needed a better solution, so I came up with using [WURFL][1]. 10 | 11 | WURFL, the Wireless Universal Resource FiLe, is a Device Description Repository (DDR), i.e. a software component that maps HTTP Request headers to the profile of the HTTP client (Desktop, Mobile Device, Tablet, etc.) that issued the request. Adding WURFL to your ASP.NET application is easy thanks to the [WURFL\_Official\_API Nuget package][2]. The Nuget package also contains definition file, so you just need to update the Nuget package once in a while to get your definition file up to date. 12 | 13 | 14 | 15 | After installing the Nuget package, you need to setup WURLF in your Global.asax file 16 | 17 | ```csharp 18 | var wurflDataFile = HttpContext.Current.Server.MapPath("~/App_Data/wurfl-latest.zip"); 19 | var configurer = new InMemoryConfigurer().MainFile(wurflDataFile).SetMatchMode(MatchMode.Accuracy); 20 | WURFLManagerBuilder.Build(configurer); 21 | ``` 22 | 23 | I recommend setting the match mode to accuracy instead of speed, to get the best results. Using the WURFL library is also quite easy, just pass the user agent string and get the properties you want. 24 | 25 | ```csharp 26 | var device = WURFLManagerBuilder.Instance.GetDeviceForRequest(context.Request.UserAgent); 27 | var isTablet = Boolean.Parse(device.GetCapability("is_tablet")); 28 | var isMobileDevice = Boolean.Parse(device.GetCapability("is_smartphone")); 29 | ``` 30 | 31 | [1]: http://wurfl.sourceforge.net/ 32 | [2]: https://www.nuget.org/packages/WURFL_Official_API/ 33 | -------------------------------------------------------------------------------- /content/post/2014/experience-with-being-featured-in-the-red-stripe-deal-promotion-on-windows-phone/sk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2014/experience-with-being-featured-in-the-red-stripe-deal-promotion-on-windows-phone/sk.png -------------------------------------------------------------------------------- /content/post/2014/how-to-get-rid-of-the-strange-line-under-systray-in-windows-phone-8/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "How to get rid of the strange line under systray in Windows Phone 8" 3 | author = "Igor Kulman" 4 | date = "2014-03-24" 5 | url = "/how-to-get-rid-of-the-strange-line-under-systray-in-windows-phone-8/" 6 | categories = ["Windows Phone"] 7 | tags = ["Csharp","Windows Phone","XAML"] 8 | +++ 9 | If you create an Windows Phone 8 app and test it only on WVGA and 720p devices or emulators, you may be surprised how you app looks on a WXGA device (or emulator). 10 | 11 | ![1px bug](line.png) 12 | 13 | I have not been able the reason why this happens but the solution is quite simple. Set your page's top border to -1. 14 | 15 | 16 | 17 | ```xml 18 | 19 | ``` 20 | 21 | Doing this in XAML for every page is not very convenient, a better solution would be to set the negative top margin on the whole application frame 22 | 23 | ```csharp 24 | private void InitializePhoneApplication() 25 | { 26 | RootFrame.Margin = new Thickness(0, -1, 0, 0); 27 | } 28 | ``` 29 | 30 | If you use Caliburn.Micro, you need to override the CreatePhoneApplicationFrame in the Bootstrapper instead 31 | 32 | ```csharp 33 | protected override PhoneApplicationFrame CreatePhoneApplicationFrame() 34 | { 35 | var frame = new PhoneApplicationFrame { Margin = new Thickness(0, -1, 0, 0) }; 36 | return frame; 37 | } 38 | ``` 39 | 40 | [1]: http://blog.kulman.sk/wp-content/uploads/2014/03/line.png 41 | -------------------------------------------------------------------------------- /content/post/2014/how-to-get-rid-of-the-strange-line-under-systray-in-windows-phone-8/line.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2014/how-to-get-rid-of-the-strange-line-under-systray-in-windows-phone-8/line.png -------------------------------------------------------------------------------- /content/post/2014/ignoring-certificate-errors-in-windows-phone-8-1/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Ignoring certificate errors in Windows Phone 8.1" 3 | author = "Igor Kulman" 4 | date = "2014-06-11" 5 | url = "/ignoring-certificate-errors-in-windows-phone-8-1/" 6 | categories = ["Windows Phone"] 7 | tags = ["Csharp","Windows Phone","WinRT", "Security"] 8 | +++ 9 | Connecting to servers with self-signed, expired or otherwise problematic certificates has always been a problem in Windows Phone. There is no way to ignore certificate errors in Windows Phone 7 and Windows Phone 8, not even using the new Portable HTTP Client Libraries. If you are dealing with a self-signed certificate on the server, you have to somehow get it (may not always be possible) and install it on the device or in the emulator (for emulator every time you close and start it again). Ignoring certificate errors would be a much more comfortable approach. Of course, only do it in development with dev servers, not in production. 10 | 11 | In Windows Phone 8.1 there are strangely two `HttpClient` classes, one in `System.Net.Http` and another in `Windows.Web.Http`. Normally you would go with the one in `System.Net.Http` because you are probably using it thanks to the mentioned Portable HTTP Client Libraries on every other platform. You are out of luck in Windows Phone 8.1 XAML, if you want to ignore certificate errors, you have to use the one from `Windows.Web.Http`, because only this one accepts an `IHttpFilter` as an argument. 12 | 13 | 14 | 15 | Using the `IHttpFilter`, you can easily ignore certificate errors 16 | 17 | ```csharp 18 | var filter = new HttpBaseProtocolFilter(); 19 | #if DEBUG 20 | // ******************* 21 | // IGNORING CERTIFACTE PROBLEMS 22 | // ******************* 23 | filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.IncompleteChain); 24 | filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.Expired); 25 | filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.Untrusted); 26 | filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.InvalidName); 27 | // ******************* 28 | #endif 29 | 30 | var httpClient = new Windows.Web.Http.HttpClient(filter); 31 | ``` 32 | 33 | but you have to get used to doing all the request in a different way, the `Windows.Web.Http.HttpClient` way that differs from the `System.Net.Http.HttpClient` way. 34 | -------------------------------------------------------------------------------- /content/post/2014/making-your-windows-phone-silverlight-8-1-app-a-share-contract-target/wp81.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2014/making-your-windows-phone-silverlight-8-1-app-a-share-contract-target/wp81.png -------------------------------------------------------------------------------- /content/post/2014/pock8-beautiful-pocket-client-for-windows-phone/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Pock8: beautiful Pocket client for Windows Phone" 3 | author = "Igor Kulman" 4 | date = "2014-03-14" 5 | url = "/pock8-beautiful-pocket-client-for-windows-phone/" 6 | categories = ["Windows Phone"] 7 | tags = ["Windows Phone"] 8 | +++ 9 | Recently I have released a new Windows Phone app called [Pock8][1]. Pock8 is a beautiful Pocket (formerly Read It Later) client for Windows Phone. The design of the app was created by Jan Marek who worked with my on the [Shopping List Simple][2] app. 10 | 11 | ![Pock8](pocket.png) 12 | 13 | Our goal was to create a Pocket client that would be really easy to use and that would have a nice and simple design. I think we have achieved our goal. The main features of the app are 14 | 15 | * clean and simple design 16 | * optimized article view for comfortable reading 17 | * article cache for offline reading 18 | * dark theme for OLED screens or reading in the dark 19 | * support for receiving articles from other apps like WPCentral 20 | * listening to articles aloud 21 | * sharing articles 22 | 23 | 24 | 25 | In version 1.2 we really concentrated on user feedback and added many features that our users requested. We love and users and want to make them happy. 26 | 27 | The app is free to use with one limitation, all the list display just 5 articles at any time. You can use an in-app purchase to get rid of the limitation and support further development of the app. 28 | 29 | For more info about [Pock8][1], follow the app on Twitter at [@pock8app][4]. 30 | 31 | Pock8 32 | 33 | [1]: http://t.co/YMtrM84rwI 34 | [2]: http://windowsphone.com/s?appid=b2667b3c-9272-4416-b0be-c8adadc651e4 35 | [3]: http://www.kulman.sk/data/timelinejs/pocket.png 36 | [4]: https://twitter.com/pock8app 37 | -------------------------------------------------------------------------------- /content/post/2014/pock8-beautiful-pocket-client-for-windows-phone/pocket.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2014/pock8-beautiful-pocket-client-for-windows-phone/pocket.png -------------------------------------------------------------------------------- /content/post/2014/tvtime-track-your-favorite-tv-shows-on-windows-phone/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "TvTime: track your favorite TV shows on Windows Phone" 3 | author = "Igor Kulman" 4 | date = "2014-09-16" 5 | url = "/tvtime-track-your-favorite-tv-shows-on-windows-phone/" 6 | categories = ["Windows Phone"] 7 | tags = ["Csharp","Windows Phone","Windows Store","XAML"] 8 | +++ 9 | We have just had released a new app called TvTime. TvTime is a simple and beautiful app for tracking your favorite TV Shows. Simply add a find the TV Shows you like, add them to the list and get detailed information about actors, air times and episodes. If you decide to track unwatched episodes, you will always know what you have already seen. So get TvTime now so you never miss your favorite TV Show! 10 | 11 | ![TvTime](tvtimepromo.jpg) 12 | 13 | Main features 14 | 15 | * clean and simple design 16 | * thousands of TV Shows to choose 17 | * tracking unwatched episodes 18 | * live tile 19 | * show and episodes details 20 | 21 | You can download the app for free here. 22 | 23 | 24 | 25 | Get it on Windows 10 26 | 27 | [1]: http://blog.kulman.sk/wp-content/uploads/2014/09/tvtimepromo.jpg 28 | -------------------------------------------------------------------------------- /content/post/2014/tvtime-track-your-favorite-tv-shows-on-windows-phone/tvtimepromo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2014/tvtime-track-your-favorite-tv-shows-on-windows-phone/tvtimepromo.jpg -------------------------------------------------------------------------------- /content/post/2014/visual-studio-template-for-caliburn-micro-windows-phone-apps/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Visual Studio template for Caliburn.Micro Windows Phone apps" 3 | author = "Igor Kulman" 4 | date = "2014-11-03" 5 | url = "/visual-studio-template-for-caliburn-micro-windows-phone-apps/" 6 | categories = ["Windows Phone"] 7 | tags = ["Csharp","Caliburn-Micro","Windows Phone","XAML"] 8 | +++ 9 | I have been building Windows Phone apps using the [Caliburn.Micro][1] framework for some time now. Setting up a new project takes some time and can be easily automated, so I decided to create a Visual Studio template for Windows Phone apps build with Caliburn.Micro. 10 | 11 | The templates can be downloaded from [the Visual Studio Extensions gallery][2] and used to build Windows Phone 8 and Windows Phone 8.1 Silverlight apps. It contains the basic setup with Caliburn Micro and [Fody][3], with a sample view and viewmodel. 12 | 13 | The [source code is available on GitHub][4], so if you want to modify it to best suit your needs, feel free to do it. 14 | 15 | {{% github-repo "igorkulman/CaliburnWP8AppVSIX" %}} 16 | 17 | 18 | 19 | [1]: https://github.com/Caliburn-Micro/Caliburn.Micro 20 | [2]: https://visualstudiogallery.msdn.microsoft.com/21b4568e-1fb9-4881-9d51-8e1ea0160a9f 21 | [3]: http://blog.kulman.sk/inotifypropertychanged-the-easy-way-in-windows-phone-and-windows-8/ "INotifyPropertyChanged the easy way in Windows Phone and Windows 8" 22 | [4]: https://github.com/igorkulman/CaliburnWP8AppVSIX 23 | -------------------------------------------------------------------------------- /content/post/2014/what-to-put-on-the-about-screen-of-your-windows-phone-app/about1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2014/what-to-put-on-the-about-screen-of-your-windows-phone-app/about1.png -------------------------------------------------------------------------------- /content/post/2014/what-to-put-on-the-about-screen-of-your-windows-phone-app/about2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2014/what-to-put-on-the-about-screen-of-your-windows-phone-app/about2.png -------------------------------------------------------------------------------- /content/post/2014/why-universal-apps-as-not-as-universal-as-you-may-think/56995992.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2014/why-universal-apps-as-not-as-universal-as-you-may-think/56995992.jpg -------------------------------------------------------------------------------- /content/post/2015/a-week-with-microsoft-band-2/BandDashboard1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2015/a-week-with-microsoft-band-2/BandDashboard1.png -------------------------------------------------------------------------------- /content/post/2015/a-week-with-microsoft-band-2/BandDashboard2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2015/a-week-with-microsoft-band-2/BandDashboard2.png -------------------------------------------------------------------------------- /content/post/2015/a-week-with-microsoft-band-2/BandDisplay.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2015/a-week-with-microsoft-band-2/BandDisplay.jpg -------------------------------------------------------------------------------- /content/post/2015/a-week-with-microsoft-band-2/BandGPS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2015/a-week-with-microsoft-band-2/BandGPS.png -------------------------------------------------------------------------------- /content/post/2015/a-week-with-microsoft-band-2/BandSetup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2015/a-week-with-microsoft-band-2/BandSetup.png -------------------------------------------------------------------------------- /content/post/2015/a-week-with-microsoft-band-2/BandSleep1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2015/a-week-with-microsoft-band-2/BandSleep1.png -------------------------------------------------------------------------------- /content/post/2015/a-week-with-microsoft-band-2/BandSleep2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2015/a-week-with-microsoft-band-2/BandSleep2.png -------------------------------------------------------------------------------- /content/post/2015/a-week-with-microsoft-band-2/BandSteps.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2015/a-week-with-microsoft-band-2/BandSteps.png -------------------------------------------------------------------------------- /content/post/2015/a-week-with-microsoft-band-2/BandUI1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2015/a-week-with-microsoft-band-2/BandUI1.png -------------------------------------------------------------------------------- /content/post/2015/a-week-with-microsoft-band-2/BandUI2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2015/a-week-with-microsoft-band-2/BandUI2.png -------------------------------------------------------------------------------- /content/post/2015/automatically-push-your-git-repos-before-computer-shutdown/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Automatically push your Git repos before computer shutdown" 3 | author = "Igor Kulman" 4 | date = "2015-02-02" 5 | url = "/automatically-push-your-git-repos-before-computer-shutdown/" 6 | categories = ["PowerShell"] 7 | tags = ["Git","PowerShell"] 8 | +++ 9 | I use two computers, my desktop computer located at home and set up for work and play and a work notebook (company provided) that I usually leave at the office. I use both computers for work and sometimes I forget to do ‘git push’ when working at my home desktop computer. The next day, when using the work notebook, I wonder where the code from the previous day has disappeared. 10 | 11 | Of course, I can solve it by connecting to my home Raspberry Pi through SSH, waking the desktop computer over LAN from it, connecting to it using Remote Desktop to do the ‘git push’ .. not really a simple solution, there must be a better way. 12 | 13 | 14 | 15 | So I came up with a really simple PowerShell script to iterate to a directory with git projects and execute ‘git push’ on all of them 16 | 17 | ```powershell 18 | Get-ChildItem D:\Projects\Apps | ForEach-Object { 19 | cd $_.FullName 20 | git push 21 | } 22 | ``` 23 | 24 | To make the script execute on each computer shutdown, run **gpedit.msc** and go to **Computer Configuration** | **Windows Settings** | **Scripts (Startup/Shutdown)** | **Shutdown** and add the script. Adding the script just by referencing the .ps1 file did not work for me, I had to add the path to PowerShell (%SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe) with the script as a parameter. 25 | -------------------------------------------------------------------------------- /content/post/2015/back-navigation-on-backspace-key-press-in-windows-8-1-apps/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Back navigation on Backspace key press in Windows 8.1 apps" 3 | author = "Igor Kulman" 4 | date = "2015-03-03" 5 | url = "/back-navigation-on-backspace-key-press-in-windows-8-1-apps/" 6 | categories = ["Windows Phone", "Windows Store"] 7 | tags = ["Windows Phone", "Windows Store"] 8 | +++ 9 | I am not a mouse or a touch person, I like using the keyboard and keyboard shortcuts for everything. So when I (have to) use a Windows 8.1 Metro app, I always miss when the app does not navigate back when I press the Backspace key, just like the browser does. 10 | 11 | Implementing this functionality is really simple, you just need to handle the KeyUp event and listen for the Backspace key. You can implement the KeyUp event handler on every View in your app, but that is not necessary. You can just hook up the global Window.Current.CoreWindow.KeyUp event after you app starts. 12 | 13 | 14 | 15 | ```csharp 16 | Window.Current.CoreWindow.KeyUp += (_, args) => 17 | { 18 | if (args.VirtualKey == VirtualKey.Back) 19 | { 20 | var element = FocusManager.GetFocusedElement(); 21 | if (element is TextBox || element is PasswordBox) 22 | { 23 | return; //do not disturb user when typing 24 | } 25 | 26 | var frame = (Frame)Window.Current.Content; 27 | if (frame.CanGoBack) 28 | { 29 | frame.GoBack(); 30 | } 31 | } 32 | }; 33 | ``` 34 | 35 | If you implement this in your app, I am sure you will make some of your users more happy. 36 | -------------------------------------------------------------------------------- /content/post/2015/customizing-the-player-framework-ui/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Customizing the Player Framework UI" 3 | author = "Igor Kulman" 4 | date = "2015-05-04" 5 | url = "/customizing-the-player-framework-ui/" 6 | categories = ["Windows Phone","Windows Store"] 7 | tags = ["Windows Phone","Windows Store", "XAML"] 8 | keywords = ["Windows Phone","Windows Store", "XAML", "PlayerFramework"] 9 | +++ 10 | In my last article I gave you a tip on how to localize the Player Framework, in this article I will show you have to customize the UI of the actual player. 11 | 12 | The first step is to obtain the Generic.xaml file that the Player Framework uses for styling. You can find it in `C:\ Program Files (x86)\ Microsoft SDKs\ Windows\ v8.0\ ExtensionSDKs\ Microsoft.PlayerFramework.Xaml\ 2.0.0.0\ Redist\ CommonConfiguration\ neutral\ Microsoft.PlayerFramework\ Themes`. Copy it to your projects and rename it to something more telling, like PlayerFramework.xaml. 13 | 14 | You can now edit the copied XAML file and customize it any way you want. If you do the styling for a Windows Phone app, keep in mind that the ControlPanel switches to the Compact states and a few transformations are applied by default, that can interfere with your styling. 15 | 16 | 17 | 18 | Finally, you need to apply the style by adding it to the page with your player 19 | 20 | ```xml 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | ``` 29 | -------------------------------------------------------------------------------- /content/post/2015/enabling-and-disabling-hardware-devices-with-powershell/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Enabling and disabling hardware devices with PowerShell" 3 | author = "Igor Kulman" 4 | date = "2015-11-06" 5 | url = "/enabling-and-disabling-hardware-devices-with-powershell/" 6 | categories = ["PowerShell"] 7 | tags = ["PowerShell"] 8 | Keywords = [ "PowerShell", "Windows"] 9 | +++ 10 | I have a built-in fingerprint reader on my Thinkpad notebook that I use for loging in almost exclusively. I say almost because since I upgraded to Windows 10 it sometimes just stops working when the computer wakes up from sleep. I found out that to make it work again I have to go to the Device Manager, find it, disable it and enabled it back again. 11 | 12 | Of course, I was looking for a way to automate this, because I do not think that this issue will be fixed any time soon by Microsoft or Lenovo. I found out there is a [PowerShell cmdlet that expose device enumeration and management APIs](https://gallery.technet.microsoft.com/Device-Management-7fad2388). Using this cmdlet I wrote a simple PowerShell script to the the work. 13 | 14 | 15 | 16 | It has to be run with administrator privileges to work. Maybe I will go one step further and make this script run each time the notebook wakes up, just to be sure. 17 | 18 | ```powershell 19 | Import-Module DeviceManagement.psd1 20 | 21 | Get-Device | where {$_.name -like "Synaptics FP Sensors*"} | Disable-Device 22 | Get-Device | where {$_.name -like "Synaptics FP Sensors*"} | Enable-Device 23 | ``` 24 | -------------------------------------------------------------------------------- /content/post/2015/highlighting-letters-in-textblock-in-windows-phone-8-1-and-windows-8-1/highlighting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2015/highlighting-letters-in-textblock-in-windows-phone-8-1-and-windows-8-1/highlighting.png -------------------------------------------------------------------------------- /content/post/2015/highlighting-letters-in-textblock-in-windows-phone-8-1-and-windows-8-1/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Highlighting letters in TextBlock in Windows Phone 8.1 and Windows 8.1" 3 | author = "Igor Kulman" 4 | date = "2015-10-17" 5 | url = "/highlighting-letters-in-textblock-in-windows-phone-8-1-and-windows-8-1/" 6 | categories = ["Windows Phone","Windows Store"] 7 | tags = ["Windows Phone","Windows Store","XAML"] 8 | keywords = ["Windows Phone","Windows Store","XAML"] 9 | +++ 10 | In my current project I had to implement an interesting feature for both Windows Phone 8.1 and Windows 8.1 project of the Universal app. The idea is simply. The users want to search for a movie. They enter a search term into a TextBox and a list of results is shown. The results should have the search term highlighted in them. 11 | 12 | ![Searcg term highlight](highlighting.png) 13 | 14 | 15 | 16 | The standard TextBlock used to display the movie titles does not support any kind of letter highlighting, so I had to write a custom one. I created a custom UserControl. The UserControl contains a few dependency properties Text, HighlightedText, HighlightBrush and a TextBlock. When Text or HighlightedText change, the Text is then split into multiple Runs that are added to the TextBlock. 17 | 18 | ```csharp 19 | private void Update() 20 | { 21 | if (string.IsNullOrEmpty(Text) || string.IsNullOrEmpty(HighlightedText)) 22 | { 23 | TB.Inlines.Clear(); 24 | return; 25 | } 26 | 27 | TB.Inlines.Clear(); 28 | var parts = Regex.Split(Text, HighlightedText, RegexOptions.IgnoreCase); 29 | var len = 0; 30 | foreach (var part in parts) 31 | { 32 | len = len + part.Length + 1; 33 | 34 | TB.Inlines.Add(new Run 35 | { 36 | Text = part 37 | }); 38 | 39 | if (Text.Length >= len) 40 | { 41 | var highlight = Text.Substring(len - 1, HighlightedText.Length); //to match the case 42 | 43 | TB.Inlines.Add(new Run 44 | { 45 | Text = highlight, 46 | Foreground = HighlightBrush 47 | }); 48 | } 49 | } 50 | } 51 | ``` 52 | 53 | The whole working custom control is available at Github: . 54 | 55 | {{% github-repo "igorkulman/Kulman.WPA81.HighlightTextBox" %}} 56 | -------------------------------------------------------------------------------- /content/post/2015/measuring-and-recording-the-room-temperature-with-a-raspberry-pi/pi-history.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2015/measuring-and-recording-the-room-temperature-with-a-raspberry-pi/pi-history.png -------------------------------------------------------------------------------- /content/post/2015/measuring-and-recording-the-room-temperature-with-a-raspberry-pi/pi-ui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2015/measuring-and-recording-the-room-temperature-with-a-raspberry-pi/pi-ui.png -------------------------------------------------------------------------------- /content/post/2015/measuring-and-recording-the-room-temperature-with-a-raspberry-pi/pitherm.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2015/measuring-and-recording-the-room-temperature-with-a-raspberry-pi/pitherm.jpg -------------------------------------------------------------------------------- /content/post/2015/mobilize-net-converting-windows-phone-apps-to-uwp/Windows10-Devices.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2015/mobilize-net-converting-windows-phone-apps-to-uwp/Windows10-Devices.png -------------------------------------------------------------------------------- /content/post/2015/my-year-with-the-raspberry-pi-and-what-i-used-it-for/pi-ui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2015/my-year-with-the-raspberry-pi-and-what-i-used-it-for/pi-ui.png -------------------------------------------------------------------------------- /content/post/2015/my-year-with-the-raspberry-pi-and-what-i-used-it-for/pitherm.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2015/my-year-with-the-raspberry-pi-and-what-i-used-it-for/pitherm.jpg -------------------------------------------------------------------------------- /content/post/2015/player-framework-localization/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Player Framework localization" 3 | author = "Igor Kulman" 4 | date = "2015-04-27" 5 | url = "/player-framework-localization/" 6 | categories = ["Windows Phone","Windows Store"] 7 | tags = ["Windows Phone","Windows Store","XAML", "PlayerFramework"] 8 | +++ 9 | In my recent universal (Windows Phone 8.1 and Windows 8.1) project I implemented PlayReady DRM protected smooth streaming movies playback using the [Player Framework][1]. This projects seems to be dead, but it is still the best option when implementing any kind of video playback. 10 | 11 | One of the first things I had to do was localize it’s controls, because the app I worked on was in Czech and Slovak, not in English (the only language the Player Framework supports out of the box). Not all the texts an be localized, but the most visible ones like button labels and error messages can. 12 | 13 | To create your own localization, I suggest you create a new RESW file in your project. You can use and existing one, but I prefer to separate the texts for the Player Framework from texts for the rest of the app. 14 | 15 | 16 | 17 | Next you have to find out the keys for the string you want to localize. You an [find them in the source code][2]. You can just copy the content of that RESW file to yours RESW file and localized everything. 18 | 19 | The last step is to let the PlayerFramework know about your RESW file using 20 | 21 | ```csharp 22 | MediaPlayer.ResourceLoader = ResourceLoader.GetForCurrentView("PlayerFramework"); //using PlayerFramework.resw in the project 23 | ``` 24 | 25 | [1]: https://playerframework.codeplex.com/ 26 | [2]: https://playerframework.codeplex.com/SourceControl/latest#Win8.Xaml.Localize.Win81/en-US/PlayerFramework.resw 27 | -------------------------------------------------------------------------------- /content/post/2015/problems-getting-paid-from-the-windows-store-again/payout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2015/problems-getting-paid-from-the-windows-store-again/payout.png -------------------------------------------------------------------------------- /content/post/2015/quick-tip-showing-solution-branch-name-in-visual-studio-title/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Quick Tip: Showing solution branch name in Visual Studio title" 3 | author = "Igor Kulman" 4 | date = "2015-07-21" 5 | url = "/quick-tip-showing-solution-branch-name-in-visual-studio-title/" 6 | categories = ["Programming in general"] 7 | tags = ["Git","Tip","Visual Studio"] 8 | keywords = ["Git","Tip","Visual Studio"] 9 | +++ 10 | By default, Visual Studio shows the name of the opened solution name in the title. This makes it easier to navigate among multiple instances of Visual Studio. You see the solution name next to the Visual Studio icon in the taskbar and also in the task manager, when you have to (and we all sometimes have to) kill the right Visual Studio because it stopped responding. 11 | 12 | I work with Git, switching branches frequently, especially working on features and bug fixes. In this situation, it would be nice if Visual Studio showed not only the solution name but also the current branch in its title. No problem, there is an extension for that. 13 | 14 | The extension is called [Rename Visual Studio Window][1] and it works with Visual Studio 2015, 2013, 2012, 2010. This extension supports Git, so you can easily add the branch name to the title with a config like mine using [gitBranchName]. 15 | 16 | ![Rename Visual Studio Window](rename.png) 17 | 18 | 19 | 20 | Your taskbar will then look like this 21 | 22 | ![Multiple projects in tray](trayalya.png) 23 | 24 | [1]: https://visualstudiogallery.msdn.microsoft.com/f3f23845-5b1e-4811-882f-60b7181fa6d6 25 | -------------------------------------------------------------------------------- /content/post/2015/quick-tip-showing-solution-branch-name-in-visual-studio-title/rename.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2015/quick-tip-showing-solution-branch-name-in-visual-studio-title/rename.png -------------------------------------------------------------------------------- /content/post/2015/quick-tip-showing-solution-branch-name-in-visual-studio-title/trayalya.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2015/quick-tip-showing-solution-branch-name-in-visual-studio-title/trayalya.png -------------------------------------------------------------------------------- /content/post/2015/removing-unused-strings-from-windows-phone-8-resx-files/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Removing unused strings from Windows Phone 8 RESX files" 3 | author = "Igor Kulman" 4 | date = "2015-05-25" 5 | url = "/removing-unused-strings-from-windows-phone-8-resx-files/" 6 | categories = ["Windows Phone", "Windows Store"] 7 | tags = ["Windows Phone", "Windows Store"] 8 | keywords = ["Windows Phone", "Windows Store", "XAML"] 9 | +++ 10 | Using RESX files is the standard approach to Windows Phone 8 app localization, it is even contained in the standard project templates. When you work on a project for a longer time, you may get to a situation that your RESX files contain strings that you no longer use. This is a problem especially when you want to add a new localization, because it is slower and kind of wasteful localizing unused strings. 11 | 12 | To solve this problem I have created a simple command line utility, that is [available at Github][1]. This utility assumes that you use the standard localization approach from the templates (AppResources.{lang}.resx and LocalizedStrings.{value} in XAML). 13 | 14 | 15 | 16 | The usage is really simple. Just run the utility with the path to your project as a parameter. It will detect all resources files and remove all the unused strings from them. 17 | 18 | [1]: https://github.com/igorkulman/RemoveUnusedResources 19 | 20 | {{% github-repo "igorkulman/RemoveUnusedResources" %}} 21 | -------------------------------------------------------------------------------- /content/post/2015/the-death-of-the-winrt-developer/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "The death of the WinRT developer?" 3 | author = "Igor Kulman" 4 | date = "2015-04-30" 5 | url = "/the-death-of-the-winrt-developer/" 6 | categories = ["Windows Phone","Windows Stre"] 7 | tags = ["Windows Phone","Windows Store","XAML"] 8 | +++ 9 | As many other Windows Phone / Windows 8 / Universal apps developers (lets just call us WinRT developers) I watched the Build 2015 keynote last night. And I did not like it. I know Microsoft does not know to communicate but the message for me was clear. We, the WinRT developer, are no longer needed. 10 | 11 | First, Microsoft announced that WPF apps will be allowed to be submitted to the Windows Store to be used on desktops / tablets. So why would anyone want to develop (or want to have developed) a Windows 8 (WinRT) app, when they can just use WPF and get everything done easier? I do not know. 12 | 13 | But allowing WPF apps to the Windows Store is a small news compared to the ability to run Android apps on Windows Phone. The first news talked about porting Android apps to the Windows Phone, but later, [statements like this][1] appeared 14 | 15 | _Android developers will be able to submit versions of their apps, written in Java or C++, to the Windows Store in he form of APKs and have those apps work on Windows Phone 10 devices. Android developers should be able to start submitting apps to the Windows 10 Store some time in the next few months._ 16 | 17 | 18 | 19 | So let get this straight. Who would want a native mobile Windows app developed, when they can just take their Android app and use it on Windows? What company would want to keep their mobile Windows team, when they can just use their Android team to make Windows apps? 20 | 21 | Sure, Android apps will probably not run on XBOX and HoloLens, but I doubt Microsoft will open the XBOX store for all the developers, more likely only chosen companies will be allowed to publish apps. HoloLens will be used only by a small number of people if this price is not really low (which I doubt it will be), so only a few HoloLens apps will be needed. 22 | 23 | For me, the situation seems clear, it is the death of the WinRT developer. 24 | 25 | [1]: http://www.zdnet.com/article/heres-how-microsoft-hopes-to-get-android-and-ios-phone-apps-into-its-windows-10-store/ 26 | -------------------------------------------------------------------------------- /content/post/2015/using-etag-to-cache-responses-in-nancyfx/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Using ETag to cache responses in NancyFX" 3 | author = "Igor Kulman" 4 | date = "2015-04-15" 5 | url = "/using-etag-to-cache-responses-in-nancyfx/" 6 | categories = ["Windows Azure"] 7 | tags = ["ASP","Azure","NancyFX"] 8 | keywords = ["ASP","Azure","NancyFX", "Cloud"] 9 | +++ 10 | Caching data is usually a good idea, especially when creating APIs for mobile clients and the user may pay for each transferred byte. There are many approaches to caching data (I recommend reading [this article][1]), in my last NancyFX project I used ETag. 11 | 12 | **ETag** 13 | 14 | ETag is a HTTP header that acts as a hash of the data. When the server returns a response, it computes a hash of the data and sends it to the client. When the client requests the data again, it includes the ETag in its request. The server compares the ETag with the hash of the current data and if they match (the data did not change), it returns an empty responses with a HTTP 304 status code. 15 | 16 | 17 | 18 | ```csharp 19 | /// 20 | /// Gets response with ETag. Returns empty body if ETag matches (no data changes) 21 | /// 22 | /// Data to match with ETag 23 | /// Model to return 24 | /// Response 25 | protected Response GetResponseWithEtag(object data, object model) 26 | { 27 | string etag = Utils.ComputeHash(data); 28 | 29 | if (CacheHelpers.ReturnNotModified(etag, null, this.Context)) 30 | { 31 | return HttpStatusCode.NotModified; 32 | } 33 | 34 | return Response.AsJson(model).WithHeader("ETag", etag); 35 | } 36 | ``` 37 | 38 | **NancyFX impelemntation** 39 | 40 | To implement caching using ETag in NancyFX I use a method in my base module 41 | 42 | There are two parameters in this method, because you may sometimes want to compute the ETag from only a part of the returned model. 43 | 44 | Using this method is the really simple 45 | 46 | ```csharp 47 | Get["/startlist/{id}"] = parameters => 48 | { 49 | var startList = _competitionService.GetStartList((int)parameters.id); 50 | var model = new StartListModel() { StartList = startList }; 51 | 52 | return GetResponseWithEtag(startList, model); 53 | }; 54 | ``` 55 | 56 | [1]: http://frontendplay.com/2013/05/22/http-caching-demystified/ 57 | -------------------------------------------------------------------------------- /content/post/2015/visual-studio-extensions-to-make-your-life-easier/asyncfixer-1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2015/visual-studio-extensions-to-make-your-life-easier/asyncfixer-1.gif -------------------------------------------------------------------------------- /content/post/2015/visual-studio-extensions-to-make-your-life-easier/guides.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2015/visual-studio-extensions-to-make-your-life-easier/guides.png -------------------------------------------------------------------------------- /content/post/2015/visual-studio-extensions-to-make-your-life-easier/trayalya.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2015/visual-studio-extensions-to-make-your-life-easier/trayalya.png -------------------------------------------------------------------------------- /content/post/2015/visual-studio-extensions-to-make-your-life-easier/vscoloroutput.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2015/visual-studio-extensions-to-make-your-life-easier/vscoloroutput.png -------------------------------------------------------------------------------- /content/post/2016/choosing-and-image-from-gallery-or-camer-in-uwp/uwp.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2016/choosing-and-image-from-gallery-or-camer-in-uwp/uwp.gif -------------------------------------------------------------------------------- /content/post/2016/choosing-and-image-from-gallery-or-camer-in-uwp/uwp2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2016/choosing-and-image-from-gallery-or-camer-in-uwp/uwp2.gif -------------------------------------------------------------------------------- /content/post/2016/choosing-and-image-from-gallery-or-camer-in-uwp/wpa81.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2016/choosing-and-image-from-gallery-or-camer-in-uwp/wpa81.gif -------------------------------------------------------------------------------- /content/post/2016/creating-a-simple-windows-10-game-with-win2d/sokoban-dpad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2016/creating-a-simple-windows-10-game-with-win2d/sokoban-dpad.png -------------------------------------------------------------------------------- /content/post/2016/creating-a-simple-windows-10-game-with-win2d/sokoban-gameplay.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2016/creating-a-simple-windows-10-game-with-win2d/sokoban-gameplay.gif -------------------------------------------------------------------------------- /content/post/2016/creating-better-forms-in-windows-phone-apps/forms1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2016/creating-better-forms-in-windows-phone-apps/forms1.gif -------------------------------------------------------------------------------- /content/post/2016/creating-better-forms-in-windows-phone-apps/forms2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2016/creating-better-forms-in-windows-phone-apps/forms2.gif -------------------------------------------------------------------------------- /content/post/2016/fixing-first-annoyances-with-bash-on-windows/bash-cmder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2016/fixing-first-annoyances-with-bash-on-windows/bash-cmder.png -------------------------------------------------------------------------------- /content/post/2016/how-to-handle-localization-strings-provided-by-client/languages.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2016/how-to-handle-localization-strings-provided-by-client/languages.png -------------------------------------------------------------------------------- /content/post/2016/using-tooltips-to-make-better-menus-in-windows-apps/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | Categories = [ "Windows Phone", "Windows Store", "UWP" ] 3 | Description = "If you use Windows apps with navigation menus consisting of icons, you may have noticed that some of those apps show you a text when hovering above those icons. This is a nice touch for the users, allowing them to quickly grasp the meaning of the menu icons without the need to click them or to expand the menu (if available)." 4 | Tags = ["Windows Phone", "Windows Store", "UWP"] 5 | Keywords = ["Windows Phone", "Windows Store", "UWP", "XAML"] 6 | author = "Igor Kulman" 7 | date = "2016-03-23T09:29:12+01:00" 8 | title = "Using Tooltips to make better menus in Windows apps" 9 | url = "/using-tooltips-to-make-better-menus-in-windows-apps" 10 | images = ["/images/tooltips.gif"] 11 | 12 | +++ 13 | 14 | If you use Windows apps with navigation menus consisting of icons, you may have noticed that some of those apps show you a text when hovering above those icons. This is a nice touch for the users, allowing them to quickly grasp the meaning of the menu icons without the need to click them or to expand the menu (if available). 15 | 16 | ![Mouse tooltips](tooltips.gif) 17 | 18 | Implementing this kind of hovers is really easy thanks to the `ToolTipService` that is available in Windows 8.1 and Windows 10 UWP. You can add `` with any element and include basically any XAML content as the tooltip. Here is a sample from the animation using a simple localized `TextBlock` 19 | 20 | 21 | 22 | ```xml 23 | 26 | 27 | 29 | 30 | 31 | 32 | ``` 33 | -------------------------------------------------------------------------------- /content/post/2016/using-tooltips-to-make-better-menus-in-windows-apps/tooltips.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2016/using-tooltips-to-make-better-menus-in-windows-apps/tooltips.gif -------------------------------------------------------------------------------- /content/post/2017/changing-navigation-vs-tabbar-title/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | Categories = ["iOS", "Swift"] 3 | Description = "The UI of the iOS app I currently work on contains a tab bar with Profile as the title of one of the included tabs. This Profile tab contains a view controller with a navigation bar where I wanted the title to be set as You profile." 4 | Tags = ["iOS", "Swift"] 5 | Keywords = ["iOS", "Swift", "UINavigationBar"] 6 | author = "Igor Kulman" 7 | date = "2017-09-12T09:29:12+01:00" 8 | title = "iOS tip: Changing navigation bar vs tab bar title" 9 | url = "/changing-navigation-vs-tabbar-title-ios" 10 | 11 | +++ 12 | 13 | The UI of the iOS app I currently work on contains a tab bar with "Profile" as the title of one of the included tabs. This "Profile" tab contains a view controller with a navigation bar where I wanted the title to be set as "You profile". 14 | 15 | So I set the tab bar item's title to "Profile" and wanted to set the navigation bar title of the view controller the standard way 16 | 17 | ```swift 18 | title = "Your profile" 19 | ``` 20 | 21 | I noticed that this also changes the title in the tab bar. After some research I found out that changing the view controller's title property changes bot the title in the navigation bar and in the bar bar. But you can change the title just for the navigation bar 22 | 23 | 24 | 25 | ```swift 26 | navigationItem.title = "Your profile" 27 | ``` 28 | 29 | and just for the tab bar 30 | 31 | ```swift 32 | tabBarItem.title = "Profile" 33 | ``` 34 | -------------------------------------------------------------------------------- /content/post/2017/creating-a-tv-schedule-grid-in-uwp/tvgrid.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2017/creating-a-tv-schedule-grid-in-uwp/tvgrid.gif -------------------------------------------------------------------------------- /content/post/2017/creating-animations-of-your-apps/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | Categories = ["macOS", "Software", "Windows"] 3 | Description = "They say that a picture is worth a thousand words so whenever I create an issue, a pull request or write a blog post about and application or some visual stuff I include a relevant image. Sometimes an image is not enough and an animation is needed to better describe the issue, or show the content of your pull request." 4 | Tags = ["macOS", "Software", "Windows"] 5 | Keywords = ["macOS", "Software", "Windows", "Tools"] 6 | author = "Igor Kulman" 7 | date = "2017-07-25T09:29:12+01:00" 8 | title = "Creating animations of your apps" 9 | url = "/creating-animations-of-your-apps" 10 | images = ["/images/stickyheader.gif"] 11 | 12 | +++ 13 | 14 | They say that a picture is worth a thousand words so whenever I create an issue, a pull request or write a blog post about and application or some visual stuff I include a relevant image. Sometimes an image is not enough and an animation is needed to better describe the issue, or show the content of your pull request. 15 | 16 | There are some good tools to help you to create animations like this on both Windows and macOS. 17 | 18 | 19 | 20 | ## ScreenToGif (Windows) 21 | 22 | [ScreenToGif](http://www.screentogif.com/) is a simple but powerful portable Windows app that helps you record your screen and save it as a Gif. You can record the whole screen or just a custom window. This is ideal for example for recording the behavior of your apps in an emulator, recording just the emulator window. 23 | 24 | ## Gipphy (macOS) 25 | 26 | To create app animations from the iOS simulator on macOS I use [Gipphy](https://itunes.apple.com/us/app/giphy-capture-the-gif-maker/id668208984?mt=12). It is a simple app that works similarly ScreenToGif. There is no need to upload your Gifs to the Gipphy website, you can just save them locally. 27 | 28 | -------------------------------------------------------------------------------- /content/post/2017/creating-navigationbar-dropdown-menu/dropdown.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2017/creating-navigationbar-dropdown-menu/dropdown.gif -------------------------------------------------------------------------------- /content/post/2017/delaying-disqus-comments-to-save-requests/disqus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2017/delaying-disqus-comments-to-save-requests/disqus.png -------------------------------------------------------------------------------- /content/post/2017/fixing-black-artifact-changing-large-tiles-mode/blackartifact.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2017/fixing-black-artifact-changing-large-tiles-mode/blackartifact.gif -------------------------------------------------------------------------------- /content/post/2017/fixing-black-artifact-changing-large-tiles-mode/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | Categories = ["iOS", "Swift"] 3 | Description = "One of the new features of iOS 11 is the ability to display large headers in the navigation bar by setting the `prefersLargeTitles` property to `true`. You can set it for the whole app (using UIAppearance for example) or differently for each view controller. But there is a problem. If you navigate from a view controller with large titles enabled to a view controller with large titles disabled, you will see a black artifact under the change animation" 4 | Tags = ["iOS", "Swift"] 5 | Keywords = ["iOS", "Swift", "UIAppearance", "UI"] 6 | author = "Igor Kulman" 7 | date = "2017-09-21T09:29:12+01:00" 8 | title = "Fixing black artifact when changing large titles mode in iOS11" 9 | url = "/fixing-black-artifact-changing-large-tiles-mode" 10 | images = ["/images/blackartifact.gif"] 11 | 12 | +++ 13 | 14 | One of the new features of iOS 11 is the ability to display large headers in the navigation bar by setting the `prefersLargeTitles` property to `true`. You can set it for the whole app (using the [`UIAppearance`](https://developer.apple.com/documentation/uikit/uiappearance) for example) or differently for each view controller. 15 | 16 | But there is a problem. If you navigate from a view controller with large titles enabled to a view controller with large titles disabled, you will see a black artifact under the change animation: 17 | 18 | ![Black navigation artifact](blackartifact.gif) 19 | 20 | The black artifact comes from the navigation controller. If you set the `backgroundColor` of the navigation controller's `view` to any, like red, it will replace the black artifact with an artifact of that color. The solution is to set the color of the color of you UI, white in my case: 21 | 22 | 23 | 24 | ![Black navigation artifact fixed](noartifact.gif) 25 | 26 | Now the animation looks ok, no visible artifact. The problem is, you cannot set it globally using `UIAppearance`, so you can either set `navigationController.view.backgroundColor = UIColor.white` on every navigation controller in your app, or create a custom navigation controller inheriting from `UINavigationController` and use it everywhere where needed. 27 | -------------------------------------------------------------------------------- /content/post/2017/fixing-black-artifact-changing-large-tiles-mode/noartifact.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2017/fixing-black-artifact-changing-large-tiles-mode/noartifact.gif -------------------------------------------------------------------------------- /content/post/2017/fixing-iphone-usb-tethering-on-macos/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | Categories = ["macOS", "Hardware"] 3 | Description = "When my ISP had a problem resulting in Internet outage for multiple hours and I needed to work, I wanted to tether the LTE connection from my iPhone 6S to my hackintosh running macOS Sierra. It has no Wi-Fi card so the only was was tethering over USB cable. " 4 | Tags = ["Hardware", "macOS"] 5 | Keywords = ["Hardware", "macOS", "Tethering"] 6 | author = "Igor Kulman" 7 | date = "2017-09-19T09:29:12+01:00" 8 | title = "Fixing problems with iPhone USB tethering on macOS" 9 | url = "/fixing-iphone-usb-tethering-on-macos" 10 | images = ["/images/tethering.png"] 11 | 12 | +++ 13 | 14 | When my ISP had a problem resulting in Internet outage for multiple hours and I needed to work, I wanted to tether the LTE connection from my iPhone 6S to my [hackintosh running macOS Sierra](/my-experience-running-a-hackintosh). It has no Wi-Fi card so the only was was tethering over USB cable. 15 | 16 | The whole process should be easy, just connecting the iPhone to the computer with an USB cable and turning on the Personal hotspot in the Settings. The iPhone immediately registered 1 connection, but Internet did not work on the computer, although everything looked fine in System Preferences 17 | 18 | ![iPhone tethering](tethering.png) 19 | 20 | 21 | 22 | After killing mDNSResponder with `killall -HUP mDNSResponder` I was able to `ping` IP addresses like 8.8.8.8 just fine, but DNS did not work. Running `cat /etc/resolv.conf` showed that the DNS server was still set to the IP address of my router. 23 | 24 | The solution was to set the DNS for the tethering connection manually with `networksetup -setdnsservers "iPhone USB" 8.8.8.8` and flush the cache using `dscacheutil -flushcache`. 25 | -------------------------------------------------------------------------------- /content/post/2017/fixing-iphone-usb-tethering-on-macos/tethering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2017/fixing-iphone-usb-tethering-on-macos/tethering.png -------------------------------------------------------------------------------- /content/post/2017/formatting-swift-code-in-xcode/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | Categories = [ "iOS", "Xcode", "Swift"] 3 | Description = "When I started using XCode I was really surprised about the really poor implementation of its code formatting functionality. It kind of formats the alignment of the code but ignores unnecessary spaces and a lot of other things. Formatting the source code and keeping the style consistent is really important to me so I was looking for a solution." 4 | Tags = ["iOS", "XCode", "Swift"] 5 | Keywords =["iOS", "XCode", "Swift", "Formatting", "SwiftFormat"] 6 | author = "Igor Kulman" 7 | date = "2017-05-05T09:29:12+01:00" 8 | title = "Formatting Swift code in XCode" 9 | url = "/formatting-swift-code-in-xcode" 10 | images = ["/images/swiftformat.png"] 11 | 12 | +++ 13 | 14 | When I started using XCode I was really surprised about the really poor implementation of its code formatting functionality. It kind of formats the alignment of the code but ignores unnecessary spaces and a lot of other things. Formatting the source code and keeping the style consistent is really important to me so I was looking for a solution. I found some linters like [SwiftLint](https://github.com/realm/SwiftLint) but I was interested in a tool that will actually format the source code for me on demand. I found [SwiftFormat](https://github.com/nicklockwood/SwiftFormat). 15 | 16 | ### SwiftFormat 17 | 18 | [SwiftFormat](https://github.com/nicklockwood/SwiftFormat) is a code library and command-line tool for reformatting swift code. It applies a set of rules to the formatting and space around the code, leaving the meaning intact. 19 | 20 | ![SwiftFormat Xcode integration](swiftformat.png) 21 | 22 | 23 | 24 | You can install SwiftFormat using `brew install swiftformat` and use it from the terminal to format given directory. This means you can use it manually or add it as a build step in XCode or a git pre-commit hook. Using SwiftFormat from the terminal before from time to time or before every commit is fine, but I wanted to use directly from XCode, preferably invoked by a keyboard shortcut. 25 | 26 | To do this you can use the XCode Source Editor Extension. There is a signed binary already included in the repository you can download, put into Applications and run. It tells you how to enable it in Settings, so you do it and restart XCode. A bit of a hassle but you do it just once and it is worth it. 27 | 28 | In conclusion use SwiftFormat to make formatting of your Swift code consistent, especially if you work in a team. 29 | -------------------------------------------------------------------------------- /content/post/2017/formatting-swift-code-in-xcode/swiftformat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2017/formatting-swift-code-in-xcode/swiftformat.png -------------------------------------------------------------------------------- /content/post/2017/generating-a-list-of-libraries-your-ios-app-uses/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | Categories = [ "iOS"] 3 | Description = "If you work on an iOS app that is a bit more corporate you probably need to show the list of all the libraries you use with their licenses somewhere in the app. Creating and updating this list by hand is a pain. If you use Carthage to manage all your dependencies (and you really should) there is a handy script by Piet Brauer I contributed to that will help you. " 4 | Tags = ["iOS", "Carthage"] 5 | Keywords =["iOS", "Carthage", "OpenSource", "GitHub"] 6 | author = "Igor Kulman" 7 | date = "2017-04-05T09:29:12+01:00" 8 | title = "Generating a list of libraries your iOS app uses" 9 | url = "/generating-a-list-of-libraries-your-ios-app-uses" 10 | images = ["/images/licenses.gif"] 11 | 12 | +++ 13 | 14 | If you work on an iOS app that is a bit more corporate you probably need to show the list of all the libraries you use with their licenses somewhere in the app. Creating and updating this list by hand is a pain. If you use Carthage to manage all your dependencies ([and you really should](http://drekka.ghost.io/cocoapods-vs-carthage/)) there is a handy [script by Piet Brauer](https://github.com/pietbrauer/CarthageLicenseScript) I contributed to that will help you. 15 | 16 | When you run the script using `$ ./PATH_TO_YOUR_SCRIPT/fetch_licenses.swift Cartfile.resolved OUTPUT_DIR` it reads your Carthage file, gets all the libraries you use, downloads their licenses and stores them all in a single `plist` file. The `plist` file contains the name, license name and full license content for every library in your Carthage file. 17 | 18 | There is currently no support for using multiple Carthage files (when you have more projects in your workspace), you need to generate the `plist` file for each of them separately and then merge them manually. But you can set up a `bash` script to do it for you. 19 | 20 | 21 | 22 | You can then read the `plist` file in your app and show it as a list of libraries like I do 23 | 24 | ![List of used licenses](licenses.gif) 25 | -------------------------------------------------------------------------------- /content/post/2017/generating-a-list-of-libraries-your-ios-app-uses/licenses.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2017/generating-a-list-of-libraries-your-ios-app-uses/licenses.gif -------------------------------------------------------------------------------- /content/post/2017/making-tableview-header-stickier/stickyheader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2017/making-tableview-header-stickier/stickyheader.gif -------------------------------------------------------------------------------- /content/post/2017/more-readable-xcodebuild-output/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | Categories = ["iOS", "macOS", "Xcode"] 3 | Description = "If you use Continuous Integration (CI) builds or build your app from the command line using `xcodebuild` you know that the output is not pretty and not very readable. Reading the build output is important when a CI build breaks" 4 | Tags = ["iOS", "macOS", "Xcode"] 5 | Keywords = ["iOS", "macOS", "Xcode", "CI", "Xcpretty"] 6 | author = "Igor Kulman" 7 | date = "2017-10-11T09:29:12+01:00" 8 | title = "More readable XCode build output for CI" 9 | url = "/more-readable-xcodebuild-output" 10 | images = ["/images/xcprettytests.png"] 11 | 12 | +++ 13 | 14 | If you use Continuous Integration (CI) builds or build your app from the command line using `xcodebuild` you know that the output is not pretty and not very readable. Reading the build output is important when a CI build breaks, but it is not easy when it looks like this 15 | 16 | ![xcodebuild output](xcodebuild.png) 17 | 18 | Many iOS developers were not satisfied with this so the [`xcpretty`](https://github.com/supermarin/xcpretty) project was created. `Xcpretty` is a fast and flexible formatter that turn the output from screnshot above to this neatly formatted output 19 | 20 | ![xcodebuild output with xcpretty](xcpretty.png) 21 | 22 | 23 | 24 | The unit tests output looks especially nice 25 | 26 | ![xcodebuild tests output with xcpretty](xcprettytests.png) 27 | 28 | Using `xcpretty` is easy, you install it as a gem (`gem install xcpretty`) and then pipe the results of your `xcodebuild` commands to it like this `xcodebuild test -project iOSSampleApp.xcodeproj -scheme iOSSampleApp -destination 'platform=iOS Simulator,name=iPhone 6s,OS=11.0' | xcpretty` 29 | 30 | You can use it with any CI that allows installing custom utilities. I use [Travis CI](https://travis-ci.org/igorkulman/iOSSampleApp), you can take a look at my [.travis.yml config](https://github.com/igorkulman/iOSSampleApp/blob/master/.travis.yml). 31 | -------------------------------------------------------------------------------- /content/post/2017/more-readable-xcodebuild-output/xcodebuild.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2017/more-readable-xcodebuild-output/xcodebuild.png -------------------------------------------------------------------------------- /content/post/2017/more-readable-xcodebuild-output/xcpretty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2017/more-readable-xcodebuild-output/xcpretty.png -------------------------------------------------------------------------------- /content/post/2017/more-readable-xcodebuild-output/xcprettytests.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2017/more-readable-xcodebuild-output/xcprettytests.png -------------------------------------------------------------------------------- /content/post/2017/my-experience-running-a-hackintosh/hackintosh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2017/my-experience-running-a-hackintosh/hackintosh.png -------------------------------------------------------------------------------- /content/post/2017/my-experience-with-swift-after-9-months/swift.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2017/my-experience-with-swift-after-9-months/swift.png -------------------------------------------------------------------------------- /content/post/2017/resigning-ios-apps/easyresigny.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2017/resigning-ios-apps/easyresigny.png -------------------------------------------------------------------------------- /content/post/2017/using-data-binding-in-ios/iosvalidation.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2017/using-data-binding-in-ios/iosvalidation.gif -------------------------------------------------------------------------------- /content/post/2017/using-macos-with-a-windows-keyboard/macoskeymapping.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2017/using-macos-with-a-windows-keyboard/macoskeymapping.png -------------------------------------------------------------------------------- /content/post/2017/using-macos-with-a-windows-keyboard/volumeshortcuts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2017/using-macos-with-a-windows-keyboard/volumeshortcuts.png -------------------------------------------------------------------------------- /content/post/2017/using-mvvm-with-tables-in-ios/iostablemvvm.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2017/using-mvvm-with-tables-in-ios/iostablemvvm.gif -------------------------------------------------------------------------------- /content/post/2017/using-vscode-as-git-merge-tool/merge-conflict.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2017/using-vscode-as-git-merge-tool/merge-conflict.png -------------------------------------------------------------------------------- /content/post/2017/using-vscode-as-git-merge-tool/tower-merge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2017/using-vscode-as-git-merge-tool/tower-merge.png -------------------------------------------------------------------------------- /content/post/2017/xcode-wireless-debugging/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | Categories = ["iOS", "macOS", "Xcode"] 3 | Description = "One of the best XCode 9 features is the ability to deploy and debug iOS app on your device over WiFi, with no need to have the device connected to you computer by a cable. The only requirement is that the device runs iOS 11." 4 | Tags = ["iOS", "macOS", "XCode"] 5 | Keywords = ["iOS", "macOS", "Xcode", "Debug"] 6 | author = "Igor Kulman" 7 | date = "2017-10-07T09:29:12+01:00" 8 | title = "iOS tip: Wireless debugging from XCode" 9 | url = "/xcode-wireless-debugging" 10 | images = ["/images/wifideploy.png"] 11 | 12 | +++ 13 | 14 | One of the best XCode 9 features is the ability to deploy and debug iOS app on your device over WiFi, with no need to have the device connected to you computer by a cable. The only requirement is that the device runs iOS 11. 15 | 16 | Setting it up is really easy. Connect the device using a cable like you normally do and go to `Window | Devices and Simulators`. You will see a new checkbox next to your iOS 11 devices called `Connect via Network` (see screenshot below), so check it. Now you can disconnect the cable and debug on your device over WiFi, the device has to be on the same network as your computer of course. 17 | 18 | ![Deployinh over Wifi](wifideploy.png) 19 | 20 | 21 | 22 | If it does not work on the first try, reboot your device, it will help. To check if XCode sees your device on the network, look for the icon of a globe next to your device's name in the left pane of the window (as shown on the screenshot). 23 | -------------------------------------------------------------------------------- /content/post/2017/xcode-wireless-debugging/wifideploy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2017/xcode-wireless-debugging/wifideploy.png -------------------------------------------------------------------------------- /content/post/2018/add-mobile-iron-to-swift-app/mobileiron.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2018/add-mobile-iron-to-swift-app/mobileiron.png -------------------------------------------------------------------------------- /content/post/2018/animating-tab-bar-buttons/tw-animation.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2018/animating-tab-bar-buttons/tw-animation.gif -------------------------------------------------------------------------------- /content/post/2018/animating-tab-bar-buttons/twitter-animation.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2018/animating-tab-bar-buttons/twitter-animation.gif -------------------------------------------------------------------------------- /content/post/2018/architecting-ios-apps-coordinators/coordinators.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2018/architecting-ios-apps-coordinators/coordinators.png -------------------------------------------------------------------------------- /content/post/2018/automating-ios-development-and-distribution-workflow/automate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2018/automating-ios-development-and-distribution-workflow/automate.png -------------------------------------------------------------------------------- /content/post/2018/automating-ios-development-and-distribution-workflow/fastlane_badge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2018/automating-ios-development-and-distribution-workflow/fastlane_badge.png -------------------------------------------------------------------------------- /content/post/2018/building-ios-depedencies-with-carthage/carthage-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2018/building-ios-depedencies-with-carthage/carthage-logo.png -------------------------------------------------------------------------------- /content/post/2018/checking-for-missing-translations-in-ios/verify-string-files-error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2018/checking-for-missing-translations-in-ios/verify-string-files-error.png -------------------------------------------------------------------------------- /content/post/2018/creating-your-own-xcode-templates/XcodeTemplates.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2018/creating-your-own-xcode-templates/XcodeTemplates.png -------------------------------------------------------------------------------- /content/post/2018/using-clonezilla-for-hackintosh-backups/clonezilla.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2018/using-clonezilla-for-hackintosh-backups/clonezilla.jpg -------------------------------------------------------------------------------- /content/post/2018/using-ios-strings-in-a-safer-way/iosstrings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2018/using-ios-strings-in-a-safer-way/iosstrings.png -------------------------------------------------------------------------------- /content/post/2018/workaround-for-faded-navbar-button/ios112bug.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2018/workaround-for-faded-navbar-button/ios112bug.gif -------------------------------------------------------------------------------- /content/post/2018/writing-a-pascal-interpreter-in-swift/factorial.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2018/writing-a-pascal-interpreter-in-swift/factorial.gif -------------------------------------------------------------------------------- /content/post/2018/writing-a-pascal-interpreter-in-swift/lexer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2018/writing-a-pascal-interpreter-in-swift/lexer.png -------------------------------------------------------------------------------- /content/post/2018/writing-a-pascal-interpreter-in-swift/parser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2018/writing-a-pascal-interpreter-in-swift/parser.png -------------------------------------------------------------------------------- /content/post/2018/writing-a-pascal-interpreter-in-swift/playground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2018/writing-a-pascal-interpreter-in-swift/playground.png -------------------------------------------------------------------------------- /content/post/2019/adding-wifi-and-bluetooth-for-apple-features-to-hackintosh/card.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2019/adding-wifi-and-bluetooth-for-apple-features-to-hackintosh/card.jpg -------------------------------------------------------------------------------- /content/post/2019/changing-uialertaction-text-color/color.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2019/changing-uialertaction-text-color/color.png -------------------------------------------------------------------------------- /content/post/2019/changing-uialertaction-text-color/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2019/changing-uialertaction-text-color/default.png -------------------------------------------------------------------------------- /content/post/2019/changing-uialertaction-text-color/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | Categories = ["iOS", "Xcode"] 3 | Description = "If you use the standard iOS UIAlertController to present the user with a list of actions, there is not much you can do about styling each of the UIAlertActions shown. The text of the shown UIAlertAction uses the UIView's tint color, so you can use the UIAppearence API to change it to any color you want, but the same color for all the `UIAlertAction`s. If you set the style to destructive instead of default, the text is shown as red, not affected by the tint color." 4 | Tags = ["iOS", "Xcode"] 5 | Keywords = ["iOS", "Xcode"] 6 | author = "Igor Kulman" 7 | date = "2019-06-26T05:29:12+01:00" 8 | title = "Changing UIAlertAction text color" 9 | url = "/changing-uialertaction-text-color" 10 | images = ["/changing-uialertaction-text-color/color.png"] 11 | 12 | +++ 13 | 14 | If you use the standard iOS `UIAlertController` to present the user with a list of actions, there is not much you can do about styling each of the `UIAlertAction`s shown. 15 | 16 | The text of the shown `UIAlertAction` uses the `UIView`'s tint color, so you can use the `UIAppearence` API to change it to any color you want, but the same color for all the `UIAlertAction`s. If you set the style to `destructive` instead of `default`, the text is shown as red, not affected by the tint color. 17 | 18 | `UIAlertController` with one `default` and one `destructive` action might then look like this with dark blue set as the global tint color using `UIAppearence`: 19 | 20 | ![Default UIAlertController appearance](default.png) 21 | 22 | The red color for the destructive option does not look that great, especially if your app uses a different shade of red everywhere else. 23 | 24 | If you dive deep into Apple documentation you will find a KVC called `titleTextColor`. This KVC allows you to set exactly what you need, the color for the `UIAlertAction` text. 25 | 26 | 27 | 28 | You can then use a simple extension 29 | 30 | ```swift 31 | extension UIAlertAction { 32 | var titleTextColor: UIColor? { 33 | get { 34 | return self.value(forKey: "titleTextColor") as? UIColor 35 | } set { 36 | self.setValue(newValue, forKey: "titleTextColor") 37 | } 38 | } 39 | } 40 | ``` 41 | 42 | to use the correct shade of red for your destructive actions 43 | 44 | ![Customized UIAlertController appearance](color.png) 45 | 46 | or to make any of the `UIAlertAction`s to be shown in any color you want or need. 47 | -------------------------------------------------------------------------------- /content/post/2019/creating-bootable-macos-backups/BootedBackup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2019/creating-bootable-macos-backups/BootedBackup.png -------------------------------------------------------------------------------- /content/post/2019/creating-bootable-macos-backups/Clone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2019/creating-bootable-macos-backups/Clone.png -------------------------------------------------------------------------------- /content/post/2019/creating-bootable-macos-backups/Formatting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2019/creating-bootable-macos-backups/Formatting.png -------------------------------------------------------------------------------- /content/post/2019/creating-bootable-macos-backups/Schedule.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2019/creating-bootable-macos-backups/Schedule.png -------------------------------------------------------------------------------- /content/post/2019/creating-bootable-macos-backups/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2019/creating-bootable-macos-backups/logo.png -------------------------------------------------------------------------------- /content/post/2019/creating-context-menu-with-highlight/DimEffect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2019/creating-context-menu-with-highlight/DimEffect.png -------------------------------------------------------------------------------- /content/post/2019/creating-context-menu-with-highlight/HighlightEffect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2019/creating-context-menu-with-highlight/HighlightEffect.png -------------------------------------------------------------------------------- /content/post/2019/creating-context-menu-with-highlight/Menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2019/creating-context-menu-with-highlight/Menu.png -------------------------------------------------------------------------------- /content/post/2019/creating-context-menu-with-highlight/TransparentWindow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2019/creating-context-menu-with-highlight/TransparentWindow.png -------------------------------------------------------------------------------- /content/post/2019/creating-context-menu-with-highlight/animation.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2019/creating-context-menu-with-highlight/animation.gif -------------------------------------------------------------------------------- /content/post/2019/debugging-ios-network-traffic/cert.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2019/debugging-ios-network-traffic/cert.png -------------------------------------------------------------------------------- /content/post/2019/debugging-ios-network-traffic/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2019/debugging-ios-network-traffic/logo.png -------------------------------------------------------------------------------- /content/post/2019/debugging-ios-network-traffic/mitmweb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2019/debugging-ios-network-traffic/mitmweb.png -------------------------------------------------------------------------------- /content/post/2019/debugging-ios-network-traffic/proxy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2019/debugging-ios-network-traffic/proxy.png -------------------------------------------------------------------------------- /content/post/2019/debugging-ios-network-traffic/trust.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2019/debugging-ios-network-traffic/trust.png -------------------------------------------------------------------------------- /content/post/2019/detecting-click-on-a-nstableviewcell/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | Categories = ["macOS", "Swift"] 3 | Description = "When you use NSTableView in an macOS application, there is no direct way to know a specific NSTableViewCell was clicked by the user. In my Localization Editor project I wanted the user to be able to focus a NSTextField when clicking anywhere in the NSTableViewCell it is contained in, so I had to implement it myself." 4 | Tags = ["macOS", "Swift"] 5 | Keywords = ["macOS", "Swift"] 6 | author = "Igor Kulman" 7 | date = "2019-04-24T05:29:12+01:00" 8 | title = "Detecting click on a specific NSTableViewCell" 9 | url = "/detecting-click-on-a-nstableviewcell" 10 | 11 | +++ 12 | 13 | When you use `NSTableView` in an macOS application, there is no direct way to know a specific `NSTableViewCell` was clicked by the user. In my [Localization Editor](https://github.com/igorkulman/iOSLocalizationEditor) project I wanted the user to be able to focus a `NSTextField` when clicking anywhere in the `NSTableViewCell` it is contained in, so I had to implement it myself. 14 | 15 | I created a new delegate extending the `NSTableViewDelegate` with one additional method informing about a `NSTableViewCell` getting clicked 16 | 17 | ```swift 18 | protocol NSTableViewClickableDelegate: NSTableViewDelegate { 19 | func tableView(_ tableView: NSTableView, didClickRow row: Int, didClickColumn: Int) 20 | } 21 | ``` 22 | 23 | Then I added an extension to the `NSTableView` to compute the index of the clicked `NSTableViewCell` 24 | 25 | ```swift 26 | extension NSTableView { 27 | open override func mouseDown(with event: NSEvent) { 28 | let localLocation = self.convert(event.locationInWindow, to: nil) 29 | let clickedRow = self.row(at: localLocation) 30 | let clickedColumn = self.column(at: localLocation) 31 | 32 | super.mouseDown(with: event) 33 | 34 | guard clickedRow >= 0, clickedColumn >= 0, let delegate = self.delegate as? NSTableViewClickableDelegate else { 35 | return 36 | } 37 | 38 | delegate.tableView(self, didClickRow: clickedRow, didClickColumn: clickedColumn) 39 | } 40 | } 41 | ``` 42 | 43 | To be able to use this extension you just need to implement `NSTableViewClickableDelegate` instead of `NSTableViewDelegate` and use the additional method it provides. 44 | 45 | -------------------------------------------------------------------------------- /content/post/2019/editing-macos-app-about-dialog/default-dialog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2019/editing-macos-app-about-dialog/default-dialog.png -------------------------------------------------------------------------------- /content/post/2019/editing-macos-app-about-dialog/dialog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2019/editing-macos-app-about-dialog/dialog.png -------------------------------------------------------------------------------- /content/post/2019/editing-macos-app-about-dialog/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | Categories = ["macOS", "Xcode"] 3 | Description = "When you create a macOS app and keep the default menu, you automatically get an About dialog. This dialog shows basic info about the app. If you want to add more information to this dialog there is no obvious way to do it. You need to start reading the Apple documentation to finally discover that it is actually quite simple." 4 | Tags = ["macOS", "Xcode"] 5 | Keywords = ["macOS", "Xcode"] 6 | author = "Igor Kulman" 7 | date = "2019-05-29T05:29:12+01:00" 8 | title = "Editing macOS app About dialog" 9 | url = "/editing-macos-app-about-dialog" 10 | images = ["/editing-macos-app-about-dialog/dialog.png"] 11 | 12 | +++ 13 | 14 | When you create a macOS app and keep the default menu, you automatically get an About dialog. This dialog shows basic info about the app. 15 | 16 | ![Default About dialog](default-dialog.png) 17 | 18 | If you want to add more information to this dialog there is no obvious way to do it. You need to start reading the Apple documentation to finally discover that it is actually quite simple. 19 | 20 | 21 | 22 | All you have to do is to add a `Credits.rtf` to you project. You can do it directly from Xcode using `File | New | File | Rich Text File`. 23 | 24 | The content of this file will be automatically shown in the About dialog 25 | 26 | ![Customized About dialog](dialog.png) -------------------------------------------------------------------------------- /content/post/2019/faster-way-to-download-and-install-xcode/more.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2019/faster-way-to-download-and-install-xcode/more.png -------------------------------------------------------------------------------- /content/post/2019/faster-way-to-download-and-install-xcode/xcode-icon-17.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2019/faster-way-to-download-and-install-xcode/xcode-icon-17.jpg -------------------------------------------------------------------------------- /content/post/2019/switching-my-hackintosh-from-nvidia-to-amd/logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2019/switching-my-hackintosh-from-nvidia-to-amd/logo.jpg -------------------------------------------------------------------------------- /content/post/2019/switching-my-hackintosh-from-nvidia-to-amd/mojave.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2019/switching-my-hackintosh-from-nvidia-to-amd/mojave.png -------------------------------------------------------------------------------- /content/post/2019/using-pods-to-just-build-frameworks/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2019/using-pods-to-just-build-frameworks/logo.png -------------------------------------------------------------------------------- /content/post/2019/why-ios-gestures-lag-at-the-screen-edges/quick-recording-bottom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2019/why-ios-gestures-lag-at-the-screen-edges/quick-recording-bottom.png -------------------------------------------------------------------------------- /content/post/2019/why-ios-gestures-lag-at-the-screen-edges/quick-recording-middle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2019/why-ios-gestures-lag-at-the-screen-edges/quick-recording-middle.png -------------------------------------------------------------------------------- /content/post/2020/animating-annotation-position-change-on-ios/MapJump.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2020/animating-annotation-position-change-on-ios/MapJump.gif -------------------------------------------------------------------------------- /content/post/2020/animating-annotation-position-change-on-ios/MapSmooth.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2020/animating-annotation-position-change-on-ios/MapSmooth.gif -------------------------------------------------------------------------------- /content/post/2020/animating-annotation-position-change-on-ios/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | Categories = ["iOS", "Xcode", "MapKit"] 3 | Description = "" 4 | Tags = ["iOS", "Xcode", "MapKit"] 5 | Keywords = ["iOS", "Xcode", "MapKit"] 6 | author = "Igor Kulman" 7 | date = "2020-05-13T05:29:12+01:00" 8 | title = "Animating annotations position change in MKMapView" 9 | url = "/animating-annotation-position-change-on-ios" 10 | images = ["/animating-annotation-position-change-on-ios/MapSmooth.gif"] 11 | series = "Using MKMapView and MapKit on iOS" 12 | 13 | +++ 14 | 15 | Annotations are mainly used to displays static "pins" in `MKMapView` but sometimes you might need to make them move and animate their position changes so it looks better to the users. 16 | 17 | There are a few things you need to do to achieve this. 18 | 19 | ### Coordinate property specifics 20 | 21 | The `MKAnnotation` protocol has a `coordinate` property that is used by the `MKMapView` to position the annotation to its corresponding location on the map. 22 | 23 | If you just update the property you will quickly see that nothing happens, the annotation does not move on the map. 24 | 25 | `MKMapView` uses `KVO` to know when the `coordinate` property changes so in Swift you need to mark the `coordinate` property in your `MKAnnotation` as `@objc dynamic` to make it work 26 | 27 | ```swift 28 | final class LocationViewModel: NSObject, MKAnnotation { 29 | @objc dynamic coordinate: CLLocationCoordinate2D 30 | 31 | ... 32 | } 33 | ``` 34 | 35 | With this change you will notice that the annotation now moves on the map, but it is not smooth, it basically jumps from the old position to the new one. 36 | 37 | ![Annotation jumping on coordinate change](MapJump.gif) 38 | 39 | 40 | 41 | ### Animating the coordinate update 42 | 43 | To make the position change smooth you need just use `UIVIew.animate` when updating the `coordinate` property 44 | 45 | ```swift 46 | UIView.animate(0.3) { 47 | coordinate = updatedPosition 48 | } 49 | ``` 50 | 51 | With this change you can see annotation moving smoothly to the new position 52 | 53 | ![Smooth annotation movement](MapSmooth.gif) 54 | 55 | ### Pulse effect 56 | 57 | If you want to make it clear to the user that the annotation changed its position because its data was updated, you can show a pulse animation like in the animated GIFs in this post. 58 | 59 | It is quite easy just use the [Pulsator](https://github.com/shu223/Pulsator/) library. -------------------------------------------------------------------------------- /content/post/2020/clustering-annotations-in-mkpampview/MapCluster.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2020/clustering-annotations-in-mkpampview/MapCluster.png -------------------------------------------------------------------------------- /content/post/2020/converting-slow-motion-video-to-url-asset/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | Categories = ["iOS", "Xcode"] 3 | Description = "" 4 | Tags = ["iOS", "Xcode"] 5 | Keywords = ["iOS", "Xcode"] 6 | author = "Igor Kulman" 7 | date = "2020-07-22T05:29:12+01:00" 8 | title = "Converting slow motion video to an URL asset for upload" 9 | url = "/converting-slow-motion-video-to-url-asset" 10 | 11 | +++ 12 | 13 | In the iOS application I currently work on the users can choose a video from the device's gallery and that video gets uploaded to the backend. 14 | 15 | This functionality has always worked fine but recently somebody tried to upload s slow motion video and the application was not able to handle it. 16 | 17 | Turns out slow motion videos need a special case, they work a bit differently than normal videos. 18 | 19 | When you pick a video from the device's gallery you get a `PHAsset` of type `.video`. You can use `PHImageManager` to load it as `AVAsset`. 20 | 21 | The application just tried to cast it to `AVURLAsset` and processed it as a video file stored at some url that can be converted to `Data` and uploaded to the backend. 22 | 23 | A slow motion video is an `AVAsset`, just not an `AVURLAsset` but an `AVComposition` and it needs to be treated differently. 24 | 25 | The best way to make it work for my upload to backend scenario was to export it to a standard video file 26 | 27 | ```swift 28 | guard let exportSession = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetMediumQuality) else { 29 | Log.error?.message("Could not create AVAssetExportSession") 30 | return 31 | } 32 | 33 | let targetURL = dataPathProvider.uploadsDirectory.appendingPathComponent("\(UUID().uuidString).mp4") 34 | 35 | exportSession.outputURL = targetURL 36 | exportSession.outputFileType = AVFileType.mp4 37 | exportSession.shouldOptimizeForNetworkUse = true 38 | 39 | exportSession.exportAsynchronously { 40 | let exportedAsset = AVURLAsset(url: targetURL) 41 | self.processVideoAsset(asset: exportedAsset) 42 | } 43 | ``` 44 | 45 | After the slow motion video gets exported it can be converted to an `AVURLAsset` and treated the same way as a normal video file. 46 | 47 | 48 | 49 | Just make sure you set the correct extension for the exported file as without it you will not be able to preview in `AVPlayer` or get the duration or thumbnail for it. -------------------------------------------------------------------------------- /content/post/2020/different-git-config-for-work-projects/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | Categories = ["macOS", "Git"] 3 | Description = "" 4 | Tags = ["macOS", "Xcode"] 5 | Keywords = ["macOS", "Git"] 6 | author = "Igor Kulman" 7 | date = "2020-12-02T05:29:12+01:00" 8 | title = "Using different Git config for personal and work projects" 9 | url = "/different-git-config-for-work-projects" 10 | 11 | +++ 12 | 13 | I use the same machines to work on both personal and work projects. I usually have to use a different `Git` identity for the work projects than for my personal projects. 14 | 15 | Previously I had my personal `Git` identity set globally and then used local `Git` configs to override it in work projects. This worked just fine but it was too much work. There is a better solution. 16 | 17 | `Git` config allows you to use, or better to say include, another `Git` config for a specific directory and all its subdirectories. I have all my projects stored in `~/Projects` and subdirectories like `~/Projects/open-source` and work projects in `~/Projects/CompanyName`. 18 | 19 | I created a `~/.companyName.gitconfig` that overrides just the name, email and GPG signing key to match the work identity 20 | 21 | ```bash 22 | [user] 23 | name = Igor Kulman 24 | email = igor@company.name 25 | signingkey = ABC 26 | ``` 27 | 28 | I then included this config in my main `~/.gitconfig` just for the `~/Projects/CompanyName` directory 29 | 30 | ```bash 31 | [user] 32 | name = Igor Kulman 33 | email = igor@kulman.sk 34 | signingkey = DEF 35 | ... 36 | [includeIf "gitdir:~/Projects/CompanyName/"] 37 | path = ~/.companyName.gitconfig 38 | ``` 39 | 40 | to achieve exactly what I needed. 41 | 42 | To verify and quickly check which `Git` identity is being used in a specific `Git` repository you can use this simple `Git` alias 43 | 44 | ```bash 45 | [alias] 46 | whoami = "! git var -l | grep '^GIT_.*_IDENT'" 47 | ``` 48 | 49 | -------------------------------------------------------------------------------- /content/post/2020/generating-boilerplate-swift-code/BuildPhase.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2020/generating-boilerplate-swift-code/BuildPhase.png -------------------------------------------------------------------------------- /content/post/2020/using-custom-annotation-views-in-mkmapview/LiveLocationMap.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2020/using-custom-annotation-views-in-mkmapview/LiveLocationMap.jpg -------------------------------------------------------------------------------- /content/post/2020/using-intel-wifi-bt-on-macos/BT.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2020/using-intel-wifi-bt-on-macos/BT.png -------------------------------------------------------------------------------- /content/post/2020/using-intel-wifi-bt-on-macos/HeliPort.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2020/using-intel-wifi-bt-on-macos/HeliPort.png -------------------------------------------------------------------------------- /content/post/2020/using-intel-wifi-bt-on-macos/itlwm_manual.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2020/using-intel-wifi-bt-on-macos/itlwm_manual.png -------------------------------------------------------------------------------- /content/post/2020/workaround-for-swift-scripts-crash/Swift_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2020/workaround-for-swift-scripts-crash/Swift_logo.png -------------------------------------------------------------------------------- /content/post/2020/xcode-build-times/buildtimes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2020/xcode-build-times/buildtimes.png -------------------------------------------------------------------------------- /content/post/2020/xcode-build-times/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | Categories = ["iOS", "Xcode"] 3 | Description = "" 4 | Tags = ["iOS", "Xcode"] 5 | Keywords = ["iOS", "Xcode"] 6 | author = "Igor Kulman" 7 | date = "2020-08-19T05:29:12+01:00" 8 | title = "How much time a day do you waste waiting for Xcode builds?" 9 | url = "/xcode-build-times" 10 | images = ["/xcode-build-times/buildtimes.png"] 11 | 12 | +++ 13 | 14 | Have you ever wondered how much time a day you spend waiting for Xcode to do your builds? 15 | 16 | Working on a project that is almost entirely written in Swift I wonder that every day with a feeling that it is a non-trivial amount of time just wasted. 17 | 18 | With [Xcode build times](https://github.com/matopeto/xcode-build-times) you can actually measure it and know for sure. 19 | 20 | ### Xcode build times 21 | 22 | Xcode build times is a script that tracks all your daily builds and their duration. 23 | 24 | You just set it up in Xcode to be called on build start, success and fail as stated in the project README. 25 | 26 | It script is intended to be used as a plugin for [BitBar](https://github.com/matryer/bitbar). BitBar is a open source tool that allows you to show any script output in the macOS menu bar. 27 | 28 | Just install BitBar and set the plugins directory to the directory with the Xcode build times script, as stated in the project README. 29 | 30 | ![Xcode build times](buildtimes.png) 31 | 32 | -------------------------------------------------------------------------------- /content/post/2021/automatically-merge-xcode-project-conflicts/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | Categories = ["Git", "Xcode", "iOS"] 3 | Description = "" 4 | Tags = ["Git", "Xcode", "iOS"] 5 | Keywords = ["Git", "Xcode", "iOS"] 6 | author = "Igor Kulman" 7 | date = "2021-12-21T05:29:12+01:00" 8 | title = "Automatically merging conflicts in Xcode project files" 9 | url = "/automatically-merge-xcode-project-conflicts" 10 | images = ["/automatically-merge-xcode-project-conflicts/kintsugi.png"] 11 | 12 | +++ 13 | 14 | Dealing with code conflicts is somethings every developer is probably used to, but it is never a good experience, especially when dealing with file formats that are not exactly human readable, like Xcode project files. 15 | 16 | The Xcode projects files (`project.pbxproj`) are a proper mess with every file appearing multiple times, being referenced by an id, etc .. definitely not something you would want to deal with manually. Luckily there is a better way. 17 | 18 | ### Kintsugi 19 | 20 | [Kintsugi](https://github.com/Lightricks/Kintsugi) is lightweight tool to automatically resolve Git conflicts that occur in Xcode project files. You install the Kintsugi gem with 21 | 22 | 23 | ```bash 24 | gem install kintsugi 25 | ``` 26 | 27 | and then simply calling it a path to a project as a parameter. 28 | 29 | For example if you have a merge conflicts in `App/project.pbxproj` you execute 30 | 31 | ```bash 32 | kintsugi App/project.pbxproj 33 | ``` 34 | 35 | and Kintsugi will take care of the conflicts for you. 36 | 37 | I have been using Kintsugi for a few weeks now and I have to say it works really well. There was only one time so far it failed to automatically merge a conflicts I had in an Xcode project file. 38 | 39 | -------------------------------------------------------------------------------- /content/post/2021/automatically-merge-xcode-project-conflicts/kintsugi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2021/automatically-merge-xcode-project-conflicts/kintsugi.png -------------------------------------------------------------------------------- /content/post/2021/dealing-with-microsoft-in-wp-times/e15.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2021/dealing-with-microsoft-in-wp-times/e15.jpg -------------------------------------------------------------------------------- /content/post/2021/dealing-with-microsoft-in-wp-times/hn.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2021/dealing-with-microsoft-in-wp-times/hn.jpg -------------------------------------------------------------------------------- /content/post/2021/dealing-with-microsoft-in-wp-times/lumia.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2021/dealing-with-microsoft-in-wp-times/lumia.jpg -------------------------------------------------------------------------------- /content/post/2021/dealing-with-microsoft-in-wp-times/tvtime.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2021/dealing-with-microsoft-in-wp-times/tvtime.jpg -------------------------------------------------------------------------------- /content/post/2021/dealing-with-microsoft-in-wp-times/win8konference.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2021/dealing-with-microsoft-in-wp-times/win8konference.png -------------------------------------------------------------------------------- /content/post/2021/dealing-with-microsoft-in-wp-times/windows8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2021/dealing-with-microsoft-in-wp-times/windows8.png -------------------------------------------------------------------------------- /content/post/2021/graying-out-images/flags-original.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2021/graying-out-images/flags-original.png -------------------------------------------------------------------------------- /content/post/2021/graying-out-images/flags.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2021/graying-out-images/flags.png -------------------------------------------------------------------------------- /content/post/2021/graying-out-images/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | Categories = ["Swift", "Xcode", "Cocoa"] 3 | Description = "" 4 | Tags = ["Swift", "Xcode", "Cocoa"] 5 | Keywords = ["Swift", "Xcode", "Cocoa"] 6 | author = "Igor Kulman" 7 | date = "2021-02-17T05:29:12+01:00" 8 | title = "Graying out images in Cocoa" 9 | url = "/graying-out-images" 10 | images = ["/graying-out-images/flags.png"] 11 | 12 | +++ 13 | 14 | I have been working on a macOS application recently where I encountered an interesting task to grey out flags for countries that are disabled. 15 | 16 | ![Colorful flags](flags-original.png) 17 | 18 | I first tried overlaying a semi-transparent gray view (fun fact, you cannot directly set a background for a view in Cocoa, you need to use the layer) over the flag image but it did not look very good. 19 | 20 | Luckily there is a way to convert a `NSImage` to grayscale directly in Cocoa. 21 | 22 | You first need to create a bitmap representation your `NSImage` 23 | 24 | ```swift 25 | let bitmap = NSBitmapImageRep(cgImage: cgImage) 26 | ``` 27 | 28 | convert it to grayscale 29 | 30 | ```swift 31 | let grayscale = bitmap.converting(to: .genericGray, renderingIntent: .default) 32 | ``` 33 | 34 | and then construct an `NSImage` from the result. 35 | 36 | ```swift 37 | let grayImage = NSImage(size: grayscale.size) 38 | greyImage.addRepresentation(grayscale) 39 | ``` 40 | 41 | Putting it all together as an NSImage extension might look like this 42 | 43 | 44 | 45 | ```swift 46 | extension NSImage { 47 | func grayOut() -> NSImage? { 48 | guard let image = cgImage else { 49 | return nil 50 | } 51 | 52 | let bitmap = NSBitmapImageRep(cgImage: image) 53 | 54 | guard let grayscale = bitmap.converting(to: .genericGray, renderingIntent: .default) else { 55 | return nil 56 | } 57 | 58 | let grayImage = NSImage(size: grayscale.size) 59 | grayImage.addRepresentation(grayscale) 60 | return grayImage 61 | } 62 | } 63 | ``` 64 | 65 | Applying this method to the flags from the beginning of this post will get you this result 66 | 67 | ![Grayed out flags](flags.png) -------------------------------------------------------------------------------- /content/post/2021/reading-environment-variables-from-unit-tests/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | Categories = ["Swift", "Xcode"] 3 | Description = "" 4 | Tags = ["Swift", "Xcode"] 5 | Keywords = ["Swift", "Xcode"] 6 | author = "Igor Kulman" 7 | date = "2021-03-17T05:29:12+01:00" 8 | title = "Reading environment variables from iOS and macOS unit tests" 9 | url = "/reading-environment-variables-from-unit-tests" 10 | images = ["/reading-environment-variables-from-unit-tests/scheme.png"] 11 | 12 | +++ 13 | 14 | In some environments like the CI/CD you might need to read environments variables from your iOS or macOS unit tests. 15 | 16 | A typical example might be reading secrets or configuration that is CI/CD specific and you do not want to store it in source control. 17 | 18 | In Swift you can read environment variables using the `ProcessInfo.processInfo.environment` dictionary, for example 19 | 20 | ```swift 21 | let host = ProcessInfo.processInfo.environment["apiHost"] ?? "default fallback host" 22 | ``` 23 | 24 | The problem is this code does not just work, there is one other step you need to do first. 25 | 26 | You need to edit your Test scheme and add every environment variable you want to read to the `Environment Variables` section. 27 | 28 | ![Test scheme environment variables](scheme.png) 29 | 30 | You can rename the variables but for simplicity and readability you should probably keep the same names. 31 | 32 | -------------------------------------------------------------------------------- /content/post/2021/reading-environment-variables-from-unit-tests/scheme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2021/reading-environment-variables-from-unit-tests/scheme.png -------------------------------------------------------------------------------- /content/post/2022/using-swiftlint-for-gitlab-code-quality/quality.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2022/using-swiftlint-for-gitlab-code-quality/quality.png -------------------------------------------------------------------------------- /content/post/2023/a-few-xcode-debugging-tips/didLoadBreakpoint.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2023/a-few-xcode-debugging-tips/didLoadBreakpoint.png -------------------------------------------------------------------------------- /content/post/2023/a-few-xcode-debugging-tips/form.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2023/a-few-xcode-debugging-tips/form.png -------------------------------------------------------------------------------- /content/post/2023/a-few-xcode-debugging-tips/return.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2023/a-few-xcode-debugging-tips/return.png -------------------------------------------------------------------------------- /content/post/2023/tableviews-with-reorder-and-selection/reorder1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2023/tableviews-with-reorder-and-selection/reorder1.gif -------------------------------------------------------------------------------- /content/post/2023/tableviews-with-reorder-and-selection/reorder2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2023/tableviews-with-reorder-and-selection/reorder2.gif -------------------------------------------------------------------------------- /content/post/2023/using-critical-alerts-on-ios/alert.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2023/using-critical-alerts-on-ios/alert.png -------------------------------------------------------------------------------- /content/post/2023/using-critical-alerts-on-ios/critical.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2023/using-critical-alerts-on-ios/critical.jpg -------------------------------------------------------------------------------- /content/post/2023/using-critical-alerts-on-ios/notifications.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2023/using-critical-alerts-on-ios/notifications.jpg -------------------------------------------------------------------------------- /content/post/2023/using-critical-alerts-on-ios/settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2023/using-critical-alerts-on-ios/settings.png -------------------------------------------------------------------------------- /content/post/2024/custom-areas-in-snapshots/locationAttachment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2024/custom-areas-in-snapshots/locationAttachment.png -------------------------------------------------------------------------------- /content/post/2024/custom-areas-in-snapshots/locationAttachmentArea.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2024/custom-areas-in-snapshots/locationAttachmentArea.png -------------------------------------------------------------------------------- /content/post/2024/use-openvn-as-proxy/firefox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2024/use-openvn-as-proxy/firefox.png -------------------------------------------------------------------------------- /content/post/2025/vscode-ios-setup/afterbuild.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2025/vscode-ios-setup/afterbuild.png -------------------------------------------------------------------------------- /content/post/2025/vscode-ios-setup/build.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2025/vscode-ios-setup/build.png -------------------------------------------------------------------------------- /content/post/2025/vscode-ios-setup/copilot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2025/vscode-ios-setup/copilot.png -------------------------------------------------------------------------------- /content/post/2025/vscode-ios-setup/debugging.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2025/vscode-ios-setup/debugging.png -------------------------------------------------------------------------------- /content/post/2025/vscode-ios-setup/debugsetup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2025/vscode-ios-setup/debugsetup.png -------------------------------------------------------------------------------- /content/post/2025/vscode-ios-setup/generateconfig.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2025/vscode-ios-setup/generateconfig.png -------------------------------------------------------------------------------- /content/post/2025/vscode-ios-setup/selectworkspace.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/content/post/2025/vscode-ios-setup/selectworkspace.png -------------------------------------------------------------------------------- /layouts/_default/_markup/render-image.html: -------------------------------------------------------------------------------- 1 | {{ .Text }} -------------------------------------------------------------------------------- /layouts/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: 3 | Sitemap: {{ "sitemap.xml" | absURL }} -------------------------------------------------------------------------------- /layouts/rss.xml: -------------------------------------------------------------------------------- 1 | {{ printf "" | safeHTML }} 2 | 3 | 4 | {{ if eq .Title .Site.Title }}{{ .Site.Title }}{{ else }}{{ with .Title }}{{.}} on {{ end }}{{ .Site.Title }}{{ end }} 5 | {{ .Permalink }} 6 | Recent content {{ if ne .Title .Site.Title }}{{ with .Title }}in {{.}} {{ end }}{{ end }}on {{ .Site.Title }} 7 | Hugo -- gohugo.io{{ with .Site.LanguageCode }} 8 | {{.}}{{end}}{{ with .Site.Author.email }} 9 | {{.}}{{ with $.Site.Author.name }} ({{.}}){{end}}{{end}}{{ with .Site.Author.email }} 10 | {{.}}{{ with $.Site.Author.name }} ({{.}}){{end}}{{end}}{{ with .Site.Copyright }} 11 | {{.}}{{end}}{{ if not .Date.IsZero }} 12 | {{ .Date.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML }}{{ end }} 13 | {{ with .OutputFormats.Get "RSS" }} 14 | {{ printf "" .Permalink .MediaType | safeHTML }} 15 | {{ end }} 16 | {{ range first 15 (where site.RegularPages "Type" "in" site.Params.mainSections) }} 17 | 18 | {{ .Title }} 19 | {{ .Permalink }} 20 | {{ .Date.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML }} 21 | {{ with .Site.Author.email }}{{.}}{{ with $.Site.Author.name }} ({{.}}){{end}}{{end}} 22 | {{ .Permalink }} 23 | {{ .Summary | html }} 24 | 25 | {{ end }} 26 | 27 | -------------------------------------------------------------------------------- /layouts/shortcodes/github-repo.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | -------------------------------------------------------------------------------- /layouts/shortcodes/vimeo.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
-------------------------------------------------------------------------------- /layouts/sitemap.xml: -------------------------------------------------------------------------------- 1 | 2 | {{ range .Data.Pages }} 3 | 4 | {{ .Permalink }} 5 | {{ safeHTML ( .Date.Format "2006-01-02T15:04:05-07:00" ) }}{{ with .Sitemap.ChangeFreq }} 6 | {{ . }}{{ end }}{{ if ge .Sitemap.Priority 0.0 }} 7 | {{ .Sitemap.Priority }}{{ end }} 8 | 9 | {{ end }} 10 | -------------------------------------------------------------------------------- /netlify.toml: -------------------------------------------------------------------------------- 1 | [context.production] 2 | command = "hugo --baseURL=$URL" 3 | [context.production.environment] 4 | HUGO_VERSION = "0.110.0" 5 | 6 | [context.deploy-preview] 7 | command = "hugo --buildDrafts --buildFuture --baseURL=$DEPLOY_PRIME_URL" 8 | [context.deploy-preview.environment] 9 | HUGO_VERSION = "0.110.0" -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/screenshot.png -------------------------------------------------------------------------------- /static/_headers: -------------------------------------------------------------------------------- 1 | /* 2 | X-XSS-Protection: 1; mode=block 3 | X-Content-Type-Options: nosniff 4 | Referrer-Policy: no-referrer-when-downgrade 5 | X-Frame-Options: DENY 6 | Feature-Policy: accelerometer 'none'; camera 'none'; geolocation 'none'; gyroscope 'none'; magnetometer 'none'; microphone 'none'; payment 'none'; usb 'none' -------------------------------------------------------------------------------- /static/_redirects: -------------------------------------------------------------------------------- 1 | https://coding-journal.netlify.com/* https://blog.kulman.sk/:splat 301! 2 | http://coding-journal.netlify.com/* https://blog.kulman.sk/:splat 301! -------------------------------------------------------------------------------- /static/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/static/android-chrome-192x192.png -------------------------------------------------------------------------------- /static/android-chrome-384x384.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/static/android-chrome-384x384.png -------------------------------------------------------------------------------- /static/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/static/apple-touch-icon.png -------------------------------------------------------------------------------- /static/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | #2b5797 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /static/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/static/favicon-16x16.png -------------------------------------------------------------------------------- /static/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/static/favicon-32x32.png -------------------------------------------------------------------------------- /static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/static/favicon.ico -------------------------------------------------------------------------------- /static/images/avatar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/static/images/avatar.jpg -------------------------------------------------------------------------------- /static/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/static/mstile-150x150.png -------------------------------------------------------------------------------- /static/site.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "name": "", 3 | "short_name": "", 4 | "icons": [ 5 | { 6 | "src": "/android-chrome-192x192.png", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | }, 10 | { 11 | "src": "/android-chrome-384x384.png", 12 | "sizes": "384x384", 13 | "type": "image/png" 14 | } 15 | ], 16 | "theme_color": "#ffffff", 17 | "background_color": "#ffffff", 18 | "display": "standalone" 19 | } 20 | -------------------------------------------------------------------------------- /themes/hugo-paper/.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | -------------------------------------------------------------------------------- /themes/hugo-paper/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 南小北 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /themes/hugo-paper/assets/custom.css: -------------------------------------------------------------------------------- 1 | /* Place custom css here. */ 2 | .prose code::before { 3 | content: normal; 4 | } 5 | 6 | .prose code::after { 7 | content: normal; 8 | } 9 | 10 | .support-section { 11 | margin: 2.5rem 0; 12 | padding: 1.75rem; 13 | background-color: #f8f9fa; 14 | border-radius: 0.75rem; /* Using larger radius to match your design */ 15 | text-align: center; 16 | } 17 | 18 | .support-section p { 19 | margin: 0 0 1.25rem; 20 | font-size: 1.1rem; 21 | color: #374151; /* Using a softer color that matches your text style */ 22 | font-weight: 400; 23 | } 24 | 25 | .support-section a { 26 | display: inline-block; 27 | padding: 0.75rem 1.75rem; 28 | font-size: 0.95rem; 29 | font-weight: 500; 30 | color: #fff; 31 | background-color: #333; /* Changed to match your design's button style */ 32 | border-radius: 0.75rem; /* Matching your design's rounded corners */ 33 | text-decoration: none; 34 | transition: all 0.2s ease; 35 | } 36 | 37 | .support-section a:hover { 38 | background-color: #000; 39 | transform: translateY(-1px); 40 | } 41 | 42 | /* Dark mode */ 43 | @media (prefers-color-scheme: dark) { 44 | .support-section { 45 | background-color: rgba(255, 255, 255, 0.08); /* Subtle dark mode background */ 46 | } 47 | 48 | .support-section p { 49 | color: #e5e5e5; 50 | } 51 | 52 | .support-section a { 53 | background-color: #fff; 54 | color: #000; 55 | } 56 | 57 | .support-section a:hover { 58 | background-color: #e5e5e5; 59 | } 60 | } -------------------------------------------------------------------------------- /themes/hugo-paper/i18n/ar.yaml: -------------------------------------------------------------------------------- 1 | - id: prev_page 2 | translation: 'الصفحة السابقة' 3 | 4 | - id: next_page 5 | translation: 'الصفحة التالية' 6 | 7 | - id: read_time 8 | translation: 9 | one: 'دقيقة واحده' 10 | other: 'دقیقه {{ .Count }}' 11 | 12 | - id: toc 13 | translation: 'فهرس المحتوي' 14 | 15 | - id: translations 16 | translation: 'ترجمات اخري' 17 | 18 | - id: home 19 | translation: 'الصفحة الرئيسية' 20 | -------------------------------------------------------------------------------- /themes/hugo-paper/i18n/az.yaml: -------------------------------------------------------------------------------- 1 | - id: prev_page 2 | translation: 'Əvvəlki' 3 | 4 | - id: next_page 5 | translation: 'Növbəti' -------------------------------------------------------------------------------- /themes/hugo-paper/i18n/be.yaml: -------------------------------------------------------------------------------- 1 | - id: prev_page 2 | translation: 'Папярэдняя' 3 | 4 | - id: next_page 5 | translation: 'Наступная' 6 | -------------------------------------------------------------------------------- /themes/hugo-paper/i18n/bn.yaml: -------------------------------------------------------------------------------- 1 | - id: prev_page 2 | translation: 'পূর্ববর্তী পাতা' 3 | 4 | - id: next_page 5 | translation: 'পরবর্তী পাতা' 6 | -------------------------------------------------------------------------------- /themes/hugo-paper/i18n/de.yaml: -------------------------------------------------------------------------------- 1 | - id: prev_page 2 | translation: 'Vorherige Seite' 3 | 4 | - id: next_page 5 | translation: 'Nächste Seite' 6 | -------------------------------------------------------------------------------- /themes/hugo-paper/i18n/en.yaml: -------------------------------------------------------------------------------- 1 | - id: prev_page 2 | translation: 'Prev Page' 3 | 4 | - id: next_page 5 | translation: 'Next Page' 6 | 7 | # Related posts 8 | - id: seeAlso 9 | translation: "See also" 10 | 11 | -------------------------------------------------------------------------------- /themes/hugo-paper/i18n/es.yaml: -------------------------------------------------------------------------------- 1 | - id: prev_page 2 | translation: 'Página siguiente' 3 | 4 | - id: next_page 5 | translation: 'Página anterior' 6 | -------------------------------------------------------------------------------- /themes/hugo-paper/i18n/fa.yaml: -------------------------------------------------------------------------------- 1 | - id: prev_page 2 | translation: 'صفحه قبل' 3 | 4 | - id: next_page 5 | translation: 'صفحه بعد' 6 | 7 | - id: read_time 8 | translation: 9 | one: 'یک دقیقه' 10 | other: 'دقیقه {{ .Count }}' 11 | 12 | - id: home 13 | translation: 'صفحه اصلی' 14 | -------------------------------------------------------------------------------- /themes/hugo-paper/i18n/fr.yaml: -------------------------------------------------------------------------------- 1 | - id: prev_page 2 | translation: 'Page précédente' 3 | 4 | - id: next_page 5 | translation: 'Page suivante' 6 | -------------------------------------------------------------------------------- /themes/hugo-paper/i18n/he.yaml: -------------------------------------------------------------------------------- 1 | - id: prev_page 2 | translation: 'לעמוד הקודם' 3 | 4 | - id: next_page 5 | translation: 'לעמוד הבא' 6 | -------------------------------------------------------------------------------- /themes/hugo-paper/i18n/id.yaml: -------------------------------------------------------------------------------- 1 | - id: prev_page 2 | translation: 'Sebelumnya' 3 | 4 | - id: next_page 5 | translation: 'Selanjutnya' 6 | -------------------------------------------------------------------------------- /themes/hugo-paper/i18n/it.yaml: -------------------------------------------------------------------------------- 1 | - id: prev_page 2 | translation: 'Pagina Precedente' 3 | 4 | - id: next_page 5 | translation: 'Pagina Successiva' 6 | -------------------------------------------------------------------------------- /themes/hugo-paper/i18n/ja.yaml: -------------------------------------------------------------------------------- 1 | - id: prev_page 2 | translation: '前のページ' 3 | 4 | - id: next_page 5 | translation: '次のページ' 6 | -------------------------------------------------------------------------------- /themes/hugo-paper/i18n/ko.yaml: -------------------------------------------------------------------------------- 1 | - id: prev_page 2 | translation: '이전 페이지' 3 | 4 | - id: next_page 5 | translation: '다음 페이지' 6 | -------------------------------------------------------------------------------- /themes/hugo-paper/i18n/oc.yaml: -------------------------------------------------------------------------------- 1 | - id: prev_page 2 | translation: 'Pagina precedenta' 3 | 4 | - id: next_page 5 | translation: 'Pagina seguenta' 6 | -------------------------------------------------------------------------------- /themes/hugo-paper/i18n/pl.yaml: -------------------------------------------------------------------------------- 1 | - id: prev_page 2 | translation: 'Poprzednia strona' 3 | 4 | - id: next_page 5 | translation: 'Następna strona' 6 | -------------------------------------------------------------------------------- /themes/hugo-paper/i18n/pt.yaml: -------------------------------------------------------------------------------- 1 | - id: prev_page 2 | translation: 'Página Anterior' 3 | 4 | - id: next_page 5 | translation: 'Página Seguinte' 6 | -------------------------------------------------------------------------------- /themes/hugo-paper/i18n/ru.yaml: -------------------------------------------------------------------------------- 1 | - id: prev_page 2 | translation: 'Сюда' 3 | 4 | - id: next_page 5 | translation: 'Туда' 6 | -------------------------------------------------------------------------------- /themes/hugo-paper/i18n/sw.yaml: -------------------------------------------------------------------------------- 1 | - id: prev_page 2 | translation: 'Ukurasa Uliotangulia' 3 | 4 | - id: next_page 5 | translation: 'Ukurasa Unaofuata' 6 | -------------------------------------------------------------------------------- /themes/hugo-paper/i18n/tr.yaml: -------------------------------------------------------------------------------- 1 | - id: prev_page 2 | translation: 'Öneceki' 3 | 4 | - id: next_page 5 | translation: 'Sonrakı' -------------------------------------------------------------------------------- /themes/hugo-paper/i18n/zh.yaml: -------------------------------------------------------------------------------- 1 | - id: prev_page 2 | translation: '上一页' 3 | 4 | - id: next_page 5 | translation: '下一页' 6 | -------------------------------------------------------------------------------- /themes/hugo-paper/images/pagespeed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/themes/hugo-paper/images/pagespeed.png -------------------------------------------------------------------------------- /themes/hugo-paper/images/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/themes/hugo-paper/images/screenshot.png -------------------------------------------------------------------------------- /themes/hugo-paper/images/screenshot_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/themes/hugo-paper/images/screenshot_dark.png -------------------------------------------------------------------------------- /themes/hugo-paper/images/screenshot_mobile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/themes/hugo-paper/images/screenshot_mobile.png -------------------------------------------------------------------------------- /themes/hugo-paper/images/tn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/themes/hugo-paper/images/tn.png -------------------------------------------------------------------------------- /themes/hugo-paper/layouts/404.html: -------------------------------------------------------------------------------- 1 | {{ define "main" }} 2 |

5 | 404 6 |

7 | {{ end }} 8 | -------------------------------------------------------------------------------- /themes/hugo-paper/layouts/_default/baseof.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | {{ $.Scratch.Delete "bg_color" }} 4 | {{ $.Scratch.Delete "social_list" }} 5 | {{ $.Scratch.Delete "avatar_url" }} 6 | 7 | 8 | {{ $color_map := dict "linen" "#faf8f1" "wheat" "#f8f5d7" "gray" "#fbfbfb" 9 | "light" "#fff" }} 10 | {{ $.Scratch.Set "bg_color" (index $color_map (site.Params.color | default 11 | (print "linen"))) }} 12 | {{ $bg_color := $.Scratch.Get "bg_color" }} 13 | 14 | 15 | {{ $social_params := slice "twitter" "github" "instagram" "linkedin" "mastodon" 16 | "threads" "bluesky" "rss" }} 17 | {{ range $social_params }} 18 | {{ if isset site.Params . }} 19 | {{ $.Scratch.Add "social_list" (slice .) }} 20 | {{ end }} 21 | {{ end }} 22 | 23 | 24 | {{ if site.Params.avatar }} 25 | {{ if in site.Params.avatar "http" }} 26 | {{ $.Scratch.Set "avatar_url" (absURL "/images/avatar.jpg") }} 27 | {{ else }} 28 | {{ $official_cdn := "https://www.gravatar.com/avatar/" }} 29 | {{ $cdn := (site.Params.gravatarCdn | default $official_cdn) }} 30 | {{ $md5 := (md5 site.Params.avatar) }} 31 | {{ $avatar_url := print $cdn $md5 "?s=160&d=identicon" }} 32 | {{ $.Scratch.Set "avatar_url" (absURL "/images/avatar.jpg") }} 33 | {{ end }} 34 | {{ end }} 35 | 36 | 42 | {{ partial "head.html" . }} 43 | 44 | {{ partial "header.html" . }} 45 | 46 |
49 | {{ block "main" . }}{{ end }} 50 |
51 | 52 | {{ partial "footer.html" . }} 53 | 54 | 55 | -------------------------------------------------------------------------------- /themes/hugo-paper/layouts/partials/footer.html: -------------------------------------------------------------------------------- 1 | 23 | -------------------------------------------------------------------------------- /themes/hugo-paper/layouts/partials/math.html: -------------------------------------------------------------------------------- 1 | {{ if site.Params.localKatex }} 2 | 3 | 4 | 5 | {{ else }} 6 | 12 | 18 | 24 | {{ end }} 25 | 26 | 40 | -------------------------------------------------------------------------------- /themes/hugo-paper/layouts/partials/mermaid.html: -------------------------------------------------------------------------------- 1 | 2 | {{ if .Params.mermaid }} 3 | 7 | 14 | {{ end }} 15 | -------------------------------------------------------------------------------- /themes/hugo-paper/layouts/shortcodes/collapse.html: -------------------------------------------------------------------------------- 1 | {{ if not (.Get "summary") }} 2 | {{ errorf "missing param 'summary': %s" .Position }} 3 | {{ else if not (.Get "content") }}{{ warnf "missing param 'content': %s" 4 | .Position }} 5 | {{ end }} 6 | 7 |
8 | {{ .Get "summary" | markdownify }} 9 | {{ .Get "content" | markdownify }} 10 |
11 | -------------------------------------------------------------------------------- /themes/hugo-paper/static/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/themes/hugo-paper/static/apple-touch-icon.png -------------------------------------------------------------------------------- /themes/hugo-paper/static/bluesky.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /themes/hugo-paper/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/themes/hugo-paper/static/favicon.ico -------------------------------------------------------------------------------- /themes/hugo-paper/static/github.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /themes/hugo-paper/static/instagram.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /themes/hugo-paper/static/linkedin.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /themes/hugo-paper/static/mastodon.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /themes/hugo-paper/static/rss.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /themes/hugo-paper/static/theme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorkulman/coding-journal/03e3aae8eed6058bf92cd902cece7aa5b7f644f1/themes/hugo-paper/static/theme.png -------------------------------------------------------------------------------- /themes/hugo-paper/static/theme.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /themes/hugo-paper/static/threads.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /themes/hugo-paper/static/twitter.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /themes/hugo-paper/theme.toml: -------------------------------------------------------------------------------- 1 | # theme.toml template for a Hugo theme 2 | # See https://github.com/gohugoio/hugoThemes#themetoml for an example 3 | 4 | name = "Paper" 5 | license = "MIT" 6 | licenselink = "https://github.com/nanxiaobei/hugo-paper/blob/main/LICENSE" 7 | description = "A simple, clean, flexible Hugo theme" 8 | homepage = "https://github.com/nanxiaobei/hugo-paper/" 9 | demosite = "https://hugo-paper.vercel.app" 10 | tags = ["Responsive", "Simple", "Clean", "Light", "White", "Blog"] 11 | features = ["Responsive", "One Column", "Blog"] 12 | min_version = "0.57.1" 13 | 14 | [author] 15 | name = "nanxiaobei" 16 | homepage = "https://lee.so/" 17 | --------------------------------------------------------------------------------