<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[echoeyecodes]]></title><description><![CDATA[Fullstack software engineer obsessed about video games, and the gaming industry!]]></description><link>https://blog.echoeyecodes.com</link><generator>RSS for Node</generator><lastBuildDate>Wed, 15 Apr 2026 18:32:22 GMT</lastBuildDate><atom:link href="https://blog.echoeyecodes.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[A quick rundown of the major improvements made to my video snipping tool]]></title><description><![CDATA[I took some time to work on my existing projects, and came across some potential problems I didn't realize for a long time. ClipClip was developed to trim videos into chunks of equal parts, mostly suitable for sharing correctly synced videos on Whats...]]></description><link>https://blog.echoeyecodes.com/a-quick-rundown-of-the-major-improvements-made-to-my-video-snipping-tool</link><guid isPermaLink="true">https://blog.echoeyecodes.com/a-quick-rundown-of-the-major-improvements-made-to-my-video-snipping-tool</guid><category><![CDATA[Android]]></category><category><![CDATA[learning]]></category><category><![CDATA[General Programming]]></category><dc:creator><![CDATA[Oluwafemi Obajuluwa]]></dc:creator><pubDate>Wed, 20 Apr 2022 17:59:27 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1650370657261/nXzwjZZpt.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I took some time to work on my existing projects, and came across some potential problems I didn't realize for a long time. <a target="_blank" href="https://play.google.com/store/apps/details?id=com.echoeyecodes.clipclip">ClipClip</a> was developed to trim videos into chunks of equal parts, mostly suitable for sharing correctly synced videos on WhatsApp statuses, and one of the core features of this project was giving the users the ability to select a custom start and end time needed to split into parts. At this point, the challenges of this project was divided into 2 phases:</p>
<ol>
<li>A reliable tool that would execute the splitting operations on videos</li>
<li>A custom UI tool for selecting timestamp ranges</li>
</ol>
<p><a target="_blank" href="https://ffmpeg.org">FFMPEG</a> is a popular software for editing and manipulating videos, so this was my go-to tool to use for this project. Being my first time creating custom android views, I spent some time developing the custom slider tool for selecting time ranges. The first implementation appeared to work well, and after some time with learning and practicing with custom views, I discovered some problems with the nature and behaviour of the bloated code. Here's a screenshot of what it looked like, and a <a target="_blank" href="https://gist.github.com/echoeyecodes/63ee7c5a5146fe53788e6203591598e8">link to the source code.</a>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1650367253298/yfjynAQ1C.png" alt="Initial screen layout" /></p>
<p>This writeup is divided into two phases of major development:</p>
<ol>
<li>The SelectionView</li>
<li>Foreground Services &amp; Work Manager  </li>
</ol>
<h1 id="heading-1-the-selection-view">1. The Selection View</h1>
<p>I used a ViewGroup for the selection view, and created custom View components for the thumb markers and progress marker. My approach to this involved a bunch of unnecessary callbacks between the viewgroup and the marker views.</p>
<p>For the recent release, I <a target="_blank" href="https://gist.github.com/echoeyecodes/2b6807c7f5c78dc3b512fccb6e34c2a9">rewrote the selection view</a> utilizing a single View component that manages all interactions including marker sliding and view dragging. Instead of using child views as markers in the SelectionView, I created variables that represents the coordinates of the markers. These coordinates are made visible to the user as touchable regions drawn on the screen with the Canvas object provided in the <code>onDraw()</code> method. The touch movements are captured within the CustomSelectionView region, and the values obtained are used to calculate the expected position values for the thumb coordinates based on where the touch events occurred. When these coordinates change, the canvas redraws them on screen after a call to <code>invalidate()</code> to show the new position of the thumb markers.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1650366996958/4k4aIK--m.png" alt="Screenshowing the new SelectionView.png" /></p>
<h2 id="heading-about-the-thumb-markers">About the Thumb Markers</h2>
<p>A thing to note about the markers is that the start and end values are initialized as 0 and width value of the view respectively. However, these values are not solely used to determine percentage offsets of the start and end values of the thumb markers and the reason is based on the expected behaviour of the selection view. The SelectionView is expected to capture all possible seconds from a video, and the thumb markers (including the touchable region) already occupy some space from the total size of the SelectionView. So, if we are to use 0 and the width of the view to represent the mininum and maximum values respectively within the slider, everything would be fine as long as we allow for intersection between the two markers.</p>
<p>However, we obviously wouldn't want that since it would be a bit difficult for users to properly select ranges that are between the marker coordinates and the size of the marker. The solution is to prevent the respective markers from intersecting each other. That means the minimum value for the start marker would be 0, and the maximum value for it would be --&gt; the end marker coordinates - size of its marker.</p>
<pre><code>    <span class="hljs-comment">/**Kotlin
     * Returns the maximum permissible value of the left thumb
     * i.e ranges between 0 and the start of the
     * right thumb
     */</span>
    <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">getMinMaxLeft</span><span class="hljs-params">(positionX: <span class="hljs-type">Float</span>)</span></span>: <span class="hljs-built_in">Float</span> {
        <span class="hljs-keyword">return</span> max(<span class="hljs-number">0f</span>, min(positionX, thumbEnd - (SIZE * <span class="hljs-number">2</span>)))
    }
</code></pre><p>Also the minimum value for the end marker would be --&gt; the x coordinate of the start marker + size of the marker, while the maximum value would be the width of the selection view.</p>
<pre><code class="lang-Kotlin">    <span class="hljs-comment">/**
     * Returns the maximum permissible value of the right thumb
     * i.e not exceeding the width of the screen and the end of the
     * left thumb
     */</span>
    <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">getMinMaxRight</span><span class="hljs-params">(positionX: <span class="hljs-type">Float</span>)</span></span>: <span class="hljs-built_in">Float</span> {
        <span class="hljs-keyword">return</span> max(thumbStart + (SIZE * <span class="hljs-number">2</span>), min(positionX, width.toFloat()))
    }
</code></pre>
<p>Using this approach brings in another problem that needs to be resolved. Calculating percentage offset for both thumb markers as <code>coordinate_value/width</code> would be incorrect since we've factored the sizes of both thumbs from SelectionView width to represent the touchable regions for the thumbs from their respective start coordinates.</p>
<pre><code class="lang-Kotlin">    <span class="hljs-comment">/**
     * returns true if the touch is between the start thumb
     * position plus width of the thumb
     */</span>
    <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">isLeft</span><span class="hljs-params">(positionX: <span class="hljs-type">Float</span>)</span></span>: <span class="hljs-built_in">Boolean</span> {
        <span class="hljs-keyword">return</span> (positionX <span class="hljs-keyword">in</span> thumbStart..thumbStart + SIZE)
    }

    <span class="hljs-comment">/**
     * returns true if the touch is between the end thumb
     * position minus width of the thumb
     */</span>
    <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">isRight</span><span class="hljs-params">(positionX: <span class="hljs-type">Float</span>)</span></span>: <span class="hljs-built_in">Boolean</span> {
        <span class="hljs-keyword">return</span> (positionX <span class="hljs-keyword">in</span> thumbEnd - SIZE..thumbEnd)
    }
</code></pre>
<p>Doing this means that it would be impossible to get 0.0 value when both markers meet due to the nature of the real and apparent coordinate values of the start and end thumb. Look at the image below as an example. Both markers meet, but instead of the expected time difference to be <code>00:00:00:000</code>, it shows <code>00:00:20:615</code> because the offset is still being calculated with the real coordinates and width of the SelectionView. <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1650367071583/cbFZ172X5.png" alt="Screen showing the markers meeting at a point" /></p>
<p>The way around this was to factor in the size of both thumb markers and subtract them from the actual width of the view to represent the apparent total width.</p>
<pre><code class="lang-Kotlin">    <span class="hljs-comment">/**
     * Returns the width of the draggable region
     */</span>
    <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">getActualWidth</span><span class="hljs-params">()</span></span>: <span class="hljs-built_in">Float</span> {
        <span class="hljs-keyword">return</span> width - (SIZE * <span class="hljs-number">2</span>)
    }
</code></pre>
<p>This directly affects the correct values for the start and end coordinates when calculating the percentage offsets relative to the SelectionView size. So to obtain the correct results, the thumb start coordinates remains as is since the starting point is from 0. However the end coordinates needs to be altered to match up with the new maximum value declared in the code above. In the <code>getActualWidth()</code> 
function, the total width was reduced by the size of the two thumb markers, so this same value would have to be subtracted from the end coordinate.</p>
<pre><code class="lang-Kotlin">    <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">getThumbEnd</span><span class="hljs-params">()</span></span>: <span class="hljs-built_in">Float</span> {
        <span class="hljs-keyword">return</span> (thumbEnd - (SIZE * <span class="hljs-number">2</span>))
    }
</code></pre>
<p>Now, the distance offset of the start and end coordinates can be calculated correctly as follows:</p>
<pre><code class="lang-Kotlin">    <span class="hljs-comment">/**
     * Returns the percentage value position of the start of the thumb
     * relative to the draggable region
     */</span>
    <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">getThumbStart</span><span class="hljs-params">()</span></span>: <span class="hljs-built_in">Float</span> {
        <span class="hljs-keyword">return</span> (thumbStart) / getActualWidth()
    }

    <span class="hljs-comment">/**
     * Returns the percentage value position of the end of the thumb
     * relative to the draggable region
     */</span>
    <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">getThumbEnd</span><span class="hljs-params">()</span></span>: <span class="hljs-built_in">Float</span> {
        <span class="hljs-keyword">return</span> (thumbEnd - (SIZE * <span class="hljs-number">2</span>)) / getActualWidth()
    }
</code></pre>
<p>Here's the final result for the complete SelectionView:
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1650367213899/wTU_AqTLc.png" alt="Final screen" /></p>
<h3 id="heading-pro-tip">Pro-tip</h3>
<p>The value of the end coordinates is expected to be equal to the width of the SelectionView, however the width of the view isn't available during intialization and therefore yields zero. When the measured width and height eventually becomes avaiable, android calls the <code>onSizeChanged()</code> method and delivers the dimensions as parameters, so this method can be overriden to set the end coordinate of the second thumb marker</p>
<pre><code class="lang-Kotlin">    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onSizeChanged</span><span class="hljs-params">(w: <span class="hljs-type">Int</span>, h: <span class="hljs-type">Int</span>, oldw: <span class="hljs-type">Int</span>, oldh: <span class="hljs-type">Int</span>)</span></span> {
        <span class="hljs-keyword">super</span>.onSizeChanged(w, h, oldw, oldh)
        <span class="hljs-keyword">this</span>.thumbEnd = w.toFloat()
        <span class="hljs-keyword">this</span>.h = h.toFloat()
        <span class="hljs-keyword">this</span>.w = w.toFloat()
    }
</code></pre>
<h1 id="heading-2-foreground-services-and-work-manager">2. Foreground Services and Work Manager</h1>
<p>During the trimming operation on the video, I delegated this action to a foreground service that handles the execution of the process and displays the status via a notification. Since the previous release, the app worked as expected on devices I tested with. However, after some months, I recently discovered that the app crashes on Android 12+ devices. It was difficult to detect the root cause of this problem since the crashlytics report from firebase noted the crash, but it offered no reason as to why the crash happened nor any information on the model of devices experiencing this issue.</p>
<p>After a bit of digging into why this was happening, I was able to trace the cause to the foreground service. I came across this <a target="_blank" href="https://developer.android.com/guide/components/foreground-services#background-start-restrictions">caveat</a> from the documentation about background processes restricted from lauching foreground services on Android 12+. <a target="_blank" href="https://developer.android.com/guide/components/foreground-services#background-start-restriction-update-app-logic">WorkManager is recommended as an alternative</a> to this. It was hard to believe this could be the problem since the foreground service could have only be initialized after the user clicks a button on the app, and this means the app would have had to be running and displaying on screen.</p>
<p>I decided to give it a try just to see if it would resolve the error and surpisingly it did! The problem was the foreground service all along, and I'm still completely baffled about why the simple foreground service previously implemented crashed on higher android versions despite not violating the rules required to run one. And even if it did crash, why wasn't the <code>ForegroundServiceStartNotAllowedException</code> thrown and logged in the firebase crashlytics log reports?
[<img src="https://media.giphy.com/media/L3zUGGx1DgLo54951b/giphy.gif" alt="I need answers" /></p>
<p>Anyway, I'm glad I revisited this project because I was able to improve it from its previous awful state🙉 into something much better and more efficient for use by every social media story spammer out there😁. If you don't already have the app, click <a target="_blank" href="https://play.google.com/store/apps/details?id=com.echoeyecodes.clipclip">here</a> to get it from the App Store! The full source for the project is also publicly available on my Github profile. <a target="_blank" href="https://github.com/echoeyecodes/ClipClip">You can check it out</a> and lemme know what you think!</p>
]]></content:encoded></item><item><title><![CDATA[Creating and optimizing custom blurs with OpenCV on Android]]></title><description><![CDATA[An image is made up of a number of pixels arranged in a 2-dimensional grid; rows and columns. The resolution of the image is a product of the number of rows and columns, with the rows representing the height of the image and columns representing the ...]]></description><link>https://blog.echoeyecodes.com/creating-and-optimizing-custom-blurs-with-opencv-on-android</link><guid isPermaLink="true">https://blog.echoeyecodes.com/creating-and-optimizing-custom-blurs-with-opencv-on-android</guid><category><![CDATA[Android]]></category><category><![CDATA[opencv]]></category><category><![CDATA[learning]]></category><category><![CDATA[General Programming]]></category><dc:creator><![CDATA[Oluwafemi Obajuluwa]]></dc:creator><pubDate>Fri, 08 Apr 2022 15:19:52 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/unsplash/4uCdG0scCJ0/upload/v1649158225119/f5GrMNWN7.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>An image is made up of a number of pixels arranged in a 2-dimensional grid; rows and columns. The resolution of the image is a product of the number of rows and columns, with the rows representing the height of the image and columns representing the width of the image. A 1080x720 image has a total of 777,600 pixels, and each pixel comprises of a number of colors referred to as channels. A digital image would typically consist of 3 channels; red, green, and blue. Greyscale images consists of just a single channel; black or white. Each pixel is represented by 8-bits (~a byte) with values ranging from 0-255. Whenever effects such as blurs are applied to images, under the hood, it's a set of mathematical operations applied directly on pixels to achieve the desired results.</p>
<p>There are various techniques used to blur images, some of which are;</p>
<ul>
<li>Mean filters</li>
<li>Gaussian blurs</li>
<li>Bilateral filters</li>
</ul>
<p>A popular approach to applying filters is the Kernel Convolution, where a set of numbers (kernel) is passed accross the pixels of an image. A kernel is a small matrix used for blurring, and other image effects. The size of the kernel must be odd, and the greater the value of the kernel, the greater the blurring effect. The kernel is applied to every pixel in the image, with the currently selected pixel at the center of the kernel. Each value in the kernel is multiplied with the respective pixel values within the matrix range highlighted by the kernel and summed up together. The central pixel value is eventually replaced with the result of these operations.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1649157957909/EpGJaHH2k.png" alt="mean blur filter illustration" /></p>
<h2 id="heading-native-approach-to-blurring-images">Native approach to blurring images</h2>
<p>To implement the mean filter in android, we can obtain the pixels by converting the image to bitmap, applying the kernel to every pixel. We'll be applying the blurs to this sample image:
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1649414147291/YF0zCpbOu.png" alt="Screenshot_20220408-113138.png" /></p>
<p>Here's my implementation for this:</p>
<pre><code class="lang-kotlin"><span class="hljs-keyword">private</span> <span class="hljs-keyword">suspend</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">meanFilter</span><span class="hljs-params">(bitmap: <span class="hljs-type">Bitmap</span>)</span></span> {
        <span class="hljs-keyword">val</span> kernel = floatArrayOf(<span class="hljs-number">1</span> / <span class="hljs-number">9f</span>, <span class="hljs-number">1</span> / <span class="hljs-number">9f</span>, <span class="hljs-number">1</span> / <span class="hljs-number">9f</span>, <span class="hljs-number">1</span> / <span class="hljs-number">9f</span>, <span class="hljs-number">1</span> / <span class="hljs-number">9f</span>, <span class="hljs-number">1</span> / <span class="hljs-number">9f</span>, <span class="hljs-number">1</span> / <span class="hljs-number">9f</span>, <span class="hljs-number">1</span> / <span class="hljs-number">9f</span>, <span class="hljs-number">1</span> / <span class="hljs-number">9f</span>)
        <span class="hljs-keyword">return</span> withContext(Dispatchers.IO) {
            <span class="hljs-keyword">val</span> diameter = <span class="hljs-number">3</span> <span class="hljs-comment">// 3x3 matrix</span>
            <span class="hljs-keyword">val</span> cols = bitmap.width
            <span class="hljs-keyword">val</span> rows = bitmap.height
            <span class="hljs-keyword">val</span> step = (diameter - <span class="hljs-number">1</span>) / <span class="hljs-number">2</span>

            <span class="hljs-keyword">val</span> imagePixels = IntArray(rows * cols)
            <span class="hljs-keyword">val</span> newImagePixels = IntArray(rows * cols)

            bitmap.getPixels(imagePixels, <span class="hljs-number">0</span>, cols, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, cols, rows) <span class="hljs-comment">// here we are assigning all pixel values to the IntArray so we can process the individual pixels via the kernel</span>

            <span class="hljs-keyword">for</span> (i <span class="hljs-keyword">in</span> <span class="hljs-number">0</span> until cols) {
                <span class="hljs-keyword">for</span> (j <span class="hljs-keyword">in</span> <span class="hljs-number">0</span> until rows) {
                    <span class="hljs-keyword">val</span> startCoord = Point(j - step, i - step)
                    <span class="hljs-keyword">val</span> endCoord = Point(j + step, i + step)

                    <span class="hljs-keyword">val</span> matrix = ArrayList&lt;<span class="hljs-built_in">Int</span>&gt;()
                    <span class="hljs-keyword">for</span> (_col <span class="hljs-keyword">in</span> startCoord.y..endCoord.y) {
                        <span class="hljs-keyword">for</span> (_row <span class="hljs-keyword">in</span> startCoord.x..endCoord.x) {
                            <span class="hljs-keyword">if</span> (_row &lt; <span class="hljs-number">0</span> || _row &gt;= rows || _col &lt; <span class="hljs-number">0</span> || _col &gt;= cols) {
                                <span class="hljs-comment">//ignore pixels out of matrix bounds</span>
                                matrix.add(<span class="hljs-number">0</span>)
                            } <span class="hljs-keyword">else</span> {
                                <span class="hljs-keyword">val</span> pixel = imagePixels[_row * cols + _col]
                                matrix.add(pixel)
                            }
                        }
                    }

                    <span class="hljs-keyword">val</span> sum = matrix.mapIndexed { index, value -&gt;
                        <span class="hljs-keyword">val</span> multiplier = kernel[index]

                        <span class="hljs-keyword">val</span> alpha = value shr <span class="hljs-number">24</span> and <span class="hljs-number">0xFF</span>
                        <span class="hljs-keyword">val</span> red = ((value ushr <span class="hljs-number">16</span> and <span class="hljs-number">0xFF</span>) * multiplier).toInt()
                        <span class="hljs-keyword">val</span> green = ((value ushr <span class="hljs-number">8</span> and <span class="hljs-number">0xFF</span>) * multiplier).toInt()
                        <span class="hljs-keyword">val</span> blue = ((value and <span class="hljs-number">0xFF</span>) * multiplier).toInt()
                        ((alpha) shl <span class="hljs-number">24</span>) or ((red) shl <span class="hljs-number">16</span>) or ((green) shl <span class="hljs-number">8</span>) or (blue)
                    }.sum()
                    newImagePixels[j * cols + i] = sum
                }
            }
            Bitmap.createBitmap(newImagePixels, cols, rows, Bitmap.Config.ARGB_8888)
        }
    }
</code></pre>
<p>You'll notice we did some bitwise shift operations on the pixel values before applying the kernel on them, that is because every pixel is made up of certain 8-bit color values, and these values need to be isolated before being processed, then combined again to form a pixel value.</p>
<h2 id="heading-blurring-with-opencv">Blurring with OpenCV</h2>
<p>Now that we have an idea on how blur filters work natively, a useful image processing library that does a lot of these special type of operations faster is OpenCV. Here, images can be blurred more accurately using just a few lines of code compared to what we initially wrote. You should have OpenCV setup with a new or existing android project to get started with implementing them in your application.</p>
<p>Trying out the same blurring filter above with OpenCV;</p>
<pre><code class="lang-kotlin">    <span class="hljs-keyword">private</span> <span class="hljs-keyword">suspend</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">blurImage</span><span class="hljs-params">(bitmap: <span class="hljs-type">Bitmap</span>)</span></span>:Bitmap {
        <span class="hljs-keyword">return</span> withContext(Dispatchers.IO) {

            <span class="hljs-keyword">val</span> imageSrc = Mat()

            Utils.bitmapToMat(bitmap, imageSrc)
            <span class="hljs-keyword">val</span> size = <span class="hljs-number">24.0</span>

            <span class="hljs-keyword">val</span> destination = Mat()
            Imgproc.blur(imageSrc, destination, Size(size, size))

            <span class="hljs-keyword">val</span> copy = Bitmap.createBitmap(
                destination.width(),
                destination.height(),
                Bitmap.Config.ARGB_8888
            )
            Utils.matToBitmap(destination, copy)
            copy
        }
    }
</code></pre>
<p>Here's the output:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1649156269080/niZDuE0DP.png" alt="Blurred image" /></p>
<p>Pretty straightfoward eh? Great! Well, what if we have to only blur only a particular segment of the image, instead of the whole image. We'll use the <code>submat()</code> function to select our region of interest, and only blur those parts we need. As an example, we'll try to blur an image starting from 30% away from the origin at the top and left side of the image, having a width/height that is 30% of the image size.</p>
<pre><code class="lang-kotlin">    <span class="hljs-keyword">private</span> <span class="hljs-keyword">suspend</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">blurImage</span><span class="hljs-params">(bitmap: <span class="hljs-type">Bitmap</span>)</span></span>:Bitmap {
        <span class="hljs-keyword">return</span> withContext(Dispatchers.IO) {

            <span class="hljs-keyword">val</span> imageSrc = Mat()

            Utils.bitmapToMat(bitmap, imageSrc)
            <span class="hljs-keyword">val</span> size = <span class="hljs-number">24.0</span>

            <span class="hljs-keyword">val</span> rows = imageSrc.rows()
            <span class="hljs-keyword">val</span> cols = imageSrc.cols()

            <span class="hljs-keyword">val</span> rowStart = (<span class="hljs-number">0.3</span> * rows).toInt()
            <span class="hljs-keyword">val</span> rowEnd = (<span class="hljs-number">0.6</span> * rows).toInt()
            <span class="hljs-keyword">val</span> colStart = (<span class="hljs-number">0.3</span> * cols).toInt()
            <span class="hljs-keyword">val</span> colEnd = (<span class="hljs-number">0.6</span> * cols).toInt()

            <span class="hljs-keyword">val</span> subRegion = imageSrc.submat(rowStart, rowEnd, colStart, colEnd)
            Imgproc.blur(subRegion, subRegion, Size(size, size))

            <span class="hljs-keyword">val</span> copy = Bitmap.createBitmap(
                imageSrc.width(),
                imageSrc.height(),
                Bitmap.Config.ARGB_8888
            )
            Utils.matToBitmap(imageSrc, copy)
            copy
        }
    }
</code></pre>
<p>Image output:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1649156334693/6oL33rFbM.png" alt="Blurred image using submat" /></p>
<p>This is a bit different from the previous implementation, and the explanation is quite simple. the <code>submat</code> function accepts a number of arguments that defines rect points we need as our region of interest. Even though this function attempts to select just a segment from the original image and returns it, it still holds a direct reference to the original image so anything we do with the subregion reflects onn the selected region, and also inadvertently affects the original image. <a target="_blank" href="https://stackoverflow.com/a/26823577">Here's an explanation for it</a></p>
<p>Now, we have a bit of control over the kind of blurring operations we need for our images, but not so much control as we would want. With the previous example, we can only blur out certain segments in rectangular shapes only. What if we need to make the blur masks to be based off various forms such as circles, rectangles, or even freehand shapes. How do we achieve this using OpenCV?</p>
<h2 id="heading-advanced-blurring-in-opencv">Advanced blurring in OpenCV</h2>
<p>For this example, we'll try reimplementing the rectangular blurring using a more dynamic approach before trying out something different. OpenCV consists of a number of methods that allows for creating masks in various shapes we want ranging from rectangles, triangles, and other polygons.</p>
<p>For rectangles, we'll create a rectangular mask in black and white and perform bitwise operations on this mask so that our blurring operations can occur within these masks only. To create a rectangular mask in OpenCV, we'll make use of the <code>Imgproc.rectangle()</code> function.</p>
<pre><code class="lang-kotlin">    <span class="hljs-keyword">private</span> <span class="hljs-keyword">suspend</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">blurImage</span><span class="hljs-params">(bitmap: <span class="hljs-type">Bitmap</span>)</span></span>:Bitmap {
        <span class="hljs-keyword">return</span> withContext(Dispatchers.IO) {
            <span class="hljs-keyword">val</span> imageSrc = Mat()

            Utils.bitmapToMat(bitmap, imageSrc)

            <span class="hljs-keyword">val</span> rows = imageSrc.rows()
            <span class="hljs-keyword">val</span> cols = imageSrc.cols()

            <span class="hljs-keyword">val</span> startY = (<span class="hljs-number">0.3</span>*rows).toInt()
            <span class="hljs-keyword">val</span> endY = (<span class="hljs-number">0.7</span>*rows).toInt()
            <span class="hljs-keyword">val</span> startX = (<span class="hljs-number">0.3</span>*cols).toInt()
            <span class="hljs-keyword">val</span> endX = (<span class="hljs-number">0.7</span>*cols).toInt()

            <span class="hljs-keyword">val</span> innerMask = Mat.zeros(imageSrc.size(), imageSrc.type())
            innerMask.setTo(Scalar.all(<span class="hljs-number">0.0</span>))

            <span class="hljs-comment">//thickness set to -1 for inner fill</span>
            Imgproc.rectangle(
                innerMask,
                Rect(startX,startY,endX,endY),
                Scalar.all(<span class="hljs-number">255.0</span>),
                -<span class="hljs-number">1</span>
            )

            <span class="hljs-keyword">val</span> outerMask = Mat()
            Core.bitwise_not(innerMask, outerMask)

            <span class="hljs-keyword">val</span> blurredImage = Mat()
            Imgproc.blur(imageSrc, blurredImage, Size(<span class="hljs-number">64.0</span>, <span class="hljs-number">64.0</span>))

            <span class="hljs-comment">//original image minus cutout</span>
            <span class="hljs-keyword">val</span> originalCut = Mat()
            Core.bitwise_and(imageSrc, outerMask, originalCut)

            <span class="hljs-comment">//blurred image minus cutout</span>
            <span class="hljs-keyword">val</span> blurredCut = Mat()
            Core.bitwise_and(blurredImage, innerMask, blurredCut)

            <span class="hljs-keyword">val</span> merge = Mat()
            Core.bitwise_or(originalCut, blurredCut, merge)

            <span class="hljs-keyword">val</span> copy = Bitmap.createBitmap(merge.width(), merge.height(), Bitmap.Config.ARGB_8888)
            Utils.matToBitmap(merge, copy)
            copy
        }
    }
</code></pre>
<p>And here's the result:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1649156413223/6L3TZp9bW.png" alt="blurred image using rectangular mask" /></p>
<p>Here's an explanation of what is going on. </p>
<pre><code class="lang-kotlin"><span class="hljs-keyword">val</span> innerMask = Mat.zeros(imageSrc.size(), imageSrc.type())
innerMask.setTo(Scalar.all(<span class="hljs-number">0.0</span>))
</code></pre>
<p>Here we are creating an empty image, with pixel values set to 0, meaning this is a black image</p>
<pre><code class="lang-kotlin">Imgproc.rectangle(innerMask, Rect(startX,startY,endX,endY), Scalar.all(<span class="hljs-number">255.0</span>), -<span class="hljs-number">1</span>)
</code></pre>
<p>The above code means we are drawing a rectangle within the black image we created. The start and end points are provided within the rect object. This region is filled with a white mask via <code>Scalar.all(255.0)</code> having a thickness of -1. According to the docs, a negative thickness value enables the shape to be filled rather than having a stroke for the drawn shape.</p>
<p>At this point, we have a black image containing a white mask. We'll need this mask to perform some bitmanipulation and embed our blurred segment within this white mask, and the rest of the original image within the black region.</p>
<p>Here's the result for the inner mask:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1649156478526/MIKFaoZjM.png" alt="inner blurred mask" /></p>
<p>Now, unto the next piece of code</p>
<pre><code class="lang-kotlin"><span class="hljs-keyword">val</span> outerMask = Mat()
Core.bitwise_not(innerMask, outerMask)
</code></pre>
<p>From the black and white image, we're trying to invert the segments such that the black region becomes white, and the white region becomes black. It follows the basic principle of binary operators using the NOT gate. Such that when we have a value like 1110011 and a not gate is applied here, the ones (1) becomes zeros (0) and vice versa. Luckily, OpenCV has a function that allows for performing these forms of operations. In the above piece of code, we used Core.bitwise(srcImage, destinationImage) to achieve this.</p>
<p>At this point, the value of outer mask would appear like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1649157387300/oA7-gCWkC.png" alt="outer blurred mask" /></p>
<p>For the outer mask, we'll attempt to copy the the orignal image pixel values to this variable using another bitwise operator, <code>and</code>. This also follows the same principle as bitwise operations when combining two binary numbers together, such that there can only be a truthy value when all values involved are non-zero, else we have a false value. This way the colored parts of the original image remain the same, while the black regions remain zero as required.</p>
<pre><code class="lang-kotlin"><span class="hljs-keyword">val</span> originalCut = Mat()
Core.bitwise_and(imageSrc, outerMask, originalCut)
</code></pre>
<p>here's the result:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1649156587679/q8Zp1v7L7.png" alt="original image plus outer mask" /></p>
<p>We'll be doing the opposite for our blurred image as well to obtain a blurred mask:</p>
<pre><code class="lang-kotlin"><span class="hljs-keyword">val</span> blurredCut = Mat()
Core.bitwise_and(blurredImage, innerMask, blurredCut)
</code></pre>
<p>Result for this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1649156631753/NsbAKTjWG.png" alt="blurred image plus inner mask" /></p>
<p>Finally, we combine the original cut and the blurred cut to achieve a single image that represents a merge between the two image. The black pixels would be added with the blurred pixels to yield a blurred pixel, thereby replacing all black pixels between both images. A bitwise operation that gurantees this form of idea is the <code>or</code> operator, whereby we have a truthy value as long as one of the values involved in the artihmetic operation is non-zero. Here's how it is implemented.</p>
<pre><code class="lang-kotlin"><span class="hljs-keyword">val</span> merge = Mat()
Core.bitwise_or(originalCut, blurredCut, merge)
</code></pre>
<p>Now merge represents our true blurred region results we're trying to achieve as we did using submat. Here's the result you should be getting:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1649156671874/sKWG7dwDM.png" alt="final blurred image" /></p>
<p>If we want to achieve a circular blur using this same approach, all we have to do is replace the <code>Imgproc.rectangle()</code> with <code>Imgproc.circle()</code> and pass in the required parameters required to draw the circle. Such as this:</p>
<pre><code class="lang-kotlin"><span class="hljs-keyword">val</span> circleMask = Mat()
Imgproc.circle(circleMask, org.opencv.core.Point(rowEnd/<span class="hljs-number">2.0</span>, rowEnd/<span class="hljs-number">2.0</span>), rowEnd/<span class="hljs-number">2</span>, Scalar(<span class="hljs-number">1.0</span>))
</code></pre>
<h2 id="heading-one-more-thing">One more thing...</h2>
<p>Looking at the previous image, you'll notice there's a sharp edge between the blurred image bounds and the rest of the original image. What if we wanted to avoid this, such that the blurred region appears to blend alongside the original image as shown in the figure below?</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1649156719879/ZNLEM9Rkh.png" alt="blurred image with smooth edges" /></p>
<p>We'll be doing something called an alpha blend, which is a process of overlaying a foreground image with transparency over a background image. At every pixel of the image, we need to combine the foreground image, with the background image using an alpha mask. The foreground image would be the blurred image, the background image is the original image, and the alpha mask would be represented by the blurred black and white mask. The formula for doing this operation is gotten from <a target="_blank" href="https://learnopencv.com/alpha-blending-using-opencv-cpp-python/">here</a>:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1649156851845/Ccq71BJgW.png" alt="Alpha blend formula" /></p>
<p>Here's our implementation in kotlin:</p>
<pre><code class="lang-kotlin">    <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">alphaBlend</span><span class="hljs-params">(imageSrc:<span class="hljs-type">Mat</span>, blurredImage: <span class="hljs-type">Mat</span>, blurredMask: <span class="hljs-type">Mat</span>)</span></span>: Mat{
        <span class="hljs-keyword">val</span> destination = Mat(imageSrc.size(), imageSrc.type())

        <span class="hljs-keyword">for</span> (col <span class="hljs-keyword">in</span> <span class="hljs-number">0</span> until destination.cols()){
            <span class="hljs-keyword">for</span> (row <span class="hljs-keyword">in</span> <span class="hljs-number">0</span> until destination.rows()){
                <span class="hljs-keyword">val</span> pixel = imageSrc.<span class="hljs-keyword">get</span>(row, col)
                <span class="hljs-keyword">val</span> blurredPixel = blurredImage.<span class="hljs-keyword">get</span>(row, col)
                <span class="hljs-keyword">val</span> blurVal = blurredMask.<span class="hljs-keyword">get</span>(row, col)[<span class="hljs-number">0</span>] / <span class="hljs-number">255</span>

                <span class="hljs-keyword">val</span> newPixelValue = pixel.mapIndexed { index, value -&gt;
                    (blurVal * blurredPixel[index]) + ((<span class="hljs-number">1.0f</span> - blurVal) * value)
                }.toDoubleArray()

                destination.put(row, col, *newPixelValue)
            }
        }
        <span class="hljs-keyword">return</span> destination
    }
</code></pre>
<p>We're getting every pixel from the blurred mask, dividing it by 255 such that we get a value ranging between 0 and 1. We then multiply this value with every blurred pixel, and subtract the same value with from 1.0 then multiply it with the original image. We finally obtain the new pixel value and assign it to our new image variable. The transparency would be 0 on the original and blurry image, thereby yielding the same pixel value, however this value varies as it approaches the edges of the blurry image, thus leading to the transparent blurry effect along the edges of the blurred mask.</p>
<p>Now we'll update our <code>blurImage()</code> function to match this blend function. </p>
<pre><code class="lang-kotlin">    <span class="hljs-keyword">private</span> <span class="hljs-keyword">suspend</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">blurImage</span><span class="hljs-params">(bitmap: <span class="hljs-type">Bitmap</span>)</span></span>:Bitmap {
        <span class="hljs-keyword">return</span> withContext(Dispatchers.IO) {
            <span class="hljs-keyword">val</span> imageSrc = Mat()

            Utils.bitmapToMat(bitmap, imageSrc)

            <span class="hljs-keyword">val</span> innerMask = Mat.zeros(imageSrc.size(), imageSrc.type())

            <span class="hljs-comment">//thickness set to -1 for inner fill</span>
            Imgproc.circle(
                innerMask,
                Point(imageSrc.width() / <span class="hljs-number">2.0</span>, imageSrc.height() / <span class="hljs-number">1.5</span>),
                <span class="hljs-number">600</span>,
                Scalar.all(<span class="hljs-number">255.0</span>),
                -<span class="hljs-number">1</span>
            )

            <span class="hljs-keyword">val</span> blurredImage = Mat(imageSrc.size(), imageSrc.type())
            Imgproc.blur(imageSrc, blurredImage, Size(<span class="hljs-number">64.0</span>, <span class="hljs-number">64.0</span>))

            <span class="hljs-keyword">val</span> blurredMask = Mat(innerMask.size(), innerMask.type())
            Imgproc.blur(innerMask, blurredMask, Size(<span class="hljs-number">64.0</span>, <span class="hljs-number">64.0</span>))

            <span class="hljs-keyword">val</span> merge = alphaBlend(imageSrc, blurredImage, blurredMask)

            <span class="hljs-keyword">val</span> copy = Bitmap.createBitmap(merge.width(), merge.height(), Bitmap.Config.ARGB_8888)
            Utils.matToBitmap(merge, copy)
            copy
        }
    }
</code></pre>
<p>Now this is the final result:
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1649156899602/mFZqOyvPE.png" alt="blurred image with smooth edges" /></p>
<h2 id="heading-a-new-problem-emerges">A new problem emerges</h2>
<p>One thing you'll notice about this is that our blur process has become really slow, taking up to over 15 seconds to achieve the blur result. And this is because of two reasons;</p>
<ul>
<li>We are looping through every pixel in the 2-dimensional grid, meaning for a 1080x1080 image, we're actually iterating through the image 1,166,400 times which is quite a lot!</li>
<li>We are accessing the pixels directly from the image using the <code>get</code> and <code>set</code> methods, which are fairly expensive operations.</li>
</ul>
<h2 id="heading-a-way-out-of-this-mess">A way out of this mess</h2>
<p>After doing a bunch of research on various ways to optimze this process, I was finally able to figure out a way out of this thanks to this <a target="_blank" href="https://answers.opencv.org/question/5/how-to-get-and-modify-the-pixel-of-mat-in-java/">post</a> which provided a couple of insights regarding OpenCV.</p>
<p>From this post, I figured the best way to optimize the entire process was to convert the pixels to primitives like IntArray/FloatArray and perform the operations on this object, the reassign the processed pixels back to the image object. The get/set operations would be faster than way, and could also allow for single interation of every pixel since the image is now represented as a one-dimensional array.</p>
<p>First, I would like to highlight some approaches that didn't work for me at first. I assigned the pixels to ByteArray, and performed the normal alpha blending operations on the pixels but for some reason, I wasn't able to achieve the desired result. Here's what I did:</p>
<pre><code class="lang-kotlin">    <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">alphaBlend</span><span class="hljs-params">(imageSrc:<span class="hljs-type">Mat</span>, blurredImage: <span class="hljs-type">Mat</span>, blurredMask: <span class="hljs-type">Mat</span>)</span></span>: Mat{

        <span class="hljs-keyword">val</span> total = imageSrc.width() * imageSrc.height()
        <span class="hljs-keyword">val</span> channels = imageSrc.channels()
        <span class="hljs-keyword">val</span> size = total * channels

        <span class="hljs-keyword">val</span> array = ByteArray(size)
        <span class="hljs-keyword">val</span> array1 = ByteArray(size)
        <span class="hljs-keyword">val</span> array2 = ByteArray(size)

        <span class="hljs-keyword">val</span> array3 = ByteArray(size)

        <span class="hljs-keyword">val</span> destination = Mat(imageSrc.size(), imageSrc.type())

        imageSrc.<span class="hljs-keyword">get</span>(<span class="hljs-number">0</span>,<span class="hljs-number">0</span>, array)
        blurredImage.<span class="hljs-keyword">get</span>(<span class="hljs-number">0</span>,<span class="hljs-number">0</span>, array1)
        blurredMask.<span class="hljs-keyword">get</span>(<span class="hljs-number">0</span>,<span class="hljs-number">0</span>, array2)

        <span class="hljs-keyword">for</span> (index <span class="hljs-keyword">in</span> <span class="hljs-number">0</span> until size){
            <span class="hljs-keyword">val</span> pixel = array[index]
            <span class="hljs-keyword">val</span> blurredPixel = array1[index]
            <span class="hljs-keyword">val</span> blurVal = (array2[index]) / <span class="hljs-number">255.0f</span>

            <span class="hljs-keyword">val</span> newValue = ((blurVal * blurredPixel) + ((<span class="hljs-number">1.0f</span> - blurVal) * pixel)).toInt().toByte()
            array3[index] = newValue
        }
        destination.put(<span class="hljs-number">0</span>,<span class="hljs-number">0</span>, array3)
        <span class="hljs-keyword">return</span> destination
    }
</code></pre>
<p>Then I spent days figuring out why this didn't work, and decided to opt in for other valid primitives.
Instead of using ByteArray, I opted for <code>FloatArray</code> since the alpha mask value ought to be a decimal value ranging from 0.0 to 1.0. After doing this, I encountered some errors thrown like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1649157783143/dxusUuDY0.png" alt="mat data type conversion error" /></p>
<p>After a couple of hours spent on debugging, I realized that the data type of the images, ought to match the array primitives they're being assigned to due to certain conditions that have been implemented under the hood by OpenCV. What's even more surprising is that these conditions have been stated here in this <a target="_blank" href="https://answers.opencv.org/question/5/how-to-get-and-modify-the-pixel-of-mat-in-java/">post</a> that helped me out with optimization, but overlooked at the time:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1649157646305/IQOTe_5cH.png" alt="working with pixels using array primitives" /></p>
<p>So what I did was simple, before assigning the pixels to the FloatArray primitive, I converted the images to the required data types for float arrays, like this:</p>
<pre><code class="lang-kotlin">imageSrc.convertTo(imageSrc, CV_32F)
blurredImage.convertTo(blurredImage, CV_32F)
blurredMask.convertTo(blurredMask, CV_32F)
</code></pre>
<p>Well the above approach solved the error, only that this form of conversion gave rise to another error as shown below:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1649157758273/hNkM1kBWj.png" alt="mat to bitmap conversion error" /></p>
<p>Well as stated in the error message, before using <code>Utils.MatToBitmap()</code>, the mat object needs to be a datatype that is either <code>CV_8UC1</code>, <code>CV_8UC3</code>, or <code>CV_8UC4</code>. So the solution is to convert the destination mat object to either of these by;</p>
<pre><code class="lang-kotlin">destination.convertTo(destination, CV_8UC3)
</code></pre>
<p>Here's the full code implementation for the optimized image blur using alpha blending:</p>
<pre><code class="lang-kotlin">    <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">alphaBlend</span><span class="hljs-params">(imageSrc:<span class="hljs-type">Mat</span>, blurredImage: <span class="hljs-type">Mat</span>, blurredMask: <span class="hljs-type">Mat</span>)</span></span>: Mat{

        <span class="hljs-keyword">val</span> total = imageSrc.width() * imageSrc.height()
        <span class="hljs-keyword">val</span> channels = imageSrc.channels()
        <span class="hljs-keyword">val</span> size = total * channels

        <span class="hljs-keyword">val</span> array = FloatArray(size)
        <span class="hljs-keyword">val</span> array1 = FloatArray(size)
        <span class="hljs-keyword">val</span> array2 = FloatArray(size)

        <span class="hljs-keyword">val</span> array3 = FloatArray(size)
        imageSrc.convertTo(imageSrc, CV_32F)
        blurredImage.convertTo(blurredImage, CV_32F)
        blurredMask.convertTo(blurredMask, CV_32F)

        <span class="hljs-keyword">val</span> destination = Mat(imageSrc.size(), imageSrc.type())

        imageSrc.<span class="hljs-keyword">get</span>(<span class="hljs-number">0</span>,<span class="hljs-number">0</span>, array)
        blurredImage.<span class="hljs-keyword">get</span>(<span class="hljs-number">0</span>,<span class="hljs-number">0</span>, array1)
        blurredMask.<span class="hljs-keyword">get</span>(<span class="hljs-number">0</span>,<span class="hljs-number">0</span>, array2)

        <span class="hljs-keyword">for</span> (index <span class="hljs-keyword">in</span> <span class="hljs-number">0</span> until size){
            <span class="hljs-keyword">val</span> pixel = array[index]
            <span class="hljs-keyword">val</span> blurredPixel = array1[index]
            <span class="hljs-keyword">val</span> blurVal = (array2[index]) / <span class="hljs-number">255.0f</span>

            <span class="hljs-keyword">val</span> newValue = ((blurVal * blurredPixel) + ((<span class="hljs-number">1.0f</span> - blurVal) * pixel))
            array3[index] = newValue
        }
        destination.put(<span class="hljs-number">0</span>,<span class="hljs-number">0</span>, array3)
        destination.convertTo(destination, CV_8UC3)
        <span class="hljs-keyword">return</span> destination
    }

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">suspend</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">blurImage</span><span class="hljs-params">(bitmap: <span class="hljs-type">Bitmap</span>)</span></span>:Bitmap {
        <span class="hljs-keyword">return</span> withContext(Dispatchers.IO) {
            <span class="hljs-keyword">val</span> imageSrc = Mat()

            Utils.bitmapToMat(bitmap, imageSrc)

            <span class="hljs-keyword">val</span> innerMask = Mat.zeros(imageSrc.size(), imageSrc.type())

            <span class="hljs-comment">//thickness set to -1 for inner fill</span>
            Imgproc.circle(
                innerMask,
                Point(imageSrc.width() / <span class="hljs-number">2.0</span>, imageSrc.height() / <span class="hljs-number">1.5</span>),
                <span class="hljs-number">600</span>,
                Scalar.all(<span class="hljs-number">255.0</span>),
                -<span class="hljs-number">1</span>
            )

            <span class="hljs-keyword">val</span> blurredImage = Mat(imageSrc.size(), imageSrc.type())
            Imgproc.blur(imageSrc, blurredImage, Size(<span class="hljs-number">64.0</span>, <span class="hljs-number">64.0</span>))

            <span class="hljs-keyword">val</span> blurredMask = Mat(innerMask.size(), innerMask.type())
            Imgproc.blur(innerMask, blurredMask, Size(<span class="hljs-number">64.0</span>, <span class="hljs-number">64.0</span>))

            <span class="hljs-keyword">val</span> merge = alphaBlend(imageSrc, blurredImage, blurredMask)

            <span class="hljs-keyword">val</span> copy = Bitmap.createBitmap(merge.width(), merge.height(), Bitmap.Config.ARGB_8888)
            Utils.matToBitmap(merge, copy)
            copy
        }
    }
</code></pre>
<p>This approach works well, is better optimized, and performs the blur operations WAY faster than the previous implementation since we are performing the bit manipulations using kotlin array primitives on a single iteration, rather than using the direct access method.</p>
<p><a target="_blank" href="https://gist.github.com/echoeyecodes/92e2102bf28c8db14cc111f94f2b547a">Here's a link to the gist</a>. I'm open to different ideas, so if you think there is a more efficient/less lengthy way to achieve this, please let me know!😊</p>
]]></content:encoded></item><item><title><![CDATA[Creating a News App for Android]]></title><description><![CDATA[During my early days of learning android development, one of the exciting projects I wanted to work on was a News App, specifically for gaming contents. Since I knew so little at the time, one of the roadblacks I faced was not having an idea on how h...]]></description><link>https://blog.echoeyecodes.com/creating-a-news-app-for-android</link><guid isPermaLink="true">https://blog.echoeyecodes.com/creating-a-news-app-for-android</guid><category><![CDATA[Android]]></category><category><![CDATA[coding]]></category><category><![CDATA[learning]]></category><category><![CDATA[android apps]]></category><dc:creator><![CDATA[Oluwafemi Obajuluwa]]></dc:creator><pubDate>Wed, 23 Feb 2022 11:27:24 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/unsplash/-baMCm2CLKM/upload/v1645615574753/48oJv7TUu.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>During my early days of learning android development, one of the exciting projects I wanted to work on was a News App, specifically for gaming contents. Since I knew so little at the time, one of the roadblacks I faced was not having an idea on how html content could be rendered as native views on android as seen on popular news apps like IGN, or CNET. Online contents on building news app weren't all that helpful as well, because all articles I could find on this only explained how you could render a list of articles in a recyclerview, or showing them on a webview. None really covered the basis on parsing HTML and showing the full content of an HTML file.</p>
<p>Well after a really long while of tinkering with android development by working on other projects I could do, I became interested again with building a news app. I really wasn't sure of how I was going to do this, but I just kept going at it, trying out multiple ways of solving this problem. I downloaded a couple of news apps from the playstore to observe how these apps work, trying to see if any would "give in" on the secret of how they handled it lol, but all I could notice was that those content were rendered on a RecyclerView.</p>
<p>That was one piece of the puzzle that actually turned out to be really helpful. Knowing the contents were displayed on a recyclerview meant that the content of the news/article are being passed down as a list. Which gave rise to figuring out the solution to the next problem:</p>
<h2 id="heading-how-to-parse-html-content-to-a-list">How to parse HTML content to a list</h2>
<p>We know an HTML document comprises of text tags such as <code>&lt;p&gt;</code>, <code>&lt;a&gt;</code>, <code>&lt;i&gt;</code>, <code>&lt;em&gt;</code>, etc. It also contains container elements that holds group of elements as a single entity such as <code>&lt;div&gt;</code>, <code>&lt;section&gt;</code>, etc. Other popular elements are <code>&lt;img /&gt;</code> for images, <code>&lt;video /&gt;</code> for displaying videos, and lots more. We know what these elements are used for, and the task now is to figure out a way to transform these tags and their respective content to lists. As an example, I would be using the article template used by <a target="_blank" href="https://ign.com">IGN</a>. The sample article is at <a target="_blank" href="https://www.ign.com/articles/how-long-is-horizon-forbidden-west">this link</a>. After visiting the link, you'll need to right click on any part of the document and left click the "Inspect Element" option to display the HTML structure of the webpage.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1645533878016/aaWtnuwz5.png" alt="Screenshot (18).png" /></p>
<p>We need to understand the arrangement pattern generally used for articles. This way, we can imitate this pattern and figure out a way to grab the data we need, and pass them on to the list.</p>
<h2 id="heading-the-solution-traverse-the-html-document">The solution? Traverse the HTML document</h2>
<p>We'll need to pass through every element of the HTML content, and extract the data we need based on the kind it is (text, image, video, headers, etc). Luckily, there's a library that does this really well.</p>
<ul>
<li>Open up your Android studio, Create a project, and install the <a target="_blank" href="https://jsoup.org/">JSOUP</a> dependency adding this one line of code in your app's <code>build.gradle</code> file.</li>
</ul>
<pre><code><span class="hljs-attribute">implementation</span> 'org.jsoup:jsoup:<span class="hljs-number">1</span>.<span class="hljs-number">14</span>.<span class="hljs-number">3</span>'
</code></pre><ul>
<li><p>Create an empty Kotlin file, and name it <code>ArticleParser.kt</code>. This is the class that would be responsible for traversing the DOM and adding the content to an array list.</p>
</li>
<li><p>Now we need to describe the data types that would be synonymous to the HTML tags. To do this, we'll create a new kotlin file that holds every possible type we'll be needing to represent our tags.</p>
</li>
</ul>
<p>First is the HTML text tags like <code>&lt;p&gt;</code>, <code>&lt;i&gt;</code>, <code>&lt;a&gt;</code>. Since this tags are generally used to hold text, we'll have a global class name for this sort of text tags called <code>Paragraph</code>:</p>
<pre><code><span class="hljs-keyword">sealed</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NewsArticle</span></span>{
     <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Paragraph</span></span>(<span class="hljs-keyword">val</span> value:String): NewsArticle()
}
</code></pre><p>Before proceeding, we'll need to understand how the article section of the webpage is structured. Going back to "Inspect Elements", we'll observe that the body/content of the article is within a parent <code>&lt;section&gt;</code> tag, having one of its classnames as "article-content". This is would be the starting point of our traversal.</p>
<p><strong>An important thing to note about JSoup types is that <code>Node</code> refers to any element or text content available on the HTML document. <code>Element</code> refers to only HTML element tags, not the text content. <code>Element</code> extends <code>Node</code>. And finallly we have <code>TextNode</code> which also extends <code>Node</code>, but refers to only the text content of an HTML file.</strong></p>
<p>In our <code>NewsArticle</code> class, we'll be creating a function that accepts a <code>Node</code> variable, and we traverse the content of this Node.</p>
<pre><code class="lang-Kotlin"><span class="hljs-keyword">suspend</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">traverseElement</span><span class="hljs-params">(element: <span class="hljs-type">Node</span>)</span></span>: List&lt;NewsArticle&gt;{
    <span class="hljs-keyword">return</span> withContent(Dispatchers.IO){
           element.traverse(<span class="hljs-keyword">object</span>: NodeVisitor){
                 <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">head</span><span class="hljs-params">(node: <span class="hljs-type">Node</span>, depth: <span class="hljs-type">Int</span>)</span></span>{

              }
                <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">tail</span><span class="hljs-params">(node: <span class="hljs-type">Node</span>, depth: <span class="hljs-type">Int</span>)</span></span>{

             }
    })
   }
}
</code></pre>
<p>The <code>head()</code> method of the <code>NodeVisitor</code> interface is invoked when we encounter the start of an HTML element/text, and passes the corresponding node, and depth. The <code>tail()</code> method is invoked when we encounter the end of an HTML element, and this method also passes the corresponding node and depth during traversing the DOM. <code>depth</code> refers to the nested level of any of the nodes encountered during traversal. This means the start of any node encountered during traversal has a depth of 0. If this node contains sibling nodes, the sibling nodes would have a depth of <code>1, 2, 3, ...n</code>.</p>
<p>It'll be ideal to handle text nodes, before any other forms of nodes. Mostly beccause, we need to figure out a way to concatenate texts as a single entity, regardless of any form they might come in such as Regular texts, Bold texts, Italic, or Link texts. Here's a sample of what I mean:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1645605223584/ulyiyNna9.PNG" alt="Capture.PNG" /></p>
<p>If you observe the text above, you'll notice it comprises of regular, bold, and italics. We wouldn't want these various element break down into different blocks while traversing through all the elements and adding them to a list. So to achieve this, we'll create a nullable <code>NewsArticle</code> object that holds the current node during traversal, and we'll check to see if it is a type of <code>NewsArticle.Paragraph</code>. If it is, we concatenate the next text with the previous text. If it isn't, we'll add the exisiting <code>NewsArticle</code> object into the list, and create a new <code>NewsArticle.Paragraph</code> object.</p>
<pre><code class="lang-Kotlin"><span class="hljs-keyword">var</span> articlePiece: NewsArticle? = <span class="hljs-literal">null</span>

    <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">resolveArticleParagraph</span><span class="hljs-params">(word: <span class="hljs-type">String</span>)</span></span>: NewsArticle {
        <span class="hljs-keyword">val</span> temp = word.replace(<span class="hljs-string">"\\\\s+"</span>, <span class="hljs-string">""</span>)
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">if</span> (temp.isNotEmpty()) {
            <span class="hljs-keyword">return</span> <span class="hljs-keyword">if</span> (articlePiece != <span class="hljs-literal">null</span> &amp;&amp; articlePiece <span class="hljs-keyword">is</span> NewsArticle.Paragraph) {
                NewsArticle.Paragraph((articlePiece <span class="hljs-keyword">as</span> NewsArticle.Paragraph).value.plus(word))
            } <span class="hljs-keyword">else</span> {
                NewsArticle.Paragraph(word)
            }
        } <span class="hljs-keyword">else</span> {
            NewsArticle.Paragraph(<span class="hljs-string">""</span>)
        }
    }


<span class="hljs-keyword">suspend</span> function traverseElement(element: Node): List&lt;NewsArticle&gt;{
    <span class="hljs-keyword">return</span> withContent(Dispatchers.IO){
           element.traverse(<span class="hljs-keyword">object</span>: NodeVisitor{
                 <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">head</span><span class="hljs-params">(node: <span class="hljs-type">Node</span>, depth: <span class="hljs-type">Int</span>)</span></span>{
                     <span class="hljs-keyword">if</span> (node <span class="hljs-keyword">is</span> TextNode) {
                        <span class="hljs-keyword">val</span> word = node.text()
                        articlePiece = resolveArticleParagraph(word)
                    }
              }
                <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">tail</span><span class="hljs-params">(node: <span class="hljs-type">Node</span>, depth: <span class="hljs-type">Int</span>)</span></span>{

             }
    })
   }
}
</code></pre>
<p>This piece of code above only transforms all of the text as regular text. Now we'll need to do something that would show a distincition between regular texts, link texts, and any other form of text.</p>
<p>We'll write an extension function for the <code>Element</code> node, to determine if the type of tag encountered during traversal is a text element.</p>
<pre><code class="lang-Kotlin"><span class="hljs-keyword">open</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">RegularText</span></span>(<span class="hljs-keyword">val</span> text:String)

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ItalicText</span></span>(text: String):RegularText(text)
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">LinkText</span></span>(text: String):RegularText(text)
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BoldText</span></span>(text: String):RegularText(text)

<span class="hljs-function"><span class="hljs-keyword">fun</span> Element.<span class="hljs-title">isText</span><span class="hljs-params">()</span></span>: <span class="hljs-built_in">Boolean</span> {
    <span class="hljs-keyword">val</span> tag = <span class="hljs-keyword">this</span>.tagName()
    <span class="hljs-keyword">return</span> tag == <span class="hljs-string">"a"</span> || tag == <span class="hljs-string">"em"</span> || tag == <span class="hljs-string">"i"</span> || tag == <span class="hljs-string">"p"</span> || tag == <span class="hljs-string">"strong"</span>
}


<span class="hljs-function"><span class="hljs-keyword">fun</span> Element.<span class="hljs-title">getTextType</span><span class="hljs-params">()</span></span>: RegularText {
    <span class="hljs-keyword">val</span> tag = <span class="hljs-keyword">this</span>.tagName()
    <span class="hljs-keyword">val</span> text = <span class="hljs-keyword">this</span>.text()

    <span class="hljs-keyword">return</span> <span class="hljs-keyword">when</span> (tag) {
        <span class="hljs-string">"a"</span> -&gt; LinkText(text)
        <span class="hljs-string">"i"</span>, <span class="hljs-string">"em"</span> -&gt; ItalicText(text)
        <span class="hljs-string">"strong"</span> -&gt; BoldText(text)
        <span class="hljs-keyword">else</span> -&gt; RegularText(text)
    }
}
</code></pre>
<p>Now back to our <code>traverseElement()</code> method, we'll modify the code to be aware of various forms of text tags we need to look out for:</p>
<pre><code class="lang-Kotlin">    <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">openArticleLink</span><span class="hljs-params">()</span></span>: NewsArticle {
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">if</span> (articlePiece != <span class="hljs-literal">null</span>) {
            <span class="hljs-keyword">if</span> (articlePiece <span class="hljs-keyword">is</span> NewsArticle.Paragraph) {
                NewsArticle.Paragraph((articlePiece <span class="hljs-keyword">as</span> NewsArticle.Paragraph).value.plus(<span class="hljs-string">"["</span>))
            } <span class="hljs-keyword">else</span> {
                <span class="hljs-comment">//when a paragraph starts with a link sentence</span>
                addToArticle()
                NewsArticle.Paragraph(<span class="hljs-string">"["</span>)
            }
        } <span class="hljs-keyword">else</span> {
            NewsArticle.Paragraph(<span class="hljs-string">"["</span>)
        }
    }


   <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">openArticleItalic</span><span class="hljs-params">()</span></span>: NewsArticle {
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">if</span> (articlePiece != <span class="hljs-literal">null</span>) {
            <span class="hljs-keyword">if</span> (articlePiece <span class="hljs-keyword">is</span> NewsArticle.Paragraph) {
                NewsArticle.Paragraph((articlePiece <span class="hljs-keyword">as</span> NewsArticle.Paragraph).value.plus(<span class="hljs-string">"_"</span>))
            } <span class="hljs-keyword">else</span> {
                <span class="hljs-comment">//when a paragraph starts with an italic sentence</span>
                addToArticle()
                NewsArticle.Paragraph(<span class="hljs-string">"_"</span>)
            }
        } <span class="hljs-keyword">else</span> {
            NewsArticle.Paragraph(<span class="hljs-string">"_"</span>)
        }
    }

    <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">openArticleBold</span><span class="hljs-params">()</span></span>: NewsArticle {
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">if</span> (articlePiece != <span class="hljs-literal">null</span>) {
            <span class="hljs-keyword">if</span> (articlePiece <span class="hljs-keyword">is</span> NewsArticle.Paragraph) {
                NewsArticle.Paragraph((articlePiece <span class="hljs-keyword">as</span> NewsArticle.Paragraph).value.plus(<span class="hljs-string">"*"</span>))
            } <span class="hljs-keyword">else</span> {
                <span class="hljs-comment">//when a paragraph starts with an italic sentence</span>
                addToArticle()
                NewsArticle.Paragraph(<span class="hljs-string">"*"</span>)
            }
        } <span class="hljs-keyword">else</span> {
            NewsArticle.Paragraph(<span class="hljs-string">"*"</span>)
        }
    }

    <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">closeArticleLink</span><span class="hljs-params">(link: <span class="hljs-type">String</span>)</span></span>: NewsArticle {
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">if</span> (articlePiece != <span class="hljs-literal">null</span> &amp;&amp; articlePiece <span class="hljs-keyword">is</span> NewsArticle.Paragraph) {
            NewsArticle.Paragraph((articlePiece <span class="hljs-keyword">as</span> NewsArticle.Paragraph).value.plus(<span class="hljs-string">"]"</span>.plus(<span class="hljs-string">"(<span class="hljs-subst">${link}</span>)"</span>)))
        } <span class="hljs-keyword">else</span> {
            NewsArticle.Paragraph(<span class="hljs-string">""</span>)
        }
    }

    <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">closeArticleItalic</span><span class="hljs-params">()</span></span>: NewsArticle {
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">if</span> (articlePiece != <span class="hljs-literal">null</span> &amp;&amp; articlePiece <span class="hljs-keyword">is</span> NewsArticle.Paragraph) {
            NewsArticle.Paragraph((articlePiece <span class="hljs-keyword">as</span> NewsArticle.Paragraph).value.plus(<span class="hljs-string">"_"</span>))
        } <span class="hljs-keyword">else</span> {
            NewsArticle.Paragraph(<span class="hljs-string">""</span>)
        }
    }

    <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">closeArticleBold</span><span class="hljs-params">()</span></span>: NewsArticle {
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">if</span> (articlePiece != <span class="hljs-literal">null</span> &amp;&amp; articlePiece <span class="hljs-keyword">is</span> NewsArticle.Paragraph) {
            NewsArticle.Paragraph((articlePiece <span class="hljs-keyword">as</span> NewsArticle.Paragraph).value.plus(<span class="hljs-string">"*"</span>))
        } <span class="hljs-keyword">else</span> {
            NewsArticle.Paragraph(<span class="hljs-string">""</span>)
        }
    }

<span class="hljs-keyword">suspend</span> function traverseElement(element: Node): List&lt;NewsArticle&gt;{
    <span class="hljs-keyword">return</span> withContent(Dispatchers.IO){
           element.traverse(<span class="hljs-keyword">object</span>: NodeVisitor{
                 <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">head</span><span class="hljs-params">(node: <span class="hljs-type">Node</span>, depth: <span class="hljs-type">Int</span>)</span></span>{
                     <span class="hljs-keyword">if</span> (node <span class="hljs-keyword">is</span> TextNode) {
                        <span class="hljs-keyword">val</span> word = node.text()
                        articlePiece = resolveArticleParagraph(word)
                    } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (node <span class="hljs-keyword">is</span> Element) {
                        <span class="hljs-keyword">if</span> (node.isText()) {
                            <span class="hljs-keyword">if</span> (node.getTextType() <span class="hljs-keyword">is</span> LinkText) {
                                articlePiece = openArticleLink()
                            } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (node.getTextType() <span class="hljs-keyword">is</span> ItalicText) {
                                articlePiece = openArticleItalic()
                            } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (node.getTextType() <span class="hljs-keyword">is</span> BoldText) {
                                articlePiece = openArticleBold()
                            }
                        }
              }
                <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">tail</span><span class="hljs-params">(node: <span class="hljs-type">Node</span>, depth: <span class="hljs-type">Int</span>)</span></span>{
                     <span class="hljs-keyword">if</span> (node.isText()) {
                                <span class="hljs-keyword">if</span> (node.getTextType() <span class="hljs-keyword">is</span> LinkText) {
                                    <span class="hljs-keyword">val</span> link = node.attr(<span class="hljs-string">"href"</span>)
                                    articlePiece = closeArticleLink(link)
                                } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (node.getTextType() <span class="hljs-keyword">is</span> ItalicText) {
                                    articlePiece = closeArticleItalic()
                                } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (node.getTextType() <span class="hljs-keyword">is</span> BoldText) {
                                    articlePiece = closeArticleBold()
                                }
                            }
             }
    })
   }
}
</code></pre>
<p>Here's an explanation of what is happening above:
When we encounter a <code>LinkText</code>, instead of passing off the whole text to the list as a raw text, we'll do a bit of markdown syntax such that the text ends up being like <code>[some text here](https://link.com)</code> or <code>_text should be in italics_</code></p>
<p>Now how do we know when we are done with a block so it can be added as an item to the list. The idea was to delegete breaks at the <code>tail()</code>, such that when we get to the closing tag of an element at a particlar depth level, the current <code>NewsArticle</code> object is added to the list and reinitialized to null again for the next traversal.</p>
<p>The <code>tail()</code> method ends up being with the following snippet:</p>
<pre><code class="lang-Kotlin"><span class="hljs-keyword">if</span> (depth == articleParserConfig.breakDepth) {
      addToArticle()
      addSpacer()
}
</code></pre>
<p>Handling the text nodes is where the majority of the work is. Finally, you'll be needing Regex and android's <code>SpannableStringBuilder</code> to properly format and style the text based on the kinds they are. With this idea, considerations for other Container Elements such as images, videos, gallery views can easily be implemented. The full source code for the sample project can be found <a target="_blank" href="https://github.com/echoeyecodes/IGN">here</a></p>
]]></content:encoded></item><item><title><![CDATA[Database table structure for different notification events]]></title><description><![CDATA[I set out to build one of my favorite projects some time around June, and while I was able to complete it to some extent and successfully launched it, I did face some setbacks while trying to implement certain features in the application. One of the ...]]></description><link>https://blog.echoeyecodes.com/database-table-structure-for-different-notification-events</link><guid isPermaLink="true">https://blog.echoeyecodes.com/database-table-structure-for-different-notification-events</guid><category><![CDATA[database]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Tutorial]]></category><category><![CDATA[coding]]></category><dc:creator><![CDATA[Oluwafemi Obajuluwa]]></dc:creator><pubDate>Mon, 20 Dec 2021 14:43:13 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1640011483042/nMfXzZRxo.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I set out to build one of my <a target="_blank" href="https://picashot.co">favorite projects</a> some time around June, and while I was able to complete it to some extent and successfully launched it, I did face some setbacks while trying to implement certain features in the application. One of the most difficult feature I had to implement was notifications. I spent quite some time trying to figure out how to model this form of data in the database. I am using a relational database (PostgreSQL). The main problem I faced with the notifications model was based on the requirements needed to store notifications in a way that still references certain rows and columns in multiple tables. Here's the explanation in details:</p>
<p>a. In the database, here's a <code>User</code> table that contains columns like <em>id(primary key) name, email, profileUrl</em>, etc</p>
<pre><code><span class="hljs-string">class</span> <span class="hljs-string">User</span> <span class="hljs-string">extends</span> <span class="hljs-string">Model</span> { }

<span class="hljs-string">User.init(</span>
  {
    <span class="hljs-attr">name:</span> {
      <span class="hljs-attr">type:</span> <span class="hljs-string">DataTypes.STRING</span>,
      <span class="hljs-attr">allowNull:</span> <span class="hljs-literal">false</span>,
    },
    <span class="hljs-attr">bio:</span> {
      <span class="hljs-attr">type:</span> <span class="hljs-string">DataTypes.STRING</span>,
      <span class="hljs-attr">allowNull:</span> <span class="hljs-literal">false</span>,
      <span class="hljs-attr">defaultValue:</span> <span class="hljs-string">"Hey there!"</span>
    },
    <span class="hljs-attr">id:</span> {
      <span class="hljs-attr">type:</span> <span class="hljs-string">DataTypes.UUID</span>,
      <span class="hljs-attr">allowNull:</span> <span class="hljs-literal">false</span>,
      <span class="hljs-attr">primaryKey:</span> <span class="hljs-literal">true</span>,
      <span class="hljs-attr">defaultValue:</span> <span class="hljs-string">DataTypes.UUIDV4</span>,
      <span class="hljs-attr">unique:</span> <span class="hljs-literal">true</span>,
    },
    <span class="hljs-attr">username:</span> {
      <span class="hljs-attr">type:</span> <span class="hljs-string">DataTypes.TEXT</span>,
      <span class="hljs-attr">allowNull:</span> <span class="hljs-literal">false</span>,
      <span class="hljs-attr">unique:</span> <span class="hljs-literal">true</span>,
    },
    <span class="hljs-attr">profile_url:</span> {
      <span class="hljs-attr">type:</span> <span class="hljs-string">DataTypes.STRING</span>,
      <span class="hljs-attr">allowNull:</span> <span class="hljs-literal">false</span>,
      <span class="hljs-attr">defaultValue:</span>
        <span class="hljs-string">"https://someimagesite.com/default_image.jpg"</span>,
    },
    <span class="hljs-attr">email:</span> {
      <span class="hljs-attr">type:</span> <span class="hljs-string">DataTypes.TEXT</span>,
      <span class="hljs-attr">allowNull:</span> <span class="hljs-literal">false</span>,
      <span class="hljs-attr">unique:</span> <span class="hljs-literal">true</span>,
    }
  }<span class="hljs-string">,</span>
  {
    <span class="hljs-attr">sequelize:</span> <span class="hljs-string">instance</span>,
    <span class="hljs-attr">modelName:</span> <span class="hljs-string">"users"</span>,
    <span class="hljs-attr">tableName:</span> <span class="hljs-string">"users"</span>,
    <span class="hljs-attr">timestamps:</span> <span class="hljs-literal">true</span>,
    <span class="hljs-attr">createdAt:</span> <span class="hljs-literal">true</span>,
    <span class="hljs-attr">updatedAt:</span> <span class="hljs-literal">true</span>,
  }
<span class="hljs-string">);</span>


<span class="hljs-string">User.hasMany(Post,</span> {
  <span class="hljs-attr">foreignKey:</span> <span class="hljs-string">"userId"</span>,
  <span class="hljs-attr">foreignKeyConstraint:</span> <span class="hljs-literal">true</span>,
  <span class="hljs-attr">constraints:</span> <span class="hljs-literal">true</span>,
  <span class="hljs-attr">onUpdate:</span> <span class="hljs-string">"CASCADE"</span>,
  <span class="hljs-attr">onDelete:</span> <span class="hljs-string">"CASCADE"</span>,
}<span class="hljs-string">);</span>


<span class="hljs-string">User.hasMany(Comment,</span> {
  <span class="hljs-attr">foreignKey:</span> <span class="hljs-string">"userId"</span>,
  <span class="hljs-attr">foreignKeyConstraint:</span> <span class="hljs-literal">true</span>,
  <span class="hljs-attr">constraints:</span> <span class="hljs-literal">true</span>,
  <span class="hljs-attr">onUpdate:</span> <span class="hljs-string">"CASCADE"</span>,
  <span class="hljs-attr">onDelete:</span> <span class="hljs-string">"CASCADE"</span>,
}<span class="hljs-string">);</span>

<span class="hljs-string">Post.belongsTo(User)</span>
<span class="hljs-string">Comment.belongsTo(User)</span>
</code></pre><p>b. Here's a <code>Post</code> table that contains columns like <em>id(primary key), content, title, userId, timestamp</em>. "userId" references a row in the <code>User</code> table and it represents the author of the posts. It has a foreign key constraints set as "onUpdate: CASCASDE" &amp; "onDelete: CASCADE" on the User table which ensures that when a user row is deleted/updated from the users table, any other references to the row in any table gets updated as well. </p>
<pre><code><span class="hljs-string">class</span> <span class="hljs-string">Post</span> <span class="hljs-string">extends</span> <span class="hljs-string">Model</span> { }

<span class="hljs-string">Post.init(</span>
  {
    <span class="hljs-attr">content:</span> {
      <span class="hljs-attr">type:</span> <span class="hljs-string">DataTypes.TEXT</span>,
      <span class="hljs-attr">allowNull:</span> <span class="hljs-literal">false</span>,
    },
    <span class="hljs-attr">id:</span> {
      <span class="hljs-attr">type:</span> <span class="hljs-string">DataTypes.UUID</span>,
      <span class="hljs-attr">allowNull:</span> <span class="hljs-literal">false</span>,
      <span class="hljs-attr">primaryKey:</span> <span class="hljs-literal">true</span>,
      <span class="hljs-attr">defaultValue:</span> <span class="hljs-string">UUIDV4</span>,
      <span class="hljs-attr">unique:</span> <span class="hljs-literal">true</span>,
    },
    <span class="hljs-attr">userId:</span> {
      <span class="hljs-attr">type:</span> <span class="hljs-string">DataTypes.UUID</span>,
      <span class="hljs-attr">allowNull:</span> <span class="hljs-literal">false</span>,
    },
  }<span class="hljs-string">,</span>
  {
    <span class="hljs-attr">sequelize:</span> <span class="hljs-string">instance</span>,
    <span class="hljs-attr">modelName:</span> <span class="hljs-string">"posts"</span>,
    <span class="hljs-attr">tableName:</span> <span class="hljs-string">"posts"</span>,
    <span class="hljs-attr">timestamps:</span> <span class="hljs-literal">true</span>,
    <span class="hljs-attr">createdAt:</span> <span class="hljs-literal">true</span>,
    <span class="hljs-attr">updatedAt:</span> <span class="hljs-literal">true</span>,
  }
<span class="hljs-string">);</span>
</code></pre><p>Now, imagine we need to to display a notification to certain users in the following typical format:
<em>"@echoeyecodes just made a post"</em></p>
<p>In the sample format above, we can see a couple of references to certain attributes of 2 tables in the database.</p>
<ul>
<li>username of user (User table)</li>
<li>post thumbnail (Post table)</li>
<li>description (Post table)</li>
<li>profile photo of user (User Table)</li>
<li>timestamp (Post table)</li>
</ul>
<p>To model this as a table in the database for notifications, we'll need the following columns:</p>
<ul>
<li>postId</li>
<li>userId</li>
<li>targetUserId (recipient of the notification)</li>
</ul>
<pre><code><span class="hljs-string">class</span> <span class="hljs-string">Notification</span> <span class="hljs-string">extends</span> <span class="hljs-string">Model</span> {}

<span class="hljs-string">Notification.init(</span>
  {
    <span class="hljs-attr">id:</span> {
      <span class="hljs-attr">type:</span> <span class="hljs-string">DataTypes.UUID</span>,
      <span class="hljs-attr">allowNull:</span> <span class="hljs-literal">false</span>,
      <span class="hljs-attr">primaryKey:</span> <span class="hljs-literal">true</span>,
      <span class="hljs-attr">defaultValue:</span> <span class="hljs-string">UUIDV4</span>
    },
    <span class="hljs-attr">postId:</span> {
      <span class="hljs-attr">type:</span> <span class="hljs-string">DataTypes.UUID</span>,
      <span class="hljs-attr">allowNull:</span> <span class="hljs-literal">false</span>,
    },
    <span class="hljs-attr">userId:</span> {
      <span class="hljs-attr">type:</span> <span class="hljs-string">DataTypes.UUID</span>,
      <span class="hljs-attr">allowNull:</span> <span class="hljs-literal">false</span>,
    },
    <span class="hljs-attr">targetUserId:</span> {
      <span class="hljs-attr">type:</span> <span class="hljs-string">DataTypes.UUID</span>,
      <span class="hljs-attr">allowNull:</span> <span class="hljs-literal">false</span>,
    },
    <span class="hljs-attr">isRead:</span> {
        <span class="hljs-attr">type:</span> <span class="hljs-string">DataTypes.BOOLEAN</span>,
        <span class="hljs-attr">allowNull:</span> <span class="hljs-literal">false</span>,
        <span class="hljs-attr">defaultValue:</span> <span class="hljs-literal">false</span>
    },
  }<span class="hljs-string">,</span>
  {
    <span class="hljs-attr">sequelize:</span> <span class="hljs-string">instance</span>,
    <span class="hljs-attr">modelName:</span> <span class="hljs-string">"notifications"</span>,
    <span class="hljs-attr">tableName:</span> <span class="hljs-string">"notifications"</span>,
    <span class="hljs-attr">timestamps:</span> <span class="hljs-literal">true</span>,
    <span class="hljs-attr">createdAt:</span> <span class="hljs-literal">true</span>,
    <span class="hljs-attr">updatedAt:</span> <span class="hljs-literal">true</span>,
  }
<span class="hljs-string">);</span>
</code></pre><p>Now to ensure our data here is consistent with the tables it references and avoid null data, we'll add foreign key constraints --&gt; <code>onUpdate: CASCASDE</code> &amp; <code>onDelete: CASCADE</code> to the <code>userId</code>, and <code>postId</code> columns to User and Post table</p>
<p>With this model, we can query for notifications on posts created by a certain user with no issues at all. But the 'gotcha!' in this is that it only works well for post notifications. What about when we need notifications for the following events:</p>
<ul>
<li>a. when a user mentions another user in the content of a post?</li>
<li>b. when a user publishes a comment on someone else's post?</li>
<li>c. when a user mentions another user in a comment/reply</li>
<li>d. when a user likes a post</li>
<li>e. when a user likes a comment/reply</li>
</ul>
<p>If we analyze these events, you'll notice that each event references certain columns in different tables beyond Post and User. We could go ahead and add more attributes like <em>"commentId", "replyId"</em> to our notification model to adjust to the requirements for notifications, but that would make our model contain redundant columns, and make it harder to debug or understand. We would also have more than a few null columns for a row that actually only references at most 2 tables.</p>
<h2 id="heading-how-do-we-solve-this-problem">How do we solve this problem?</h2>
<p>I looked up for a conventional approach for storing notifications in databases, and found some that didn't exactly solve this specific issue, but gave me insights on how to resolve this. I didn't want to create separate tables for different kinds of notifications, especially when these notifications are expected to be arranged in a chronological order. Well, thanks to this <a target="_blank" href="https://stackoverflow.com/a/29439644">stackoverflow answer</a>, I figured that I could have a separate table for notification event-types, e.g (post-likes, comment-likes, post-mentions, comment-mentions etc) and a notification table that holds only generalized attributes for every form of notification. This notification will contain attributes like timestamp, eventId, recepientId since all forms of notification are expected to have these attributes. That was the first step towards the solution. So now we have an events table like:</p>
<pre><code><span class="hljs-string">class</span> <span class="hljs-string">NotificationEvent</span> <span class="hljs-string">extends</span> <span class="hljs-string">Model</span> {}

<span class="hljs-string">NotificationEvent.init(</span>
  {
    <span class="hljs-attr">id:</span> {
      <span class="hljs-attr">type:</span> <span class="hljs-string">DataTypes.INTEGER</span>,
      <span class="hljs-attr">allowNull:</span> <span class="hljs-literal">false</span>,
      <span class="hljs-attr">primaryKey:</span> <span class="hljs-literal">true</span>
    },
    <span class="hljs-attr">type:</span> {
      <span class="hljs-attr">type:</span> <span class="hljs-string">DataTypes.STRING</span>,
      <span class="hljs-attr">allowNull:</span> <span class="hljs-literal">false</span>,
    }
  }<span class="hljs-string">,</span>
  {
    <span class="hljs-attr">sequelize:</span> <span class="hljs-string">instance</span>,
    <span class="hljs-attr">modelName:</span> <span class="hljs-string">"notification_events"</span>,
    <span class="hljs-attr">tableName:</span> <span class="hljs-string">"notification_events"</span>,
    <span class="hljs-attr">timestamps:</span> <span class="hljs-literal">true</span>,
    <span class="hljs-attr">createdAt:</span> <span class="hljs-literal">true</span>,
    <span class="hljs-attr">updatedAt:</span> <span class="hljs-literal">true</span>,
  }
<span class="hljs-string">);</span>


<span class="hljs-string">NotificationEvent.hasMany(Notification,</span> {
    <span class="hljs-attr">foreignKey:</span> <span class="hljs-string">"eventId"</span>,
    <span class="hljs-attr">foreignKeyConstraint:</span> <span class="hljs-literal">true</span>,
    <span class="hljs-attr">constraints:</span> <span class="hljs-literal">true</span>,
    <span class="hljs-attr">onUpdate:</span> <span class="hljs-string">"CASCADE"</span>,
    <span class="hljs-attr">onDelete:</span> <span class="hljs-string">"CASCADE"</span>,
}<span class="hljs-string">)</span>

<span class="hljs-string">Notification.belongsTo(NotificationEvent,</span> {
  <span class="hljs-attr">foreignKey:</span> <span class="hljs-string">"eventId"</span>,
  <span class="hljs-attr">onDelete:</span> <span class="hljs-string">"CASCADE"</span>,
  <span class="hljs-attr">onUpdate:</span> <span class="hljs-string">"CASCADE"</span>,
  <span class="hljs-attr">foreignKeyConstraint:</span> <span class="hljs-literal">true</span>,
  <span class="hljs-attr">constraints:</span> <span class="hljs-literal">true</span>
}<span class="hljs-string">)</span>
</code></pre><p>Then our revamped notification model would look like:</p>
<pre><code><span class="hljs-string">class</span> <span class="hljs-string">Notification</span> <span class="hljs-string">extends</span> <span class="hljs-string">Model</span> {}

<span class="hljs-string">Notification.init(</span>
  {
    <span class="hljs-attr">id:</span> {
      <span class="hljs-attr">type:</span> <span class="hljs-string">DataTypes.UUID</span>,
      <span class="hljs-attr">allowNull:</span> <span class="hljs-literal">false</span>,
      <span class="hljs-attr">primaryKey:</span> <span class="hljs-literal">true</span>,
      <span class="hljs-attr">defaultValue:</span> <span class="hljs-string">UUIDV4</span>
    },
    <span class="hljs-attr">eventId:</span> {
        <span class="hljs-attr">type:</span> <span class="hljs-string">DataTypes.INTEGER</span>,
        <span class="hljs-attr">allowNull:</span> <span class="hljs-literal">false</span>
    },
    <span class="hljs-attr">targetId:</span> {
      <span class="hljs-attr">type:</span> <span class="hljs-string">DataTypes.UUID</span>,
      <span class="hljs-attr">allowNull:</span> <span class="hljs-literal">false</span>,
    },
    <span class="hljs-attr">isRead:</span> {
        <span class="hljs-attr">type:</span> <span class="hljs-string">DataTypes.BOOLEAN</span>,
        <span class="hljs-attr">allowNull:</span> <span class="hljs-literal">false</span>,
        <span class="hljs-attr">defaultValue:</span> <span class="hljs-literal">false</span>
    },
  }<span class="hljs-string">,</span>
  {
    <span class="hljs-attr">sequelize:</span> <span class="hljs-string">instance</span>,
    <span class="hljs-attr">modelName:</span> <span class="hljs-string">"notifications"</span>,
    <span class="hljs-attr">tableName:</span> <span class="hljs-string">"notifications"</span>,
    <span class="hljs-attr">timestamps:</span> <span class="hljs-literal">true</span>,
    <span class="hljs-attr">createdAt:</span> <span class="hljs-literal">true</span>,
    <span class="hljs-attr">updatedAt:</span> <span class="hljs-literal">true</span>,
  }
<span class="hljs-string">);</span>
</code></pre><p>Going back to notification format for various events I listed above, I observed a pattern for each event:</p>
<ol>
<li><p>(a) is a form of notification between a User and a Post table. That is pretty straightforward, so we can have a UserPostNotification table that contains the columns "userId" and "postId".</p>
</li>
<li><p>(b) is a form of notification between a Comment, and a Post table. So the main attributes needed here would be the commentId, and the postId for the PostCommentNotification table. With these columns we can easily construct our notification message by fetching the related data they reference. You know that a comment would always be from a User, therefore it would have a column called "userId" so we could fetch the user information based on this column to get data like username, and profileUrl. Also, every post has a "userId" attribute that references a certain user, so we could also get the user that owns the post based on this attribute and use it as the recipient of the notification.</p>
</li>
</ol>
<p>We can now have something like <em>@username commented on your post</em></p>
<ol>
<li><p>(c) is a form of notification between a User and a Comment table. We can construct our notification message like the image below using only the attributes "userId" and "commentId".</p>
</li>
<li><p>(d) is also a form of notification between a User and a Post table. To get a message like the image below, we can obtain the information using the <code>userId</code> and <code>postId</code> attributes.</p>
</li>
<li><p>(e) is a form of notification between a "userId" and <code>commentId</code> and the message like <code>@echoeyecodes liked your comment</code> could be constructed using these two attributes.</p>
</li>
</ol>
<p>After observing these patterns, I realized I could have a single table for notifications that are between a User &amp; Post, User &amp; Comment, or User &amp; Reply. These tables would have an <code>id</code> attribute as primary key that references a row in the notifications table as a One-To-One Relationship. So to query all notifications in chronological order with the various attributes from different notification types, we could use an INNER JOIN for the <code>Notification</code> table and <code>NotificationEvents</code> Table, plus a LEFT JOIN with the <code>UserPostNotification</code> table, and <code>PostCommentNotification</code> table.</p>
<p>We could also insert an INNER JOIN clause to each of the sub-tables based on the parent tables they share constraints with, without having to re-query for these pieces of information after obtaining the foreignKey attributes since <code>UserPostNotification</code> would have foreign key constraints between a User and Post (<code>userId</code>, <code>postId</code>), <code>PostCommentNotification</code> would have a foreign key constraints between a Post and Comment <code>userId</code>, <code>commentId</code>).</p>
<p>here's how the <code>UserPostNotification</code> would look like:</p>
<pre><code><span class="hljs-string">class</span> <span class="hljs-string">UserPostNotification</span> <span class="hljs-string">extends</span> <span class="hljs-string">Model</span> {}

<span class="hljs-string">UserPostNotification.init(</span>
  {
    <span class="hljs-attr">notificationId:</span> {
      <span class="hljs-attr">type:</span> <span class="hljs-string">DataTypes.UUID</span>,
      <span class="hljs-attr">allowNull:</span> <span class="hljs-literal">false</span>,
      <span class="hljs-attr">primaryKey:</span> <span class="hljs-literal">true</span>,
    },
    <span class="hljs-attr">sourceId:</span> {
      <span class="hljs-attr">type:</span> <span class="hljs-string">DataTypes.UUID</span>,
      <span class="hljs-attr">allowNull:</span> <span class="hljs-literal">false</span>
  },
    <span class="hljs-attr">referenceId:</span> {
        <span class="hljs-attr">type:</span> <span class="hljs-string">DataTypes.UUID</span>,
        <span class="hljs-attr">allowNull:</span> <span class="hljs-literal">false</span>
    },
  }<span class="hljs-string">,</span>
  {
    <span class="hljs-attr">sequelize:</span> <span class="hljs-string">instance</span>,
    <span class="hljs-attr">modelName:</span> <span class="hljs-string">"user_post_notifications"</span>,
    <span class="hljs-attr">tableName:</span> <span class="hljs-string">"user_post_notifications"</span>,
    <span class="hljs-attr">timestamps:</span> <span class="hljs-literal">true</span>,
    <span class="hljs-attr">createdAt:</span> <span class="hljs-literal">true</span>,
    <span class="hljs-attr">updatedAt:</span> <span class="hljs-literal">true</span>,
  }
<span class="hljs-string">);</span>
</code></pre><p>then the <code>PostCommentNotification</code>:</p>
<pre><code><span class="hljs-string">class</span> <span class="hljs-string">PostCommentNotification</span> <span class="hljs-string">extends</span> <span class="hljs-string">Model</span> {}

<span class="hljs-string">PostCommentNotification.init(</span>
  {
    <span class="hljs-attr">notificationId:</span> {
      <span class="hljs-attr">type:</span> <span class="hljs-string">DataTypes.UUID</span>,
      <span class="hljs-attr">allowNull:</span> <span class="hljs-literal">false</span>,
      <span class="hljs-attr">primaryKey:</span> <span class="hljs-literal">true</span>,
    },
    <span class="hljs-attr">sourceId:</span> {
      <span class="hljs-attr">type:</span> <span class="hljs-string">DataTypes.UUID</span>,
      <span class="hljs-attr">allowNull:</span> <span class="hljs-literal">false</span>
  },
    <span class="hljs-attr">referenceId:</span> {
        <span class="hljs-attr">type:</span> <span class="hljs-string">DataTypes.UUID</span>,
        <span class="hljs-attr">allowNull:</span> <span class="hljs-literal">false</span>
    },
  }<span class="hljs-string">,</span>
  {
    <span class="hljs-attr">sequelize:</span> <span class="hljs-string">instance</span>,
    <span class="hljs-attr">modelName:</span> <span class="hljs-string">"post_comment_notifications"</span>,
    <span class="hljs-attr">tableName:</span> <span class="hljs-string">"post_comment_notifications"</span>,
    <span class="hljs-attr">timestamps:</span> <span class="hljs-literal">true</span>,
    <span class="hljs-attr">createdAt:</span> <span class="hljs-literal">true</span>,
    <span class="hljs-attr">updatedAt:</span> <span class="hljs-literal">true</span>,
  }
<span class="hljs-string">);</span>
</code></pre><p>Now to query for all notifications available for a particular user, we would query via the notification table and use a left join for various notification types available like:</p>
<pre><code><span class="hljs-keyword">const</span> NOTIFICATION_INCLUDE_OPTIONS : IncludeOptions[] = [{model: User, required: <span class="hljs-literal">true</span>},
    {model: NotificationEvent, required: <span class="hljs-literal">true</span>},
    {model: UserPostNotification, include: [{model: User}]},{model: PostCommentNotification, include: [{model: User}, {model: Comment, include: [{model: User}]}]}]


<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getUserNotifications</span>(<span class="hljs-params">userId:<span class="hljs-built_in">string</span>(){
   <span class="hljs-keyword">const</span> result = <span class="hljs-keyword">await</span> <span class="hljs-built_in">Promise</span>.all((<span class="hljs-keyword">await</span> Notification.findAll({include: NOTIFICATION_INCLUDE_OPTIONS, where:{targetId: userId}}))
        .filter((item) =&gt; {
//here we filter off notifications <span class="hljs-keyword">with</span> possible all notification <span class="hljs-keyword">type</span> <span class="hljs-keyword">as</span> <span class="hljs-literal">null</span>. <span class="hljs-built_in">this</span> kind <span class="hljs-keyword">of</span> state cannot possibly exist since every notification <span class="hljs-built_in">object</span> would be <span class="hljs-keyword">of</span> at least one <span class="hljs-keyword">type</span>, but just to be safe, we need <span class="hljs-built_in">this</span> check
            <span class="hljs-keyword">const</span> result = item.get({plain: <span class="hljs-literal">true</span>}) <span class="hljs-keyword">as</span> NotificationType
            <span class="hljs-keyword">if</span>(!result.user_post_notification &amp;&amp; !result.post_comment_notification){
                <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>
            }
            <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>
        })
        .map((item) =&gt; formatNotification(item.get({plain: <span class="hljs-literal">true</span>}))))
        <span class="hljs-keyword">return</span> result
}</span></span>
</code></pre><p>Finally, we can write a small utility function that constructs the notification message based on the event type for every notification like the one below:</p>
<pre><code>async <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">formatNotification</span>(<span class="hljs-params">instance:NotificationType</span>)</span>{
    const <span class="hljs-keyword">type</span> <span class="hljs-operator">=</span> instance.notification_event.type <span class="hljs-keyword">as</span> NotificationEventType

   <span class="hljs-keyword">if</span>(<span class="hljs-keyword">type</span> <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-string">"post_comment"</span>){
     <span class="hljs-comment">//format notification based on requirements e.g @echoeyecodes commented on your post</span>
   }<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(<span class="hljs-keyword">type</span> <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-string">"post_create"</span>){
     <span class="hljs-comment">//format notification based on requirements e.g @echoeyecodes uploaded a photo</span>
}
}
</code></pre>]]></content:encoded></item><item><title><![CDATA[Replies are... well, comments too!]]></title><description><![CDATA[Last week, I did a bit of refactoring on Picashot's web service, and went through a rethink of how to store comments and replies in the database. I initially had 2 tables for this, a Comment table and Reply table. These tables had very similar column...]]></description><link>https://blog.echoeyecodes.com/replies-are-well-comments-too</link><guid isPermaLink="true">https://blog.echoeyecodes.com/replies-are-well-comments-too</guid><category><![CDATA[database]]></category><category><![CDATA[coding]]></category><category><![CDATA[services]]></category><category><![CDATA[TypeScript]]></category><category><![CDATA[learning]]></category><dc:creator><![CDATA[Oluwafemi Obajuluwa]]></dc:creator><pubDate>Mon, 13 Dec 2021 13:30:46 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1639391099220/C_uppXQoo.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Last week, I did a bit of refactoring on <a target="_blank" href="https://picashot.co">Picashot's web service</a>, and went through a rethink of how to store comments and replies in the database. I initially had 2 tables for this, a <code>Comment</code> table and <code>Reply</code> table. These tables had very similar columns, and the only thing that made them distinct in any way was that the <code>Comment</code> table had a <code>comment</code> column that holds the actual text of the comment, while the <code>Reply</code> table had a <code>reply</code> column for the reply text, and a <code>columnID</code> column that references the comment row it replies to.
Here's how the <code>Comment</code> model looks like:</p>
<pre><code><span class="hljs-string">class</span> <span class="hljs-string">Comment</span> <span class="hljs-string">extends</span> <span class="hljs-string">Model</span> { }

<span class="hljs-string">Comment.init(</span>
  {
    <span class="hljs-attr">userId:</span> {
      <span class="hljs-attr">type:</span> <span class="hljs-string">DataTypes.UUID</span>,
      <span class="hljs-attr">allowNull:</span> <span class="hljs-literal">false</span>,
    },
    <span class="hljs-attr">id:</span> {
      <span class="hljs-attr">type:</span> <span class="hljs-string">DataTypes.UUID</span>,
      <span class="hljs-attr">allowNull:</span> <span class="hljs-literal">false</span>,
      <span class="hljs-attr">primaryKey:</span> <span class="hljs-literal">true</span>,
      <span class="hljs-attr">unique:</span> <span class="hljs-literal">true</span>,
    },
    <span class="hljs-attr">comment:</span> {
      <span class="hljs-attr">type:</span> <span class="hljs-string">DataTypes.TEXT</span>,
      <span class="hljs-attr">allowNull:</span> <span class="hljs-literal">false</span>,
    },
    <span class="hljs-attr">postId:</span> {
      <span class="hljs-attr">type:</span> <span class="hljs-string">DataTypes.UUID</span>,
      <span class="hljs-attr">allowNull:</span> <span class="hljs-literal">false</span>,
    },
  }<span class="hljs-string">,</span>
  {
    <span class="hljs-attr">sequelize:</span> <span class="hljs-string">instance</span>,
    <span class="hljs-attr">modelName:</span> <span class="hljs-string">"comments"</span>,
    <span class="hljs-attr">tableName:</span> <span class="hljs-string">"comments"</span>,
    <span class="hljs-attr">timestamps:</span> <span class="hljs-literal">true</span>,
    <span class="hljs-attr">createdAt:</span> <span class="hljs-literal">true</span>,
    <span class="hljs-attr">updatedAt:</span> <span class="hljs-literal">true</span>,
  }
<span class="hljs-string">);</span>
</code></pre><p>and now the <code>Reply</code> model:</p>
<pre><code><span class="hljs-string">class</span> <span class="hljs-string">Reply</span> <span class="hljs-string">extends</span> <span class="hljs-string">Model</span> {}

<span class="hljs-string">Reply.init(</span>
  {
    <span class="hljs-attr">userId:</span> {
      <span class="hljs-attr">type:</span> <span class="hljs-string">DataTypes.UUID</span>,
      <span class="hljs-attr">allowNull:</span> <span class="hljs-literal">false</span>,
    },
    <span class="hljs-attr">id:</span> {
      <span class="hljs-attr">type:</span> <span class="hljs-string">DataTypes.UUID</span>,
      <span class="hljs-attr">allowNull:</span> <span class="hljs-literal">false</span>,
      <span class="hljs-attr">primaryKey:</span> <span class="hljs-literal">true</span>,
      <span class="hljs-attr">unique:</span> <span class="hljs-literal">true</span>,
    },
    <span class="hljs-attr">reply:</span> {
      <span class="hljs-attr">type:</span> <span class="hljs-string">DataTypes.TEXT</span>,
      <span class="hljs-attr">allowNull:</span> <span class="hljs-literal">false</span>,
    },
    <span class="hljs-attr">commentId:</span> {
        <span class="hljs-attr">type:</span> <span class="hljs-string">DataTypes.UUID</span>,
        <span class="hljs-attr">allowNull:</span> <span class="hljs-literal">false</span>,
      },
  }<span class="hljs-string">,</span>
  {
    <span class="hljs-attr">sequelize:</span> <span class="hljs-string">instance</span>,
    <span class="hljs-attr">modelName:</span> <span class="hljs-string">"replies"</span>,
    <span class="hljs-attr">tableName:</span> <span class="hljs-string">"replies"</span>,
    <span class="hljs-attr">timestamps:</span> <span class="hljs-literal">true</span>,
    <span class="hljs-attr">createdAt:</span> <span class="hljs-literal">true</span>,
    <span class="hljs-attr">updatedAt:</span> <span class="hljs-literal">true</span>,
  }
<span class="hljs-string">);</span>
</code></pre><p>What's even more wild is that I had two controllers that performed the same read/write operations for both tables and really wasn't comfortable with how this was designed. Besides the regular controllers for the table, there was a <code>CommentLike</code> model that stores comments liked by users using the <code>commentId</code> and <code>userId</code> column, however this table was only meant for the Comment table. Replies could not be liked, or even replied to because of the rigid design nature I adopted for it months back🤮. The final bit of crazy was where I had two notification models for both tables, <code>CommentNotification</code> and <code>ReplyNotification</code>, each referencing rows in both Comment and Reply table. Yes, this also means writing different controller classes that literally did the same thing, besides a few columns that were distinct🤦</p>
<p>I finally decided to rethink this design approach, and I think what really helped me out here was the way tweets work on twitter. I spent some time using the twitter api for evaluating tweet acitivities, and noticed how tweet response are usually structured. Essentially every comment, or quote made on twitter is a tweet, which means they all have the same common attributes (columns) that describes them. What could probably distinguish a tweet from another is if one tweet is a standalone tweet, or a reply to another tweet, but generally they are all a single entity - A Tweet</p>
<p>Having this in mind, I realized that every reply to a comment is still essentially a comment, so I could actually store all replies within the comments table. But how would I be able to distinguish a standalone comment from a reply to a comment, since querying for all comments related to a particular post would include the standalone comments and replies, which isn't what we want? For this, I created a junction table called <code>CommentReply</code> with two columns commentId, and referenceId like this:</p>
<pre><code><span class="hljs-string">class</span> <span class="hljs-string">CommentReply</span> <span class="hljs-string">extends</span> <span class="hljs-string">Model</span> { }
<span class="hljs-string">CommentReply.init(</span>
    {
        <span class="hljs-attr">commentId:</span> {
            <span class="hljs-attr">type:</span> <span class="hljs-string">DataTypes.UUID</span>,
            <span class="hljs-attr">allowNull:</span> <span class="hljs-literal">false</span>,
            <span class="hljs-attr">primaryKey:</span> <span class="hljs-literal">true</span>,
            <span class="hljs-attr">unique:</span> <span class="hljs-literal">true</span>,
        },
        <span class="hljs-attr">referenceId:</span> {
            <span class="hljs-attr">type:</span> <span class="hljs-string">DataTypes.UUID</span>,
            <span class="hljs-attr">allowNull:</span> <span class="hljs-literal">true</span>,
        },
    }<span class="hljs-string">,</span>
    {
        <span class="hljs-attr">sequelize:</span> <span class="hljs-string">instance</span>,
        <span class="hljs-attr">modelName:</span> <span class="hljs-string">"comment_replies"</span>,
        <span class="hljs-attr">tableName:</span> <span class="hljs-string">"comment_replies"</span>,
        <span class="hljs-attr">timestamps:</span> <span class="hljs-literal">true</span>,
        <span class="hljs-attr">createdAt:</span> <span class="hljs-literal">true</span>,
        <span class="hljs-attr">updatedAt:</span> <span class="hljs-literal">true</span>,
    }
<span class="hljs-string">);</span>
</code></pre><p>The <code>commentId</code> column references the comment that is supposed to be a reply, while the <code>referenceId</code> column references the comment being replied to. So, whenever a reply is made to a certain comment, the reply is stored in the database as a comment, and the <code>id</code> of this comment (reply) along, with the <code>id</code> of the comment that's being replied to is stored in a CommentReply.</p>
<p>Now how do I query for comments that are originally standalone comments, not replies. The idea is to query for every comment within the database, and perform a left join with the <code>CommentReply</code> table.  A "left join" would include null columns in the query results for comments that do not have references in the <code>commentId</code> column of the <code>CommentReply</code> table. So rows with null <code>commentId</code> column represents original standalone comments, while the non-null <code>columnID</code> rows are replies. So based on this ideology, we can query for standalone comments, or just comments that are replies to a certain comment  Here's how I performed the query in the comment controller class:</p>
<pre><code>  async getComments({ postId, <span class="hljs-keyword">limit</span>, <span class="hljs-keyword">offset</span>, userId, commentId }: GetShotParams &amp; { shotId: string, commentId: string | <span class="hljs-keyword">null</span> }) {

    <span class="hljs-comment">/* if query contains commentId, fetch all comments referenced by that id
    else, fetch comments that do not have a row in the replies. Note that: Standalone
    comment ids can never have a row in the columnId for commentReplies, but references so this works!
    */</span>

    const <span class="hljs-keyword">where</span>: WhereOptions = commentId ? { shotId, <span class="hljs-string">'$comment_reply."referenceId"$'</span>: commentId } : { postId, <span class="hljs-string">'$comment_reply."commentId"$'</span>: <span class="hljs-keyword">null</span> }

    const comments = (await <span class="hljs-keyword">Comment</span>.findAll({ <span class="hljs-keyword">where</span>, <span class="hljs-keyword">order</span>: [[<span class="hljs-string">'createdAt'</span>, "DESC"]], <span class="hljs-keyword">limit</span>, <span class="hljs-keyword">offset</span>, <span class="hljs-keyword">include</span>: COMMENT_INCLUDE_OPTIONS }))
    <span class="hljs-keyword">return</span> comments
  }
</code></pre><p>What makes this even better is that replies also get to have likes, or even nested replies just like "original comments" which wasn't available in the first design. This recursive sequence just keeps going on and on without adding an extra line of code to the controller, making it more flexible than the initial approach.</p>
<p>After implementing this, I was able to migrate every reply from the <code>Reply</code> table to the <code>Comment</code> table, and severe all ties to it😁 Now, I get to delete the reply table, its controllers, and including the notification model that is associated with this table. Damnn that's really a lot of code😵 I think the best part of refactoring code is where you get to delete a number of lines of code that really are just garbage😅</p>
]]></content:encoded></item><item><title><![CDATA[Creating uneven grids with FlexboxLayoutManager  on android]]></title><description><![CDATA[I was looking through the DeviantArt android application for features I could implement in my latest project that could be useful to have in the mobile application, and came across this layout format I liked a lot. As you can see in the image below, ...]]></description><link>https://blog.echoeyecodes.com/creating-uneven-grid-layout-with-flexboxlayoutmanager-on-android</link><guid isPermaLink="true">https://blog.echoeyecodes.com/creating-uneven-grid-layout-with-flexboxlayoutmanager-on-android</guid><category><![CDATA[Android]]></category><category><![CDATA[Kotlin]]></category><category><![CDATA[Tutorial]]></category><dc:creator><![CDATA[Oluwafemi Obajuluwa]]></dc:creator><pubDate>Mon, 06 Dec 2021 12:05:29 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1638792222118/dehssrFhA.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I was looking through the DeviantArt android application for features I could implement in my <a target="_blank" href="https://picashot.co/">latest project</a> that could be useful to have in the mobile application, and came across this layout format I liked a lot. As you can see in the image below, the images are arranged in a grid-like form, but each image has different sizes based on their aspect ratio.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h61v5gxmyxsvahmonbb9.png" alt="Deviantart application screenshot" /></p>
<p>I initially tried using a workaround with the GridLayoutManager android provides, but that didn't work as expected because this layout wouldn't allow feed items to fill up extra spaces that might be available during positioning.</p>
<p>Turns out the answer was in the FlexboxLayoutManager - A layout manager based off of CSS' flex box. I've used this quite a number of times for basic layout, especially the "wrap" feature, but never had a use case for something specific like DeviantArt's. I set out to implement this layout manager, but of course it didn't come off as easy as I thought it would. The problem I had at first was that I couldn't control the maximum number of columns that should be displayed on a single row before wrapping, so all hundreds of images were arranged on a single row. Crazy right?😅</p>
<p>Anyway I did a bit of research here and there for how to achieve this form of layout in CSS Flexbox since the layout manager is based on this. A few minutes later, I came across this post on <a target="_blank" href="https://stackoverflow.com/a/50592638/9781233">stackoverflow</a> about setting the min-width and max-width of each flex item, then allowing the default behavior of these flex items to fill up remaining space with the flex-grow property set to 1. I applied this concept on the FlexboxLayoutManager in android, and I'm glad I was able to finally achieve the same results with DeviantArt😄</p>
<p>Here's how I implemented it on android; since the sizes of the various images to be rendered is based on the aspect ratio, I would return 3 different view-types based on this faactor. The viewTypes are PORTRAIT, LANDSCAPE, and SQUARE. So in the <code>getItemViewType()</code> method of the RecyclerView adapter, this check is performed to determine the view type to be used as here:</p>
<pre><code><span class="hljs-keyword">override</span> fun getItemViewType(position: Int): Int {
        val item <span class="hljs-operator">=</span> getItem(position)
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">if</span> (item.width <span class="hljs-operator">&gt;</span> item.height) {
            LANDSCAPE
        } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (item.width <span class="hljs-operator">&lt;</span> item.height) {
            PORTRAIT
        } <span class="hljs-keyword">else</span> {
            SQUARE
        }
    }
</code></pre><p>Now that this is available, the minimum and maximum possible width and height would be determined in the <code>onCreateViewHolder()</code> and these values would be different based on the view types:</p>
<pre><code>    <span class="hljs-keyword">override</span> fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ShotFlexAdapterViewHolder {
val screenWidth <span class="hljs-operator">=</span> getScreenSize().width

        val <span class="hljs-keyword">view</span> <span class="hljs-operator">=</span> LayoutInflater.from(parent.context)
            .inflate(R.layout.layout_shot_list_item, parent, <span class="hljs-literal">false</span>)

        <span class="hljs-keyword">if</span> (viewType <span class="hljs-operator">=</span><span class="hljs-operator">=</span> PORTRAIT) {
            val maximumWidth <span class="hljs-operator">=</span> (<span class="hljs-number">0</span><span class="hljs-number">.5</span> <span class="hljs-operator">*</span> screenWidth).toInt()
            val minimumWidth <span class="hljs-operator">=</span> (<span class="hljs-number">0</span><span class="hljs-number">.3</span> <span class="hljs-operator">*</span> screenWidth).toInt()
            val minimumHeight <span class="hljs-operator">=</span> (<span class="hljs-number">0</span><span class="hljs-number">.5</span> <span class="hljs-operator">*</span> screenWidth).toInt()
            val maximumHeight <span class="hljs-operator">=</span> (<span class="hljs-number">0</span><span class="hljs-number">.6</span> <span class="hljs-operator">*</span> screenWidth).toInt()

            <span class="hljs-keyword">view</span>.updateViewLayoutParams(minimumWidth, maximumWidth, minimumHeight, maximumHeight)
        } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (viewType <span class="hljs-operator">=</span><span class="hljs-operator">=</span> LANDSCAPE) {
            val maximumWidth <span class="hljs-operator">=</span> screenWidth.toInt()
            val minimumWidth <span class="hljs-operator">=</span> (<span class="hljs-number">0</span><span class="hljs-number">.55</span> <span class="hljs-operator">*</span> screenWidth).toInt()
            val minimumHeight <span class="hljs-operator">=</span> (<span class="hljs-number">0</span><span class="hljs-number">.5</span> <span class="hljs-operator">*</span> screenWidth).toInt()
            val maximumHeight <span class="hljs-operator">=</span> (<span class="hljs-number">0</span><span class="hljs-number">.55</span> <span class="hljs-operator">*</span> screenWidth).toInt()

            <span class="hljs-keyword">view</span>.updateViewLayoutParams(minimumWidth, maximumWidth, minimumHeight, maximumHeight)
        } <span class="hljs-keyword">else</span> {
            val maximumWidth <span class="hljs-operator">=</span> (<span class="hljs-number">0</span><span class="hljs-number">.7</span> <span class="hljs-operator">*</span> screenWidth).toInt()
            val minimumWidth <span class="hljs-operator">=</span> (<span class="hljs-number">0</span><span class="hljs-number">.4</span> <span class="hljs-operator">*</span> screenWidth).toInt()
            val minimumHeight <span class="hljs-operator">=</span> (<span class="hljs-number">0</span><span class="hljs-number">.4</span> <span class="hljs-operator">*</span> screenWidth).toInt()
            val maximumHeight <span class="hljs-operator">=</span> (<span class="hljs-number">0</span><span class="hljs-number">.7</span> <span class="hljs-operator">*</span> screenWidth).toInt()

            <span class="hljs-keyword">view</span>.updateViewLayoutParams(minimumWidth, maximumWidth, minimumHeight, maximumHeight)
        }

        <span class="hljs-keyword">return</span> ShotFlexAdapterViewHolder(<span class="hljs-keyword">view</span>)
    }
</code></pre><p>Now the extension function that updates the width and height properties:</p>
<pre><code><span class="hljs-keyword">private</span> fun View.updateViewLayoutParams(
        minimumWidth: Int,
        maximumWidth: Int,
        minimumHeight: Int,
        maximumHeight: Int
    ) {
        (<span class="hljs-built_in">this</span>.layoutParams <span class="hljs-keyword">as</span> FlexboxLayoutManager.LayoutParams).apply {
            flexGrow <span class="hljs-operator">=</span> 1f
            <span class="hljs-built_in">this</span>.width <span class="hljs-operator">=</span> minimumWidth
            <span class="hljs-built_in">this</span>.height <span class="hljs-operator">=</span> minimumHeight
            <span class="hljs-built_in">this</span>.maxWidth <span class="hljs-operator">=</span> maximumWidth
            <span class="hljs-built_in">this</span>.minWidth <span class="hljs-operator">=</span> minimumWidth
            <span class="hljs-built_in">this</span>.minHeight <span class="hljs-operator">=</span> minimumHeight
            <span class="hljs-built_in">this</span>.maxHeight <span class="hljs-operator">=</span> maximumHeight
        }
    }
</code></pre><p>Here's an explanation of what is going on above. In order not to overcrop the images that would be displayed, the container width and height holding this image should match the view types i.e portrait images should have a container height greater than the container width, landscape images should have a container width greater than the container height, and square images should have container width and height of equal sizes so that the images to be displayed fits almost* perfectly with the container, and not overcropped.</p>
<p>Now on top the <code>onCreateViewHolder()</code>. For portrait images, the container is assigned a minimum width 30% the screen width, complemented with a minimum height of half of the screen width, which is slightly higher than the minimum width. This would be a particularly useful for scenarios that allows a maximum of 3 portrait images to be rendered on a single row before wrapping. Now imagine we've got a portrait image and a landscape image competing for space on a row. Obviously the landscape image would need more width size than the portrait (say 50% of the screen width), and that means lesser spaces would be left for other images.</p>
<p>For this to work in this case, we can only have a maximum of 1 landscape photo, and the remaining 50% of the screen width would be left to be shared amongst other images. Remember we initially, we defined the minimum width of portrait images to be 30% of the screen width, which means only a maximum of 1 photo can go along with a landscape photo on the same row. The remaining 20% would be shared between these two images since we set the 'flex-grow' property of every item to be 1, i.e stretch to fill the remaining space.</p>
<p>This analogy would also be applied in cases for landscape and square images. The key lies within using the min/max width and height properties to properly configure how much space each item can be allowed to have on a single row based on their aspect ratio, before wrapping subsequent images to the next row. The min width determines the smallest possible width an item can have on a row, while the maximum width determines the maximum possible width an item should have when stretching, regardless of how much space is left on the row. I hope you find this explanation useful. I'm still recovering from the 'eureka' moment I had after I discovered this layout approach😅 and here's what it looks like on the app</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lwodjk27somunxnhkz68.png" alt="Picashot Screenshot" /></p>
]]></content:encoded></item><item><title><![CDATA[Arrays -> as pointers and expressions]]></title><description><![CDATA[Whenever we need to define an object that holds a series of other objects, the basic data type for this would be an array or vector. The contents of an array/vector should be of the same data type, meaning we can’t have an array of both integers and ...]]></description><link>https://blog.echoeyecodes.com/arrays-greater-as-pointers-and-expressions</link><guid isPermaLink="true">https://blog.echoeyecodes.com/arrays-greater-as-pointers-and-expressions</guid><category><![CDATA[C++]]></category><category><![CDATA[Game Development]]></category><category><![CDATA[gaming]]></category><dc:creator><![CDATA[Oluwafemi Obajuluwa]]></dc:creator><pubDate>Tue, 30 Mar 2021 10:39:42 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1617098995721/e6iJohCxd.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Whenever we need to define an object that holds a series of other objects, the basic data type for this would be an array or vector. The contents of an array/vector should be of the same data type, meaning we can’t have an array of both integers and booleans, or an array of strings, and long. An example for defining an array of scores would be:</p>
<pre><code><span class="hljs-attribute">int</span> scores[] = {<span class="hljs-number">0</span>,<span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-number">3</span>,<span class="hljs-number">4</span>,<span class="hljs-number">5</span>,<span class="hljs-number">2</span>,<span class="hljs-number">1</span>,<span class="hljs-number">5</span>,<span class="hljs-number">6</span>};
</code></pre><p>Here, scores is an array object holding 10 integer objects. In terms of memory, there are a couple of other things to know about this array. Typically, an int has a size of 4 bytes within the memory. scores is an array of 10 integers. This means that the score object has a total size of 4 * no_of_items in container -&gt; (4 * 10 ) = 40 bytes. In memory, this scores object would occupy a space of 40 bytes. An array of 2 integers would have a memory size of 4bytes * 2 = 8 bytes.</p>
<p>When you need to access one of the objects within the array, we can use a subscript operator “[]” to achieve this. The subscript operator takes in an integer, which represents the position of the object within the array. The initial position of any element within the array has a position of 0, meaning to access the 4th element in an array, the position would be 3. An example:</p>
<pre><code><span class="hljs-type">int</span> scores = {<span class="hljs-number">15</span>,<span class="hljs-number">33</span>,<span class="hljs-number">69</span>,<span class="hljs-number">87</span>,<span class="hljs-number">125</span>};
//<span class="hljs-keyword">to</span> <span class="hljs-keyword">access</span> the <span class="hljs-number">125</span>, we would use the position at <span class="hljs-keyword">where</span> <span class="hljs-number">125</span> lies <span class="hljs-keyword">in</span> the <span class="hljs-keyword">array</span>
<span class="hljs-type">int</span> <span class="hljs-keyword">value</span> = scores[<span class="hljs-number">4</span>]; // <span class="hljs-keyword">value</span> <span class="hljs-keyword">is</span> now <span class="hljs-number">125</span>
</code></pre><p>But what happens when we refer to an array position that is beyond the size of this array, say 7? We would expect an error to occur, or the program to crash (ArrayIndexOfOutBoundsException). The truth is this might not happen. Imagine we tried printing out the element of the scores array at position 7(Remember that this position does not exist since score has a size of 6), it is very likely we would get a value returned, but this value actually refers to a different kind of thing within the memory. An example:</p>
<pre><code><span class="hljs-keyword">int</span> <span class="hljs-built_in">list</span>[] = {<span class="hljs-number">10</span>,<span class="hljs-number">24</span>,<span class="hljs-number">56</span>};
<span class="hljs-built_in">cout</span> &lt;&lt; <span class="hljs-built_in">list</span>[<span class="hljs-number">4</span>] &lt;&lt;<span class="hljs-built_in">endl</span>; <span class="hljs-comment">//print the 5th item in the array. (-45752158 was my result on my computer)</span>
</code></pre><p>The fifth item here does not exist, but we could get a random value of something else. We can understand why this happens if we look at this at a memory point of view. Recall that an int has a size of 4bytes, and an array of ints would have a size equal to the size of each items(4 bytes) multiplied by the total number of items in the array. These items in the array occupy addresses in memory next to each other.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1617099095405/1KX3j9W81.png" alt="Presentation1.png" /></p>
<p>So basically, the array object spans from the first container element address, to the last container element address in memory. There could be an object elsewhere within the program that occupies the memory address just immediately after the end of the array, so when we use a subscript value greater than the size of an array to get an element, it is likely we get a reference to another object in memory that we totally have no idea about.</p>
<h2 id="arrays-and-expressions">Arrays and expressions.</h2>
<p>Consider an example where we have an array of characters,</p>
<pre><code><span class="hljs-type">char</span> <span class="hljs-keyword">values</span>[] = {‘A’, ‘B’, ‘C’};
</code></pre><p>Any time we try to use the values object to do some form of operation, rather than getting the object itself, we would get a pointer to the first element within the array. So, values here is basically a pointer to ‘A’, not the entire array. It wouldn’t make sense when we pass entire arrays as values or parameters in a program, because these kinds of objects usually hold a list of other objects, sometimes this list can be fairly large and using the list as a whole anywhere in our program could lead to a huge amount of memory usage. With this idea, now would be a good time to explain what really happens when we subscript an array.</p>
<pre><code><span class="hljs-type">char</span> <span class="hljs-keyword">values</span>[] = {‘A’, ‘B’, ‘C’};
<span class="hljs-type">char</span> oneValue = <span class="hljs-keyword">values</span>[<span class="hljs-number">1</span>]; //oneValue now holds ‘B’
</code></pre><p>Remember, using the values object is usually a pointer to the first element within an array, so here’s a breakdown of what happens with this operation.</p>
<pre><code><span class="hljs-type">char</span>* <span class="hljs-keyword">temp</span> = <span class="hljs-keyword">values</span> + <span class="hljs-number">1</span>; // <span class="hljs-keyword">values</span> <span class="hljs-keyword">is</span> a pointer, adding one advances the pointer <span class="hljs-keyword">by</span> one space. <span class="hljs-keyword">temp</span> <span class="hljs-keyword">is</span> now a pointer <span class="hljs-keyword">to</span> the next <span class="hljs-keyword">value</span> <span class="hljs-keyword">of</span> the <span class="hljs-keyword">array</span>.
<span class="hljs-type">char</span> oneValue = *<span class="hljs-keyword">temp</span>; //dereferencing the pointer yields the <span class="hljs-keyword">value</span> <span class="hljs-keyword">in</span> that <span class="hljs-keyword">array</span>
</code></pre><p>Essentially, subscripting an array usually means advancing the pointer of the first element in the array by a number of ‘n’ spaces, which is later dereferenced and yields the value the pointer points to.</p>
<p>This same thing happens when we pass an array as a parameter to a function. Suppose we have a function that adds two numbers x, y together. We would write this as:</p>
<pre><code><span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">addNumbers</span><span class="hljs-params">(<span class="hljs-keyword">int</span> x, <span class="hljs-keyword">int</span> y)</span></span>{
    <span class="hljs-built_in">cout</span> &lt;&lt; (x+y) &lt;&lt;<span class="hljs-built_in">endl</span>;
}

<span class="hljs-keyword">int</span> value1 = <span class="hljs-number">4</span>;
<span class="hljs-keyword">int</span> value2 = <span class="hljs-number">7</span>;
addNumbers(value1,value2); <span class="hljs-comment">//calling add numbers passes copies of x and y into the function</span>
</code></pre><p>But with functions that accept arrays as a parameters, thing work a little different from usual. Imagine we need this function in our program to return an item at a particular index in an array;</p>
<pre><code><span class="hljs-type">int</span> doStuff(<span class="hljs-type">int</span> someValues[], <span class="hljs-type">int</span> <span class="hljs-keyword">index</span>){
    <span class="hljs-keyword">return</span> someValues[<span class="hljs-keyword">index</span>];
}
</code></pre><p>This would still work, but not in the way we expect because, <code>someValues</code> won’t be an array. Rather, it would be a pointer to the first element of the array passed to it. Then subscripting the pointer with an index would just advance the pointer by a number of spaces based on the value of the index. Which means we could just rewrite our function as;</p>
<pre><code><span class="hljs-type">int</span> doStuff(<span class="hljs-type">int</span>* someValues, <span class="hljs-type">int</span> <span class="hljs-keyword">index</span>){
    <span class="hljs-keyword">return</span> someValues[<span class="hljs-keyword">index</span>];
}
</code></pre><p>This approach is more efficient because rather than copying the whole array into another function that executes on top of the stack, we just get something that points to the first element, and we could advance the pointer by the desired amount of space needed.</p>
<p>If we need a function that loops through an array and prints all the values in it, we can just pass the pointer of the first element to the array, along with the size of the array to run the loop efficiently. Since there isn’t a member function for getting the size of an array, we can do this through diving the total memory size of the array by the memory suize of one element in that array. We can get the memory size of an object by calling the <code>sizeof()</code> function on that object. An example would be:</p>
<pre><code><span class="hljs-comment">// function that prints all items in the array</span>
<span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">doStuff</span><span class="hljs-params">(<span class="hljs-keyword">int</span>* someValues, <span class="hljs-keyword">int</span> size)</span></span>{
    <span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i&lt;size; ++i){
    <span class="hljs-built_in">cout</span> &lt;&lt; someValues[i] &lt;&lt; <span class="hljs-built_in">endl</span>;
}
}

<span class="hljs-keyword">int</span> scores[] = {<span class="hljs-number">0</span>,<span class="hljs-number">2</span>,<span class="hljs-number">3</span>,<span class="hljs-number">5</span>,<span class="hljs-number">5</span>}; <span class="hljs-comment">//an array of ints, each int has a size of 4 bytes</span>
<span class="hljs-keyword">int</span> sMemorySize = <span class="hljs-keyword">sizeof</span>(scores); <span class="hljs-comment">// size is 20 bytes</span>
<span class="hljs-keyword">int</span> pSize = <span class="hljs-keyword">sizeof</span>(scores[<span class="hljs-number">0</span>]); <span class="hljs-comment">// we get the size of one element within the array, which yields 4 bytes</span>
<span class="hljs-keyword">int</span> size = sMemorySize/pSize; <span class="hljs-comment">// this would be (20/5) which yields 5</span>
doStuff(scores, size);
</code></pre><h2 id="interesting-stuff-this-week">Interesting stuff this week:</h2>
<ol>
<li><p>I couldn’t help it, so I had to go check up on what to expect from Unreal Engine. I took a brief look at some of the code syntax with C++ on the engine, because I learned that the C++ paradigm with Unreal is a bit different from vanilla C++. One of the differences being that multidimensional arrays can’t be used on the engine. I’m guessing we would use other container elements, like vectors that can contain other container elements, but I wouldn’t be surprised if I get hit with a caveat that says, “This isn’t considered as a best practice when working with the engine” lol.</p>
</li>
<li><p>Speaking of best practices, I worked on a couple of <a target="_blank" href="https://github.com/echoeyecodes/cpp-practice/blob/main/map-filter-reduce.cpp">utility functions</a> with C++ (map, flat, reduce, etc). I would have created them as member functions on the vector class when extended, but I faced a couple of issues with using the list initialization methods on them. While looking up solutions for this, I realized that extending the vector class is considered a “bad practice” for reasons I’m yet to understand lol. Also, I didn’t quite get how to make the subclass inherit the list initialization from the vector object.</p>
</li>
<li><p>Finally, bitwise operators! I got a basic idea on how powerful these operators can be, especially when working with colors. It’s funny how I’ve used these operators on other non-C projects (such as with <a target="_blank" href="https://developer.android.com/training/system-ui/immersive">Android flags)</a>, but had no idea that I was using them lol.  I haven’t fully understood bitwise operators, but I’m getting there. And of course, a blog post about it :D. Meanwhile, I practiced the basic concepts of these operators by writing a <a target="_blank" href="https://github.com/echoeyecodes/cpp-practice/blob/main/hex-to-rgb.cpp">HEX-to-RGB converter</a>. Then I wrote a <a target="_blank" href="https://github.com/echoeyecodes/cpp-practice/blob/main/rgb-hex.cpp">RGB-to-HEX</a> converter as spice to keep it at 💯.</p>
</li>
</ol>
]]></content:encoded></item><item><title><![CDATA[The Life and Times of Pointers and References in C++]]></title><description><![CDATA[Alright, References and Pointers! I spent a really great amount of hours trying to understand what these compound types are. What are they? The perfect way I understand them is, references are typically another name for referring to an object. Refere...]]></description><link>https://blog.echoeyecodes.com/the-life-and-times-of-pointers-and-references-in-cpp</link><guid isPermaLink="true">https://blog.echoeyecodes.com/the-life-and-times-of-pointers-and-references-in-cpp</guid><category><![CDATA[C++]]></category><category><![CDATA[Game Development]]></category><category><![CDATA[gaming]]></category><dc:creator><![CDATA[Oluwafemi Obajuluwa]]></dc:creator><pubDate>Tue, 23 Mar 2021 08:20:57 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1616452105513/5A5SgYGBe.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Alright, References and Pointers! I spent a really great amount of hours trying to understand what these compound types are. What are they? The perfect way I understand them is, references are typically another name for referring to an object. References aren’t objects as other regular variables we define in a program, rather they are bound to already existing objects. Knowing this means that references can’t just exist on their own without having something they refer to. An object must exist, before a reference can be made. The consequence of this is that references must be initialized as soon as they are defined. Binding a reference to an object is as simple as defining a variable. 
We can define a regular variable as:</p>
<pre><code><span class="hljs-type">int</span> score = <span class="hljs-number">100</span>;
</code></pre><p>Now to bind this variable to a reference, we just need to prefix the reference name with the reference declarator “&amp;”. i.e</p>
<pre><code><span class="hljs-type">int</span> &amp;scoreRef = score;
</code></pre><p>This simple assignment operation is different from a regular assignment operation because, this doesn’t copy the value of <strong><em>score</em></strong> to <strong><em>scoreRef</em></strong>. Instead, it is binding the <strong><em>score</em></strong> object to <strong><em>scoreRef</em></strong>. Any arithmetic operations that can be performed on <strong><em>score</em></strong> can be equally done with <strong><em>scoreRef</em></strong>. If we try to fetch the value of <strong><em>scoreRef</em></strong>, we are actually obtaining the value of the <strong><em>score</em></strong> object itself. It is also important to note that if the operations performed on the <strong><em>scoreRef</em></strong> changes its value, the original object (<strong><em>score</em></strong>) which it is bound to equally changes as well. An example!</p>
<pre><code><span class="hljs-keyword">int</span> lives = <span class="hljs-number">55</span>;
<span class="hljs-keyword">int</span> someTotal = lives;
someTotal = someTotal + <span class="hljs-number">17</span>;
<span class="hljs-built_in">cout</span> &lt;&lt;someTotal &lt;&lt;<span class="hljs-built_in">endl</span>; <span class="hljs-comment">//expected value here is 72</span>
<span class="hljs-built_in">cout</span> &lt;&lt;lives &lt;&lt;<span class="hljs-built_in">endl</span>; <span class="hljs-comment">//expected value here is 55</span>
</code></pre><p>However, using the same example with reference:</p>
<pre><code><span class="hljs-keyword">int</span> lives = <span class="hljs-number">55</span>;
<span class="hljs-keyword">int</span> &amp;someTotal = lives;
someTotal = someTotal + <span class="hljs-number">17</span>;
<span class="hljs-built_in">cout</span> &lt;&lt; someTotal &lt;&lt;<span class="hljs-built_in">endl</span>; <span class="hljs-comment">//expected value here is 72</span>
<span class="hljs-built_in">cout</span> &lt;&lt; lives &lt;&lt;<span class="hljs-built_in">endl</span>; <span class="hljs-comment">// value here is also 72</span>
</code></pre><p>When the <strong><em>lives</em></strong> variable was bound to <strong><em>someTotal</em></strong>, we added 17 to the initial value. This addition changed the value of <strong>someTotal</strong> to 72. Since <strong><em>someTotal</em></strong> is bound to <strong><em>lives</em></strong>, it changes the value of <strong><em>lives</em></strong> as well. Another way to look at it is, <strong><em>someTotal</em></strong> is the same as <strong><em>lives</em></strong>, only difference is that we have another name for it.</p>
<h3 id="important-things-to-know-about-references">Important things to know about references:</h3>
<ol>
<li>References must be initialized immediately.</li>
<li><p>The data type of a reference must be the same as the data type of the object it is bound to.
e.g:
double points = 3.01245;
int &amp;pointsRef = points; //error! points should be an integer</p>
</li>
<li><p>A reference must be bound to an object. This means that we can’t bind a reference to a literal. An example, we can’t do stuff like this;</p>
</li>
</ol>
<pre><code><span class="hljs-keyword">int</span> &amp;scoreRef = <span class="hljs-number">100</span>; <span class="hljs-comment">// error! cos 100 is a literal not an object.</span>
</code></pre><h2 id="pointers">Pointers</h2>
<p>Pointers! Well, pointers are like references being that they also refer to an object… difference is that they refer to the memory address of the object they point to. Also, when a pointer is initialized to point to a particular object, they can be reassigned to point to another address of an object at any time throughout the lifecycle of the program.</p>
<p>Defining a pointer can be done by prefixing the pointer name with an asterisk, and since pointers point to memory addresses, we can obtain the memory address of an object by prefixing the object it points to with a “&amp;”. For example:</p>
<pre><code><span class="hljs-type">int</span> score = <span class="hljs-number">100</span>;
<span class="hljs-type">int</span> *score = &amp;score;
</code></pre><p>If we try to print the value of <strong><em>scoreRef</em></strong>, the result would be a series of strange alphanumeric characters, which is actually the address the object holds in memory. Right now, printing <strong><em>scoreRef</em></strong> yields a result of “003FFEA0”. </p>
<p>A pointer does not need to be initialized at the time it is defined. If just defined, the pointer is known to be a null-pointer. There are also several ways can intentionally define a null pointer as:</p>
<pre><code><span class="hljs-keyword">int</span> *somePointer = <span class="hljs-number">0</span>;
<span class="hljs-keyword">int</span> *somePointer1 = <span class="hljs-literal">NULL</span>;
<span class="hljs-keyword">int</span> *somePointer2 = <span class="hljs-literal">nullptr</span>;
</code></pre><p>Quick note: In example a above, it would be dangerous to assume that literals such as 5,6,7,8… can be assigned to a pointer. This assumption is wrong, and such assignment would fail since a pointer should refer to an object. Only 0 works because, assigning 0 to a pointer is just a way of defining the pointer as a null pointer. It is also illegal to assign an <em>int</em> variable to a pointer, even if the variable is 0.</p>
<p><strong>void</strong> pointers can hold the address of any object of any datatype. The type of the object at the address would be regarded as unknown. This however limits the kind of operations that can be performed on such pointer. You can only pass or return a void pointer, but you cannot use a void pointer to operate on the object it addresses. You can declare a void pointer as:</p>
<pre><code><span class="hljs-type">int</span> score = <span class="hljs-number">45</span>;
<span class="hljs-type">void</span> *somePointer = &amp;score;
</code></pre><p>Doing arithmetic operations like this below won't work since the compiler literally has no idea of the type of the object and if the operation would be valid.</p>
<pre><code><span class="hljs-keyword">int</span> score = <span class="hljs-number">45</span>;
<span class="hljs-keyword">void</span> *somePointer = &amp;score;

<span class="hljs-keyword">int</span> x = *somePointer; <span class="hljs-comment">//error! Dereferencing somePointer doesn't yield an int</span>
</code></pre><p>Dereferencing <strong><em>somePointer</em></strong> only yields the object they point to, but we can’t perform mutable operations on them such as adding/subtracting a value from it since the compiler can’t know if the object is an integer and accepts arithmetic operations, or if the object is a string that could be concatenated, or just something else.</p>
<h3 id="important-things-to-know-about-pointers">Important things to know about pointers:</h3>
<ul>
<li>If a pointer points to an object, the object it points to can be accessed by dereferencing the pointer. Dereferencing a pointer yields the object to which it points to. We dereference a pointer by prefixing the pointer object with an asterisk. An example:</li>
</ul>
<pre><code><span class="hljs-keyword">int</span> score = <span class="hljs-number">70</span>;
<span class="hljs-keyword">int</span> *scorePointer = &amp;score;

<span class="hljs-built_in">cout</span> &lt;&lt; scorePointer &lt;&lt; <span class="hljs-built_in">endl</span>; <span class="hljs-comment">//prints out the address like “783FUEI0”</span>
<span class="hljs-built_in">cout</span> &lt;&lt; *scorePointer &lt;&lt; <span class="hljs-built_in">endl</span>; <span class="hljs-comment">//prints out the the value of score, which is 70;</span>
</code></pre><p>If we assign a different value to the dereferenced pointer, it changes the value of the object to which the pointer points to. For example,</p>
<pre><code>*scorePointer = <span class="hljs-number">1400</span>; // this assignment changes the original <span class="hljs-keyword">value</span> <span class="hljs-keyword">of</span> score <span class="hljs-keyword">to</span> <span class="hljs-number">1400</span>;
</code></pre><p><strong>Note that it is illegal to dereference a null pointer</strong></p>
<ul>
<li>Two pointers can be equal if they hold the same address. This means that two pointers can be compared with “==” and “!=”. Two pointers can have the same address if they’re both null pointers, they point to the same object, or if the two pointers point to an address that is one-past the same object.</li>
</ul>
<p>Okay, that last statement though. I did a bit of research on what <strong>“one-past an object”</strong> means? Assume we have an array of objects, and a pointer points to the address of this array. In the stack of addresses, it is possible to have a pointer that points to the address of a location in memory that is just immediately next to the address of the array object. In the same program, it is also possible that this “unknown memory location” that is just immediately after the location of the array object has been assigned to another object. And this object could equally have a pointer that points to it. In this scenario, there’s a probability that the pointer of this object, and the pointer that is just after (one-past) the location of the array share the same memory address. I could only understand this weird stuff thanks to this <a target="_blank" href="https://stackoverflow.com/a/21850258/9781233">stackoverflow answer</a>.</p>
<ul>
<li>References aren’t objects as explained earlier. Now since pointers point to the address locations of objects, we can’t have a pointer to a reference. But pointers are objects in itself, so we can have references to pointers. An example;</li>
</ul>
<pre><code><span class="hljs-type">int</span> <span class="hljs-keyword">level</span> = <span class="hljs-number">47</span>; //<span class="hljs-keyword">some</span> harmless variable;
<span class="hljs-type">int</span> *levelPointer = &amp;<span class="hljs-keyword">level</span>; //a pointer that points <span class="hljs-keyword">to</span> the address <span class="hljs-keyword">of</span> <span class="hljs-keyword">level</span>
<span class="hljs-type">int</span> *&amp;someReference = levelPointer; // someReference <span class="hljs-keyword">is</span> now a reference <span class="hljs-keyword">to</span> the pointer “levelPointer”.
</code></pre><p>Since references are just another way of representing an existing object, <strong><em>someReference</em></strong> is actually a pointer and dereferencing it yields the <strong><em>level</em></strong> object which has a value of 47.</p>
<ul>
<li>We can assign a pointer to point to another object, even if the pointer already points to another existing object. <pre><code><span class="hljs-keyword">int</span> x = <span class="hljs-number">150</span>;
<span class="hljs-keyword">int</span> y = <span class="hljs-number">100</span>;
<span class="hljs-keyword">int</span> * somePointer = &amp;x; <span class="hljs-comment">// pointer</span>
<span class="hljs-built_in">cout</span> &lt;&lt; *somePointer &lt;&lt;<span class="hljs-built_in">endl</span>; <span class="hljs-comment">// dereferencing the pointer prints 150</span>
somePointer = &amp;y; <span class="hljs-comment">// valid assignment to another object</span>
<span class="hljs-built_in">cout</span> &lt;&lt; * somePointer &lt;&lt;<span class="hljs-built_in">endl</span>; <span class="hljs-comment">// dereferencing the pointer prints 100</span>
</code></pre></li>
</ul>
<p>So there it is! That's pretty much how I understand these two compound types.</p>
<h3 id="now-a-bit-of-therapy-from-a-community-that-gives-me-comfort">Now, a bit of therapy from a community that gives me comfort😊</h3>
<p>I pretty much knew Horizon: Zero Dawn would be a great game just from seeing some shots. Watched a bit of the gameplay and realized I wasn't wrong! This is one of my many favorites I've seen so far.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://twitter.com/photomodeoftsu1/status/1372896103004311554?s=20">https://twitter.com/photomodeoftsu1/status/1372896103004311554?s=20</a></div>
]]></content:encoded></item><item><title><![CDATA[If the gaming industry isn't the best thing ever, then I don't know what is]]></title><description><![CDATA[Okay, so my quest on being a part of the gaming industry as a developer led me to start learning C++ as it is one of the major programming languages used in creating my favorite games, and the other amazing games we have right now. Reason is, for mor...]]></description><link>https://blog.echoeyecodes.com/if-the-gaming-industry-isnt-the-best-thing-ever-then-i-dont-know-what-is</link><guid isPermaLink="true">https://blog.echoeyecodes.com/if-the-gaming-industry-isnt-the-best-thing-ever-then-i-dont-know-what-is</guid><category><![CDATA[gaming]]></category><category><![CDATA[Game Development]]></category><category><![CDATA[Games]]></category><category><![CDATA[newbie]]></category><dc:creator><![CDATA[Oluwafemi Obajuluwa]]></dc:creator><pubDate>Tue, 23 Mar 2021 08:20:06 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1616485683904/Ln1pAFE6x.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Okay, so my quest on being a part of the gaming industry as a developer led me to start learning C++ as it is one of the major programming languages used in creating my favorite games, and the other amazing games we have right now. Reason is, for more than a while now, I haven’t been able to shut up about them. Watching game reveals, announcements, trailers, gameplays are usually this 👌 close to drying up the blood in my body lol. Games are the best things ever!</p>
<p>I stumbled upon an AppleTV series that is produced alongside Ubisoft titled, <a target="_blank" href="https://en.wikipedia.org/wiki/Mythic_Quest">"Mythic Quest"</a>. Loved it from the very first episode, and not until recently did I realize that one of the characters in the tv show - “Poppy-Li” is literally the goal I’m dreaming of. From her personality to her intelligence, she’s really brilliant! The beginning of the third episode of the first season (Dinner Party) is basically one of the fantasies I’ve had if I was in her shoes hehe</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://youtu.be/UGw_sXRRB0E">https://youtu.be/UGw_sXRRB0E</a></div>
<p>(ignore their reception) lol.</p>
<p>Also, I follow some amazing set of virtual photographers on twitter who regularly bless my feed with amazing shots from some really good games. Just look up <a target="_blank" href="https://twitter.com/hashtag/photomode?src=hashtag_click">#photomode</a>, <a target="_blank" href="https://twitter.com/hashtag/WorldofVP?src=hashtag_click">#worldofvp</a>, <a target="_blank" href="https://twitter.com/hashtag/VirtualPhotography?src=hashtag_click">#virtualphotography</a>, <a target="_blank" href="https://twitter.com/hashtag/WorldofVP?src=hashtag_click">#WorldofVP</a> and you would see what I’m talking about. Seeing these photos everyday inspired me to work on an app exclusively for these contents only. It’s currently a work in progress and hope to just get it out there soon!</p>
<p>Finally, I see it coming though. I know learning C++ would be the most challenging thing I’ve ever sought out to do. I’ve already experienced some “glimpse” of how technical it could be (and that’s just Chapter 2 of the book I’m using lol), but the voices of these games are WAY louder than the fear of learning what it takes to create one.</p>
]]></content:encoded></item></channel></rss>