diff --git a/app/src/main/java/emu/skyline/AppDialog.kt b/app/src/main/java/emu/skyline/AppDialog.kt
index 3451bca4..a8e56e20 100644
--- a/app/src/main/java/emu/skyline/AppDialog.kt
+++ b/app/src/main/java/emu/skyline/AppDialog.kt
@@ -15,10 +15,11 @@ import android.view.KeyEvent
 import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
+import androidx.core.content.ContextCompat
 import androidx.core.graphics.drawable.toBitmap
 import com.google.android.material.bottomsheet.BottomSheetBehavior
 import com.google.android.material.bottomsheet.BottomSheetDialogFragment
-import emu.skyline.adapter.AppItem
+import emu.skyline.data.AppItem
 import kotlinx.android.synthetic.main.app_dialog.*
 
 /**
@@ -26,7 +27,7 @@ import kotlinx.android.synthetic.main.app_dialog.*
  *
  * @param item This is used to hold the [AppItem] between instances
  */
-class AppDialog(val item : AppItem? = null) : BottomSheetDialogFragment() {
+class AppDialog(val item : AppItem) : BottomSheetDialogFragment() {
 
     /**
      * This inflates the layout of the dialog after initial view creation
@@ -47,10 +48,9 @@ class AppDialog(val item : AppItem? = null) : BottomSheetDialogFragment() {
         dialog?.setOnKeyListener { _, keyCode, event ->
             if (keyCode == KeyEvent.KEYCODE_BUTTON_B && event.action == KeyEvent.ACTION_DOWN) {
                 dialog?.onBackPressed()
-                true
-            } else {
-                false
+                return@setOnKeyListener true
             }
+            false
         }
     }
 
@@ -60,38 +60,35 @@ class AppDialog(val item : AppItem? = null) : BottomSheetDialogFragment() {
     override fun onActivityCreated(savedInstanceState : Bundle?) {
         super.onActivityCreated(savedInstanceState)
 
-        if (item is AppItem) {
-            val missingIcon = context?.resources?.getDrawable(R.drawable.default_icon, context?.theme)?.toBitmap(256, 256)
+        val missingIcon = ContextCompat.getDrawable(requireActivity(), R.drawable.default_icon)!!.toBitmap(256, 256)
 
-            game_icon.setImageBitmap(item.icon ?: missingIcon)
-            game_title.text = item.title
-            game_subtitle.text = item.subTitle ?: getString(R.string.metadata_missing)
+        game_icon.setImageBitmap(item.icon ?: missingIcon)
+        game_title.text = item.title
+        game_subtitle.text = item.subTitle ?: getString(R.string.metadata_missing)
 
-            game_play.setOnClickListener {
-                val intent = Intent(activity, EmulationActivity::class.java)
-                intent.data = item.uri
+        game_play.setOnClickListener {
+            val intent = Intent(activity, EmulationActivity::class.java)
+            intent.data = item.uri
 
-                startActivity(intent)
-            }
+            startActivity(intent)
+        }
 
-            val shortcutManager = activity?.getSystemService(ShortcutManager::class.java)!!
-            game_pin.isEnabled = shortcutManager.isRequestPinShortcutSupported
+        val shortcutManager = requireActivity().getSystemService(ShortcutManager::class.java)
+        game_pin.isEnabled = shortcutManager.isRequestPinShortcutSupported
 
-            game_pin.setOnClickListener {
-                val info = ShortcutInfo.Builder(context, item.title)
-                info.setShortLabel(item.meta.name)
-                info.setActivity(ComponentName(context!!, EmulationActivity::class.java))
-                info.setIcon(Icon.createWithAdaptiveBitmap(item.icon ?: missingIcon))
+        game_pin.setOnClickListener {
+            val info = ShortcutInfo.Builder(context, item.title)
+            info.setShortLabel(item.meta.name)
+            info.setActivity(ComponentName(requireActivity(), EmulationActivity::class.java))
+            info.setIcon(Icon.createWithAdaptiveBitmap(item.icon ?: missingIcon))
 
-                val intent = Intent(context, EmulationActivity::class.java)
-                intent.data = item.uri
-                intent.action = Intent.ACTION_VIEW
+            val intent = Intent(context, EmulationActivity::class.java)
+            intent.data = item.uri
+            intent.action = Intent.ACTION_VIEW
 
-                info.setIntent(intent)
+            info.setIntent(intent)
 
-                shortcutManager.requestPinShortcut(info.build(), null)
-            }
-        } else
-            activity?.supportFragmentManager?.beginTransaction()?.remove(this)?.commit()
+            shortcutManager.requestPinShortcut(info.build(), null)
+        }
     }
 }
diff --git a/app/src/main/java/emu/skyline/MainActivity.kt b/app/src/main/java/emu/skyline/MainActivity.kt
index 96a2fe62..dc009545 100644
--- a/app/src/main/java/emu/skyline/MainActivity.kt
+++ b/app/src/main/java/emu/skyline/MainActivity.kt
@@ -25,9 +25,9 @@ import androidx.recyclerview.widget.LinearLayoutManager
 import androidx.recyclerview.widget.RecyclerView
 import com.google.android.material.snackbar.Snackbar
 import emu.skyline.adapter.AppAdapter
-import emu.skyline.adapter.AppItem
 import emu.skyline.adapter.GridLayoutSpan
 import emu.skyline.adapter.LayoutType
+import emu.skyline.data.AppItem
 import emu.skyline.loader.RomFile
 import emu.skyline.loader.RomFormat
 import kotlinx.android.synthetic.main.main_activity.*
@@ -37,7 +37,7 @@ import java.io.IOException
 import kotlin.concurrent.thread
 import kotlin.math.ceil
 
-class MainActivity : AppCompatActivity(), View.OnClickListener, View.OnLongClickListener {
+class MainActivity : AppCompatActivity(), View.OnClickListener {
     /**
      * This is used to get/set shared preferences
      */
@@ -51,14 +51,14 @@ class MainActivity : AppCompatActivity(), View.OnClickListener, View.OnLongClick
     /**
      * This adds all files in [directory] with [extension] as an entry in [adapter] using [loader] to load metadata
      */
-    private fun addEntries(extension : String, romFormat : RomFormat, directory : DocumentFile, found : Boolean = false) : Boolean {
+    private fun addEntries(romFormat : RomFormat, directory : DocumentFile, found : Boolean = false) : Boolean {
         var foundCurrent = found
 
         directory.listFiles().forEach { file ->
             if (file.isDirectory) {
-                foundCurrent = addEntries(extension, romFormat, file, foundCurrent)
+                foundCurrent = addEntries(romFormat, file, foundCurrent)
             } else {
-                if (extension.equals(file.name?.substringAfterLast("."), ignoreCase = true)) {
+                if (romFormat.extension.equals(file.name?.substringAfterLast("."), ignoreCase = true)) {
                     val romFd = contentResolver.openFileDescriptor(file.uri, "r")!!
                     val romFile = RomFile(this, romFormat, romFd)
 
@@ -111,14 +111,17 @@ class MainActivity : AppCompatActivity(), View.OnClickListener, View.OnLongClick
             try {
                 runOnUiThread { adapter.clear() }
 
-                var foundRoms = addEntries("nro", RomFormat.NRO, DocumentFile.fromTreeUri(this, Uri.parse(sharedPreferences.getString("search_location", "")))!!)
-                foundRoms = foundRoms or addEntries("nso", RomFormat.NSO, DocumentFile.fromTreeUri(this, Uri.parse(sharedPreferences.getString("search_location", "")))!!)
-                foundRoms = foundRoms or addEntries("nca", RomFormat.NCA, DocumentFile.fromTreeUri(this, Uri.parse(sharedPreferences.getString("search_location", "")))!!)
-                foundRoms = foundRoms or addEntries("nsp", RomFormat.NSP, DocumentFile.fromTreeUri(this, Uri.parse(sharedPreferences.getString("search_location", "")))!!)
+                val searchLocation = DocumentFile.fromTreeUri(this, Uri.parse(sharedPreferences.getString("search_location", "")))!!
+
+                var foundRoms = addEntries(RomFormat.NRO, searchLocation)
+                foundRoms = foundRoms or addEntries(RomFormat.NSO, searchLocation)
+                foundRoms = foundRoms or addEntries(RomFormat.NCA, searchLocation)
+                foundRoms = foundRoms or addEntries(RomFormat.NSP, searchLocation)
 
                 runOnUiThread {
-                    if (!foundRoms)
+                    if (!foundRoms) {
                         adapter.addHeader(getString(R.string.no_rom))
+                    }
 
                     try {
                         adapter.save(File("${applicationInfo.dataDir}/roms.bin"))
@@ -172,28 +175,7 @@ class MainActivity : AppCompatActivity(), View.OnClickListener, View.OnLongClick
         open_fab.setOnClickListener(this)
         log_fab.setOnClickListener(this)
 
-        val layoutType = LayoutType.values()[sharedPreferences.getString("layout_type", "1")!!.toInt()]
-
-        adapter = AppAdapter(this, layoutType)
-        app_list.adapter = adapter
-
-        when (layoutType) {
-            LayoutType.List -> {
-                app_list.layoutManager = LinearLayoutManager(this)
-                app_list.addItemDecoration(DividerItemDecoration(this, RecyclerView.VERTICAL))
-            }
-
-            LayoutType.Grid -> {
-                val itemWidth = 225
-                val metrics = resources.displayMetrics
-                val span = ceil((metrics.widthPixels / metrics.density) / itemWidth).toInt()
-
-                val layoutManager = GridLayoutManager(this, span)
-                layoutManager.spanSizeLookup = GridLayoutSpan(adapter, span)
-
-                app_list.layoutManager = layoutManager
-            }
-        }
+        setupAppList()
 
         app_list.addOnScrollListener(object : RecyclerView.OnScrollListener() {
             var y : Int = 0
@@ -202,23 +184,43 @@ class MainActivity : AppCompatActivity(), View.OnClickListener, View.OnLongClick
                 y += dy
 
                 if (!app_list.isInTouchMode) {
-                    if (y == 0)
-                        toolbar_layout.setExpanded(true)
-                    else
-                        toolbar_layout.setExpanded(false)
+                    toolbar_layout.setExpanded(y == 0)
                 }
 
                 super.onScrolled(recyclerView, dx, dy)
             }
         })
+    }
+
+    private fun setupAppList() {
+        val itemWidth = 225
+        val metrics = resources.displayMetrics
+        val gridSpan = ceil((metrics.widthPixels / metrics.density) / itemWidth).toInt()
+
+        val layoutType = LayoutType.values()[sharedPreferences.getString("layout_type", "1")!!.toInt()]
+
+        adapter = AppAdapter(layoutType = layoutType, gridSpan = gridSpan, onClick = selectStartGame, onLongClick = selectShowGameDialog)
+        app_list.adapter = adapter
+
+        app_list.layoutManager = when (layoutType) {
+            LayoutType.List -> LinearLayoutManager(this).also { app_list.addItemDecoration(DividerItemDecoration(this, RecyclerView.VERTICAL)) }
+            LayoutType.Grid, LayoutType.GridCompact -> GridLayoutManager(this, gridSpan).apply {
+                spanSizeLookup = GridLayoutSpan(adapter, gridSpan).also {
+                    if (app_list.itemDecorationCount > 0) {
+                        app_list.removeItemDecorationAt(0)
+                    }
+                }
+            }
+        }
 
         if (sharedPreferences.getString("search_location", "") == "") {
             val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
             intent.flags = Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION or Intent.FLAG_GRANT_PREFIX_URI_PERMISSION or Intent.FLAG_GRANT_READ_URI_PERMISSION
 
             startActivityForResult(intent, 1)
-        } else
+        } else {
             refreshAdapter(!sharedPreferences.getBoolean("refresh_required", false))
+        }
     }
 
     /**
@@ -245,12 +247,11 @@ class MainActivity : AppCompatActivity(), View.OnClickListener, View.OnLongClick
     }
 
     /**
-     * This handles on-click interaction with [R.id.log_fab], [R.id.open_fab], [R.id.app_item_linear] and [R.id.app_item_grid]
+     * This handles on-click interaction with [R.id.log_fab], [R.id.open_fab]
      */
     override fun onClick(view : View) {
         when (view.id) {
             R.id.log_fab -> startActivity(Intent(this, LogActivity::class.java))
-
             R.id.open_fab -> {
                 val intent = Intent(Intent.ACTION_OPEN_DOCUMENT)
                 intent.addCategory(Intent.CATEGORY_OPENABLE)
@@ -258,40 +259,19 @@ class MainActivity : AppCompatActivity(), View.OnClickListener, View.OnLongClick
 
                 startActivityForResult(intent, 2)
             }
-
-            R.id.app_item_linear, R.id.app_item_grid -> {
-                val tag = view.tag
-                if (tag is AppItem) {
-                    if (sharedPreferences.getBoolean("select_action", false)) {
-                        val dialog = AppDialog(tag)
-                        dialog.show(supportFragmentManager, "game")
-                    } else {
-                        val intent = Intent(this, EmulationActivity::class.java)
-                        intent.data = tag.uri
-                        startActivity(intent)
-                    }
-                }
-            }
         }
     }
 
-    /**
-     * This handles long-click interaction with [R.id.app_item_linear] and [R.id.app_item_grid]
-     */
-    override fun onLongClick(view : View?) : Boolean {
-        when (view?.id) {
-            R.id.app_item_linear, R.id.app_item_grid -> {
-                val tag = view.tag
-                if (tag is AppItem) {
-                    val dialog = AppDialog(tag)
-                    dialog.show(supportFragmentManager, "game")
-
-                    return true
-                }
-            }
+    private val selectStartGame : (appItem : AppItem) -> Unit = {
+        if (sharedPreferences.getBoolean("select_action", false)) {
+            AppDialog(it).show(supportFragmentManager, "game")
+        } else {
+            startActivity(Intent(this, EmulationActivity::class.java).apply { data = it.uri })
         }
+    }
 
-        return false
+    private val selectShowGameDialog : (appItem : AppItem) -> Unit = {
+        AppDialog(it).show(supportFragmentManager, "game")
     }
 
     /**
@@ -350,4 +330,13 @@ class MainActivity : AppCompatActivity(), View.OnClickListener, View.OnLongClick
             }
         }
     }
+
+    override fun onResume() {
+        super.onResume()
+
+        val layoutType = LayoutType.values()[sharedPreferences.getString("layout_type", "1")!!.toInt()]
+        if (layoutType != adapter.layoutType) {
+            setupAppList()
+        }
+    }
 }
diff --git a/app/src/main/java/emu/skyline/adapter/AppAdapter.kt b/app/src/main/java/emu/skyline/adapter/AppAdapter.kt
index e5c297b4..8ffbdf96 100644
--- a/app/src/main/java/emu/skyline/adapter/AppAdapter.kt
+++ b/app/src/main/java/emu/skyline/adapter/AppAdapter.kt
@@ -7,80 +7,42 @@ package emu.skyline.adapter
 
 import android.app.Dialog
 import android.content.Context
-import android.graphics.Bitmap
 import android.graphics.Color
 import android.graphics.drawable.ColorDrawable
-import android.net.Uri
+import android.util.Log
 import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
 import android.view.Window
 import android.widget.ImageView
+import android.widget.LinearLayout
 import android.widget.RelativeLayout
 import android.widget.TextView
+import androidx.core.content.ContextCompat
 import androidx.core.graphics.drawable.toBitmap
 import androidx.recyclerview.widget.RecyclerView
 import emu.skyline.R
-import emu.skyline.adapter.ElementType.Header
-import emu.skyline.adapter.ElementType.Item
-import emu.skyline.loader.AppEntry
-
-/**
- * This class is a wrapper around [AppEntry], it is used for passing around game metadata
- */
-class AppItem(val meta : AppEntry) : BaseItem() {
-    /**
-     * The icon of the application
-     */
-    val icon : Bitmap?
-        get() = meta.icon
-
-    /**
-     * The title of the application
-     */
-    val title : String
-        get() = meta.name
-
-    /**
-     * The string used as the sub-title, we currently use the author
-     */
-    val subTitle : String?
-        get() = meta.author
-
-    /**
-     * The URI of the application's image file
-     */
-    val uri : Uri
-        get() = meta.uri
-
-    /**
-     * The format of the application ROM as a string
-     */
-    private val type : String
-        get() = meta.format.name
-
-    /**
-     * The name and author is used as the key
-     */
-    override fun key() : String? {
-        return if (meta.author != null) meta.name + " " + meta.author else meta.name
-    }
-}
+import emu.skyline.data.AppItem
 
 /**
  * This enumerates the type of layouts the menu can be in
  */
-enum class LayoutType {
-    List,
-    Grid,
+enum class LayoutType(val layoutRes : Int) {
+    List(R.layout.app_item_linear),
+    Grid(R.layout.app_item_grid),
+    GridCompact(R.layout.app_item_grid_compact)
 }
 
+private typealias AppInteractionFunc = (appItem : AppItem) -> Unit
+
 /**
  * This adapter is used to display all found applications using their metadata
  */
-internal class AppAdapter(val context : Context?, private val layoutType : LayoutType) : HeaderAdapter<AppItem, BaseHeader, RecyclerView.ViewHolder>(), View.OnClickListener {
-    private val missingIcon = context?.resources?.getDrawable(R.drawable.default_icon, context.theme)?.toBitmap(256, 256)
-    private val missingString = context?.getString(R.string.metadata_missing)
+internal class AppAdapter(val layoutType : LayoutType, private val gridSpan : Int, private val onClick : AppInteractionFunc, private val onLongClick : AppInteractionFunc) : HeaderAdapter<AppItem, BaseHeader, RecyclerView.ViewHolder>() {
+
+    private lateinit var context : Context
+    private val missingIcon by lazy { ContextCompat.getDrawable(context, R.drawable.default_icon)!!.toBitmap(256, 256) }
+    private val missingString by lazy { context.getString(R.string.metadata_missing) }
 
     /**
      * This adds a header to the view with the contents of [string]
@@ -89,29 +51,6 @@ internal class AppAdapter(val context : Context?, private val layoutType : Layou
         super.addHeader(BaseHeader(string))
     }
 
-    /**
-     * The onClick handler for the supplied [view], used for the icon preview
-     */
-    override fun onClick(view : View) {
-        val position = view.tag as Int
-
-        if (getItem(position) is AppItem) {
-            val item = getItem(position) as AppItem
-
-            if (view.id == R.id.icon) {
-                val builder = Dialog(context!!)
-                builder.requestWindowFeature(Window.FEATURE_NO_TITLE)
-                builder.window!!.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
-
-                val imageView = ImageView(context)
-                imageView.setImageBitmap(item.icon ?: missingIcon)
-
-                builder.addContentView(imageView, RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT))
-                builder.show()
-            }
-        }
-    }
-
     /**
      * The ViewHolder used by items is used to hold the views associated with an item
      *
@@ -134,38 +73,49 @@ internal class AppAdapter(val context : Context?, private val layoutType : Layou
      * This function creates the view-holder of type [viewType] with the layout parent as [parent]
      */
     override fun onCreateViewHolder(parent : ViewGroup, viewType : Int) : RecyclerView.ViewHolder {
+        context = parent.context
+
         val inflater = LayoutInflater.from(context)
-        var holder : RecyclerView.ViewHolder? = null
-
-        if (viewType == Item.ordinal) {
-            val view = inflater.inflate(if (layoutType == LayoutType.List) R.layout.app_item_linear else R.layout.app_item_grid, parent, false)
-            holder = ItemViewHolder(view, view.findViewById(R.id.icon), view.findViewById(R.id.text_title), view.findViewById(R.id.text_subtitle))
-
-            if (layoutType == LayoutType.List) {
-                if (context is View.OnClickListener)
-                    view.setOnClickListener(context as View.OnClickListener)
-
-                if (context is View.OnLongClickListener)
-                    view.setOnLongClickListener(context as View.OnLongClickListener)
-            } else {
-                holder.card = view.findViewById(R.id.app_item_grid)
-
-                if (context is View.OnClickListener)
-                    holder.card!!.setOnClickListener(context as View.OnClickListener)
-
-                if (context is View.OnLongClickListener)
-                    holder.card!!.setOnLongClickListener(context as View.OnLongClickListener)
-
-                holder.title.isSelected = true
-            }
-        } else if (viewType == Header.ordinal) {
-            val view = inflater.inflate(R.layout.section_item, parent, false)
-            holder = HeaderViewHolder(view)
-
-            holder.header = view.findViewById(R.id.text_title)
+        val view = when (ElementType.values()[viewType]) {
+            ElementType.Item -> inflater.inflate(layoutType.layoutRes, parent, false)
+            ElementType.Header -> inflater.inflate(R.layout.section_item, parent, false)
         }
 
-        return holder!!
+        Log.i("blaa", "onCreateViewHolder")
+
+        return when (ElementType.values()[viewType]) {
+            ElementType.Item -> {
+                ItemViewHolder(view, view.findViewById(R.id.icon), view.findViewById(R.id.text_title), view.findViewById(R.id.text_subtitle)).apply {
+                    if (layoutType == LayoutType.List) {
+                        view.apply {
+                            if (context is View.OnClickListener) {
+                                setOnClickListener(context as View.OnClickListener)
+                            }
+                            if (context is View.OnLongClickListener) {
+                                setOnLongClickListener(context as View.OnLongClickListener)
+                            }
+                        }
+                    } else {
+                        card = view.findViewById(R.id.app_item_grid)
+                        card!!.apply {
+                            if (context is View.OnClickListener) {
+                                setOnClickListener(context as View.OnClickListener)
+                            }
+                            if (context is View.OnLongClickListener) {
+                                setOnLongClickListener(context as View.OnLongClickListener)
+                            }
+                        }
+
+                        title.isSelected = true
+                    }
+                }
+            }
+            ElementType.Header -> {
+                HeaderViewHolder(view).apply {
+                    header = view.findViewById(R.id.text_title)
+                }
+            }
+        }
     }
 
     /**
@@ -183,16 +133,45 @@ internal class AppAdapter(val context : Context?, private val layoutType : Layou
             holder.icon.setImageBitmap(item.icon ?: missingIcon)
 
             if (layoutType == LayoutType.List) {
-                holder.icon.setOnClickListener(this)
-                holder.icon.tag = position
+                holder.icon.setOnClickListener { showIconDialog(item) }
             }
 
-            holder.card?.tag = item
-            holder.parent.tag = item
+            when (layoutType) {
+                LayoutType.List -> holder.itemView
+                LayoutType.Grid, LayoutType.GridCompact -> holder.card!!
+            }.apply {
+                setOnClickListener { onClick.invoke(item) }
+                setOnLongClickListener { true.also { onLongClick.invoke(item) } }
+            }
+
+            // Increase margin of edges to avoid huge gap in between items
+            if (layoutType == LayoutType.Grid || layoutType == LayoutType.GridCompact) {
+
+                holder.itemView.layoutParams = LinearLayout.LayoutParams(holder.itemView.layoutParams.width, holder.itemView.layoutParams.height).apply {
+                    if (position % gridSpan == 0) {
+                        marginStart = holder.itemView.resources.getDimensionPixelSize(R.dimen.app_card_margin) * 2
+                    } else if (position % gridSpan == gridSpan - 1) {
+                        marginEnd = holder.itemView.resources.getDimensionPixelSize(R.dimen.app_card_margin) * 2
+                    }
+                }
+                holder.itemView.requestLayout()
+            }
         } else if (item is BaseHeader) {
             val holder = viewHolder as HeaderViewHolder
 
             holder.header!!.text = item.title
         }
     }
+
+    private fun showIconDialog(appItem : AppItem) {
+        val builder = Dialog(context)
+        builder.requestWindowFeature(Window.FEATURE_NO_TITLE)
+        builder.window!!.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
+
+        val imageView = ImageView(context)
+        imageView.setImageBitmap(appItem.icon ?: missingIcon)
+
+        builder.addContentView(imageView, RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT))
+        builder.show()
+    }
 }
diff --git a/app/src/main/java/emu/skyline/adapter/HeaderAdapter.kt b/app/src/main/java/emu/skyline/adapter/HeaderAdapter.kt
index f6265612..af7cabdd 100644
--- a/app/src/main/java/emu/skyline/adapter/HeaderAdapter.kt
+++ b/app/src/main/java/emu/skyline/adapter/HeaderAdapter.kt
@@ -10,6 +10,7 @@ import android.widget.Filter
 import android.widget.Filterable
 import androidx.recyclerview.widget.GridLayoutManager
 import androidx.recyclerview.widget.RecyclerView
+import emu.skyline.data.BaseItem
 import info.debatty.java.stringsimilarity.Cosine
 import info.debatty.java.stringsimilarity.JaroWinkler
 import java.io.*
@@ -35,16 +36,6 @@ abstract class BaseElement constructor(val elementType : ElementType) : Serializ
  */
 class BaseHeader constructor(val title : String) : BaseElement(ElementType.Header)
 
-/**
- * This is an abstract class that all adapter item classes inherit from
- */
-abstract class BaseItem : BaseElement(ElementType.Item) {
-    /**
-     * This function returns a string used for searching
-     */
-    abstract fun key() : String?
-}
-
 /**
  * This adapter has the ability to have 2 types of elements specifically headers and items
  */
@@ -69,9 +60,9 @@ abstract class HeaderAdapter<ItemType : BaseItem?, HeaderType : BaseHeader?, Vie
      */
     fun addItem(item : ItemType) {
         elementArray.add(item)
-        if (searchTerm.isNotEmpty())
+        if (searchTerm.isNotEmpty()) {
             filter.filter(searchTerm)
-        else {
+        } else {
             visibleArray.add(elementArray.size - 1)
             notifyDataSetChanged()
         }
@@ -146,93 +137,91 @@ abstract class HeaderAdapter<ItemType : BaseItem?, HeaderType : BaseHeader?, Vie
     /**
      * This returns an instance of the filter object which is used to search for items in the view
      */
-    override fun getFilter() : Filter {
-        return object : Filter() {
-            /**
-             * We use Jaro-Winkler distance for string similarity (https://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance)
-             */
-            private val jw = JaroWinkler()
+    override fun getFilter() : Filter = object : Filter() {
+        /**
+         * We use Jaro-Winkler distance for string similarity (https://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance)
+         */
+        private val jw = JaroWinkler()
 
-            /**
-             * We use Cosine similarity for string similarity (https://en.wikipedia.org/wiki/Cosine_similarity)
-             */
-            private val cos = Cosine()
+        /**
+         * We use Cosine similarity for string similarity (https://en.wikipedia.org/wiki/Cosine_similarity)
+         */
+        private val cos = Cosine()
 
-            /**
-             * This class is used to store the results of the item sorting
-             *
-             * @param score The score of this result
-             * @param index The index of this item
-             */
-            inner class ScoredItem(val score : Double, val index : Int) {}
+        /**
+         * This class is used to store the results of the item sorting
+         *
+         * @param score The score of this result
+         * @param index The index of this item
+         */
+        inner class ScoredItem(val score : Double, val index : Int) {}
 
-            /**
-             * This sorts the items in [keyArray] in relation to how similar they are to [term]
-             */
-            fun extractSorted(term : String, keyArray : ArrayList<String>) : Array<ScoredItem> {
-                val scoredItems : MutableList<ScoredItem> = ArrayList()
+        /**
+         * This sorts the items in [keyArray] in relation to how similar they are to [term]
+         */
+        fun extractSorted(term : String, keyArray : ArrayList<String>) : Array<ScoredItem> {
+            val scoredItems : MutableList<ScoredItem> = ArrayList()
 
-                keyArray.forEachIndexed { index, item ->
-                    val similarity = (jw.similarity(term, item) + cos.similarity(term, item)) / 2
+            keyArray.forEachIndexed { index, item ->
+                val similarity = (jw.similarity(term, item) + cos.similarity(term, item)) / 2
 
-                    if (similarity != 0.0)
-                        scoredItems.add(ScoredItem(similarity, index))
-                }
-
-                scoredItems.sortWith(compareByDescending { it.score })
-
-                return scoredItems.toTypedArray()
+                if (similarity != 0.0)
+                    scoredItems.add(ScoredItem(similarity, index))
             }
 
-            /**
-             * This performs filtering on the items in [elementArray] based on similarity to [term]
-             */
-            override fun performFiltering(term : CharSequence) : FilterResults {
-                val results = FilterResults()
-                searchTerm = (term as String).toLowerCase(Locale.getDefault())
+            scoredItems.sortWith(compareByDescending { it.score })
 
-                if (term.isEmpty()) {
-                    results.values = elementArray.indices.toMutableList()
-                    results.count = elementArray.size
-                } else {
-                    val filterData = ArrayList<Int>()
+            return scoredItems.toTypedArray()
+        }
 
-                    val keyArray = ArrayList<String>()
-                    val keyIndex = SparseIntArray()
+        /**
+         * This performs filtering on the items in [elementArray] based on similarity to [term]
+         */
+        override fun performFiltering(term : CharSequence) : FilterResults {
+            val results = FilterResults()
+            searchTerm = (term as String).toLowerCase(Locale.getDefault())
 
-                    for (index in elementArray.indices) {
-                        val item = elementArray[index]!!
+            if (term.isEmpty()) {
+                results.values = elementArray.indices.toMutableList()
+                results.count = elementArray.size
+            } else {
+                val filterData = ArrayList<Int>()
 
-                        if (item is BaseItem) {
-                            keyIndex.append(keyArray.size, index)
-                            keyArray.add(item.key()!!.toLowerCase(Locale.getDefault()))
-                        }
+                val keyArray = ArrayList<String>()
+                val keyIndex = SparseIntArray()
+
+                for (index in elementArray.indices) {
+                    val item = elementArray[index]!!
+
+                    if (item is BaseItem) {
+                        keyIndex.append(keyArray.size, index)
+                        keyArray.add(item.key()!!.toLowerCase(Locale.getDefault()))
                     }
-
-                    val topResults = extractSorted(searchTerm, keyArray)
-                    val avgScore = topResults.sumByDouble { it.score } / topResults.size
-
-                    for (result in topResults)
-                        if (result.score > avgScore)
-                            filterData.add(keyIndex[result.index])
-
-                    results.values = filterData
-                    results.count = filterData.size
                 }
 
-                return results
+                val topResults = extractSorted(searchTerm, keyArray)
+                val avgScore = topResults.sumByDouble { it.score } / topResults.size
+
+                for (result in topResults)
+                    if (result.score > avgScore)
+                        filterData.add(keyIndex[result.index])
+
+                results.values = filterData
+                results.count = filterData.size
             }
 
-            /**
-             * This publishes the results that were calculated in [performFiltering] to the view
-             */
-            override fun publishResults(charSequence : CharSequence, results : FilterResults) {
-                if (results.values is ArrayList<*>) {
-                    @Suppress("UNCHECKED_CAST")
-                    visibleArray = results.values as ArrayList<Int>
+            return results
+        }
 
-                    notifyDataSetChanged()
-                }
+        /**
+         * This publishes the results that were calculated in [performFiltering] to the view
+         */
+        override fun publishResults(charSequence : CharSequence, results : FilterResults) {
+            if (results.values is ArrayList<*>) {
+                @Suppress("UNCHECKED_CAST")
+                visibleArray = results.values as ArrayList<Int>
+
+                notifyDataSetChanged()
             }
         }
     }
@@ -244,7 +233,7 @@ abstract class HeaderAdapter<ItemType : BaseItem?, HeaderType : BaseHeader?, Vie
  * @param adapter The adapter which is used to deduce the type of the item based on the position
  * @param headerSpan The span size to return for headers
  */
-class GridLayoutSpan<ItemType : BaseItem?, HeaderType : BaseHeader?, ViewHolder : RecyclerView.ViewHolder?>(val adapter : HeaderAdapter<ItemType, HeaderType, ViewHolder>, var headerSpan : Int) : GridLayoutManager.SpanSizeLookup() {
+class GridLayoutSpan<ItemType : BaseItem?, HeaderType : BaseHeader?, ViewHolder : RecyclerView.ViewHolder?>(val adapter : HeaderAdapter<ItemType, HeaderType, ViewHolder>, private val headerSpan : Int) : GridLayoutManager.SpanSizeLookup() {
     /**
      * This returns the size of the span based on the type of the element at [position]
      */
diff --git a/app/src/main/java/emu/skyline/adapter/LogAdapter.kt b/app/src/main/java/emu/skyline/adapter/LogAdapter.kt
index 6d5d4ebc..5f350cc3 100644
--- a/app/src/main/java/emu/skyline/adapter/LogAdapter.kt
+++ b/app/src/main/java/emu/skyline/adapter/LogAdapter.kt
@@ -10,12 +10,12 @@ import android.content.ClipboardManager
 import android.content.Context
 import android.view.LayoutInflater
 import android.view.View
-import android.view.View.OnLongClickListener
 import android.view.ViewGroup
 import android.widget.TextView
 import android.widget.Toast
 import androidx.recyclerview.widget.RecyclerView
 import emu.skyline.R
+import emu.skyline.data.BaseItem
 
 /**
  * This class is used to hold all data about a log entry
@@ -32,7 +32,7 @@ internal class LogItem(val message : String, val level : String) : BaseItem() {
 /**
  * This adapter is used for displaying logs outputted by the application
  */
-internal class LogAdapter internal constructor(val context : Context, val compact : Boolean, private val debug_level : Int, private val level_str : Array<String>) : HeaderAdapter<LogItem, BaseHeader, RecyclerView.ViewHolder>(), OnLongClickListener {
+internal class LogAdapter internal constructor(val context : Context, val compact : Boolean, private val debug_level : Int, private val level_str : Array<String>) : HeaderAdapter<LogItem, BaseHeader, RecyclerView.ViewHolder>() {
     private val clipboard : ClipboardManager = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
 
     /**
@@ -72,41 +72,33 @@ internal class LogAdapter internal constructor(val context : Context, val compac
      */
     private class HeaderViewHolder(val parent : View, var header : TextView) : RecyclerView.ViewHolder(parent)
 
-    /**
-     * The onLongClick handler for the supplied [view], used to copy a log into the clipboard
-     */
-    override fun onLongClick(view : View) : Boolean {
-        val item = view.tag as LogItem
-        clipboard.setPrimaryClip(ClipData.newPlainText("Log Message", item.message + " (" + item.level + ")"))
-        Toast.makeText(view.context, "Copied to clipboard", Toast.LENGTH_LONG).show()
-        return false
-    }
-
     /**
      * This function creates the view-holder of type [viewType] with the layout parent as [parent]
      */
     override fun onCreateViewHolder(parent : ViewGroup, viewType : Int) : RecyclerView.ViewHolder {
         val inflater = LayoutInflater.from(context)
-        var holder : RecyclerView.ViewHolder? = null
 
-        if (viewType == ElementType.Item.ordinal) {
-            if (compact) {
-                val view = inflater.inflate(R.layout.log_item_compact, parent, false)
-                holder = ItemViewHolder(view, view.findViewById(R.id.text_title))
-
-                view.setOnLongClickListener(this)
-            } else {
-                val view = inflater.inflate(R.layout.log_item, parent, false)
-                holder = ItemViewHolder(view, view.findViewById(R.id.text_title), view.findViewById(R.id.text_subtitle))
-
-                view.setOnLongClickListener(this)
+        val view = when (ElementType.values()[viewType]) {
+            ElementType.Item -> {
+                inflater.inflate(if (compact) R.layout.log_item_compact else R.layout.log_item, parent, false)
+            }
+            ElementType.Header -> {
+                inflater.inflate(R.layout.log_item, parent, false)
             }
-        } else if (viewType == ElementType.Header.ordinal) {
-            val view = inflater.inflate(R.layout.section_item, parent, false)
-            holder = HeaderViewHolder(view, view.findViewById(R.id.text_title))
         }
 
-        return holder!!
+        return when (ElementType.values()[viewType]) {
+            ElementType.Item -> {
+                if (compact) {
+                    ItemViewHolder(view, view.findViewById(R.id.text_title))
+                } else {
+                    ItemViewHolder(view, view.findViewById(R.id.text_title), view.findViewById(R.id.text_subtitle))
+                }
+            }
+            ElementType.Header -> {
+                HeaderViewHolder(view, view.findViewById(R.id.text_title))
+            }
+        }
     }
 
     /**
@@ -121,7 +113,10 @@ internal class LogAdapter internal constructor(val context : Context, val compac
             holder.title.text = item.message
             holder.subtitle?.text = item.level
 
-            holder.parent.tag = item
+            holder.parent.setOnClickListener {
+                clipboard.setPrimaryClip(ClipData.newPlainText("Log Message", item.message + " (" + item.level + ")"))
+                Toast.makeText(holder.itemView.context, "Copied to clipboard", Toast.LENGTH_LONG).show()
+            }
         } else if (item is BaseHeader) {
             val holder = viewHolder as HeaderViewHolder
 
diff --git a/app/src/main/java/emu/skyline/data/AppItem.kt b/app/src/main/java/emu/skyline/data/AppItem.kt
new file mode 100644
index 00000000..443b51f9
--- /dev/null
+++ b/app/src/main/java/emu/skyline/data/AppItem.kt
@@ -0,0 +1,52 @@
+/*
+ * SPDX-License-Identifier: MPL-2.0
+ * Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
+ */
+
+package emu.skyline.data
+
+import android.graphics.Bitmap
+import android.net.Uri
+import emu.skyline.loader.AppEntry
+
+/**
+ * This class is a wrapper around [AppEntry], it is used for passing around game metadata
+ */
+class AppItem(val meta : AppEntry) : BaseItem() {
+    /**
+     * The icon of the application
+     */
+    val icon : Bitmap?
+        get() = meta.icon
+
+    /**
+     * The title of the application
+     */
+    val title : String
+        get() = meta.name
+
+    /**
+     * The string used as the sub-title, we currently use the author
+     */
+    val subTitle : String?
+        get() = meta.author
+
+    /**
+     * The URI of the application's image file
+     */
+    val uri : Uri
+        get() = meta.uri
+
+    /**
+     * The format of the application ROM as a string
+     */
+    private val type : String
+        get() = meta.format.name
+
+    /**
+     * The name and author is used as the key
+     */
+    override fun key() : String? {
+        return if (meta.author != null) meta.name + " " + meta.author else meta.name
+    }
+}
diff --git a/app/src/main/java/emu/skyline/data/BaseItem.kt b/app/src/main/java/emu/skyline/data/BaseItem.kt
new file mode 100644
index 00000000..8206caf0
--- /dev/null
+++ b/app/src/main/java/emu/skyline/data/BaseItem.kt
@@ -0,0 +1,19 @@
+/*
+ * SPDX-License-Identifier: MPL-2.0
+ * Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
+ */
+
+package emu.skyline.data
+
+import emu.skyline.adapter.BaseElement
+import emu.skyline.adapter.ElementType
+
+/**
+ * This is an abstract class that all adapter item classes inherit from
+ */
+abstract class BaseItem : BaseElement(ElementType.Item) {
+    /**
+     * This function returns a string used for searching
+     */
+    abstract fun key() : String?
+}
diff --git a/app/src/main/java/emu/skyline/loader/RomFile.kt b/app/src/main/java/emu/skyline/loader/RomFile.kt
index 98ca4e58..2189a875 100644
--- a/app/src/main/java/emu/skyline/loader/RomFile.kt
+++ b/app/src/main/java/emu/skyline/loader/RomFile.kt
@@ -13,7 +13,6 @@ import android.net.Uri
 import android.os.Build
 import android.os.ParcelFileDescriptor
 import android.provider.OpenableColumns
-import android.view.Surface
 import java.io.IOException
 import java.io.ObjectInputStream
 import java.io.ObjectOutputStream
@@ -23,12 +22,12 @@ import java.util.*
 /**
  * An enumeration of all supported ROM formats
  */
-enum class RomFormat(val format: Int){
-    NRO(0),
-    NSO(1),
-    NCA(2),
-    XCI(3),
-    NSP(4),
+enum class RomFormat(val extension : String) {
+    NRO("nro"),
+    NSO("nso"),
+    NCA("nca"),
+    XCI("xci"),
+    NSP("nsp"),
 }
 
 /**
@@ -185,7 +184,7 @@ internal class RomFile(val context : Context, val format : RomFormat, val file :
     fun getAppEntry(uri : Uri) : AppEntry {
         return if (hasAssets(instance)) {
             val rawIcon = getIcon(instance)
-            val icon = if (rawIcon.size != 0) BitmapFactory.decodeByteArray(rawIcon, 0, rawIcon.size) else null
+            val icon = if (rawIcon.isNotEmpty()) BitmapFactory.decodeByteArray(rawIcon, 0, rawIcon.size) else null
 
             AppEntry(getApplicationName(instance), getApplicationPublisher(instance), format, uri, icon)
         } else {
diff --git a/app/src/main/res/drawable/background_gradient.xml b/app/src/main/res/drawable/background_gradient.xml
new file mode 100644
index 00000000..2d6eebc0
--- /dev/null
+++ b/app/src/main/res/drawable/background_gradient.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <gradient
+            android:angle="270"
+            android:endColor="#80000000"
+            android:centerColor="#00000000"
+            android:startColor="#00000000"
+            android:type="linear" />
+</shape>
\ No newline at end of file
diff --git a/app/src/main/res/layout/app_item_grid.xml b/app/src/main/res/layout/app_item_grid.xml
index 8d023883..b79b30d9 100644
--- a/app/src/main/res/layout/app_item_grid.xml
+++ b/app/src/main/res/layout/app_item_grid.xml
@@ -1,21 +1,24 @@
 <?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:app="http://schemas.android.com/apk/res-auto"
+        xmlns:tools="http://schemas.android.com/tools"
         android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:gravity="center">
+        android:layout_height="wrap_content">
 
-    <androidx.cardview.widget.CardView xmlns:card_view="http://schemas.android.com/apk/res-auto"
-            xmlns:tools="http://schemas.android.com/tools"
+    <androidx.cardview.widget.CardView
             android:id="@+id/app_item_grid"
             android:layout_width="wrap_content"
             android:layout_height="match_parent"
-            android:layout_margin="15dp"
+            android:layout_gravity="center"
+            android:layout_margin="@dimen/app_card_margin_half"
             android:clickable="true"
             android:focusable="true"
             android:foreground="?attr/selectableItemBackground"
-            card_view:cardCornerRadius="4dp">
+            app:cardCornerRadius="4dp"
+            app:cardElevation="@dimen/app_card_margin"
+            app:cardUseCompatPadding="true">
 
-        <RelativeLayout
+        <LinearLayout
                 android:layout_width="155dp"
                 android:layout_height="wrap_content"
                 android:layout_gravity="center"
@@ -25,16 +28,13 @@
                     android:id="@+id/icon"
                     android:layout_width="match_parent"
                     android:layout_height="155dp"
-                    android:layout_alignParentTop="false"
-                    android:layout_centerHorizontal="true"
                     android:contentDescription="@string/icon"
-                    android:scaleType="centerCrop" />
+                    tools:src="@drawable/default_icon" />
 
             <TextView
                     android:id="@+id/text_title"
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
-                    android:layout_below="@id/icon"
                     android:ellipsize="marquee"
                     android:marqueeRepeatLimit="marquee_forever"
                     android:paddingStart="15dp"
@@ -43,14 +43,12 @@
                     android:singleLine="true"
                     android:textAlignment="center"
                     android:textAppearance="?android:attr/textAppearanceListItem"
-                    tools:ignore="RelativeOverlap" />
+                    tools:text="Title" />
 
             <TextView
                     android:id="@+id/text_subtitle"
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
-                    android:layout_below="@id/text_title"
-                    android:layout_alignStart="@id/text_title"
                     android:ellipsize="marquee"
                     android:fadingEdge="horizontal"
                     android:marqueeRepeatLimit="marquee_forever"
@@ -58,7 +56,8 @@
                     android:singleLine="true"
                     android:textAlignment="center"
                     android:textAppearance="?android:attr/textAppearanceListItemSecondary"
-                    android:textColor="@android:color/tertiary_text_light" />
-        </RelativeLayout>
+                    android:textColor="@android:color/tertiary_text_light"
+                    tools:text="Subtitle" />
+        </LinearLayout>
     </androidx.cardview.widget.CardView>
-</LinearLayout>
+</FrameLayout>
diff --git a/app/src/main/res/layout/app_item_grid_compact.xml b/app/src/main/res/layout/app_item_grid_compact.xml
new file mode 100644
index 00000000..a27fd687
--- /dev/null
+++ b/app/src/main/res/layout/app_item_grid_compact.xml
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:app="http://schemas.android.com/apk/res-auto"
+        xmlns:tools="http://schemas.android.com/tools"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content">
+
+    <androidx.cardview.widget.CardView
+            android:id="@+id/app_item_grid"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center"
+            android:layout_margin="@dimen/app_card_margin_half"
+            android:clickable="true"
+            android:focusable="true"
+            android:foreground="?attr/selectableItemBackground"
+            app:cardCornerRadius="4dp"
+            app:cardElevation="@dimen/app_card_margin"
+            app:cardUseCompatPadding="true">
+
+        <androidx.constraintlayout.widget.ConstraintLayout
+                android:layout_width="155dp"
+                android:layout_height="155dp">
+
+            <ImageView
+                    android:id="@+id/icon"
+                    android:layout_width="match_parent"
+                    android:layout_height="match_parent"
+                    android:layout_alignParentTop="false"
+                    android:layout_centerHorizontal="true"
+                    android:contentDescription="@string/icon"
+                    android:foreground="@drawable/background_gradient"
+                    app:layout_constraintBottom_toBottomOf="parent"
+                    app:layout_constraintEnd_toEndOf="parent"
+                    app:layout_constraintStart_toStartOf="parent"
+                    app:layout_constraintTop_toTopOf="parent"
+                    tools:src="@drawable/default_icon" />
+
+            <TextView
+                    android:id="@+id/text_title"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:alpha="242.25"
+                    android:ellipsize="marquee"
+                    android:marqueeRepeatLimit="marquee_forever"
+                    android:paddingStart="8dp"
+                    android:paddingEnd="8dp"
+                    android:singleLine="true"
+                    android:textAppearance="?android:attr/textAppearanceListItem"
+                    android:textColor="@android:color/white"
+                    android:textStyle="bold"
+                    app:layout_constrainedWidth="true"
+                    app:layout_constraintBottom_toTopOf="@id/text_subtitle"
+                    app:layout_constraintEnd_toEndOf="parent"
+                    app:layout_constraintHorizontal_bias="0"
+                    app:layout_constraintStart_toStartOf="parent"
+                    tools:text="Title" />
+
+            <TextView
+                    android:id="@+id/text_subtitle"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_marginBottom="8dp"
+                    android:alpha="242.25"
+                    android:ellipsize="marquee"
+                    android:fadingEdge="horizontal"
+                    android:marqueeRepeatLimit="marquee_forever"
+                    android:paddingStart="8dp"
+                    android:paddingEnd="8dp"
+                    android:singleLine="true"
+                    android:textAppearance="?android:attr/textAppearanceListItemSecondary"
+                    android:textColor="@android:color/white"
+                    app:layout_constrainedWidth="true"
+                    app:layout_constraintBottom_toBottomOf="parent"
+                    app:layout_constraintEnd_toEndOf="parent"
+                    app:layout_constraintHorizontal_bias="0"
+                    app:layout_constraintStart_toStartOf="parent"
+                    tools:text="Subtitle" />
+        </androidx.constraintlayout.widget.ConstraintLayout>
+    </androidx.cardview.widget.CardView>
+</FrameLayout>
diff --git a/app/src/main/res/layout/app_item_linear.xml b/app/src/main/res/layout/app_item_linear.xml
index c275b7e6..73d8aa55 100644
--- a/app/src/main/res/layout/app_item_linear.xml
+++ b/app/src/main/res/layout/app_item_linear.xml
@@ -1,40 +1,43 @@
 <?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:app="http://schemas.android.com/apk/res-auto"
         xmlns:tools="http://schemas.android.com/tools"
-        android:id="@+id/app_item_linear"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:background="?attr/selectableItemBackground"
         android:clickable="true"
         android:focusable="true"
-        android:orientation="vertical"
-        android:padding="15dp">
+        android:padding="16dp">
 
     <ImageView
             android:id="@+id/icon"
             android:layout_width="50dp"
             android:layout_height="50dp"
-            android:layout_alignParentStart="true"
-            android:layout_alignParentTop="false"
-            android:layout_centerVertical="true"
-            android:layout_marginEnd="10dp"
-            android:contentDescription="@string/icon" />
+            android:contentDescription="@string/icon"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toTopOf="parent"
+            tools:src="@drawable/default_icon" />
 
     <TextView
             android:id="@+id/text_title"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:layout_alignTop="@id/icon"
-            android:layout_toEndOf="@id/icon"
+            android:layout_marginStart="10dp"
             android:textAppearance="?android:attr/textAppearanceListItem"
-            tools:ignore="RelativeOverlap" />
+            app:layout_constraintBottom_toTopOf="@+id/text_subtitle"
+            app:layout_constraintStart_toEndOf="@id/icon"
+            app:layout_constraintTop_toTopOf="parent"
+            tools:text="Title" />
 
     <TextView
             android:id="@+id/text_subtitle"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:layout_below="@id/text_title"
-            android:layout_alignStart="@id/text_title"
+            android:layout_marginStart="10dp"
             android:textAppearance="?android:attr/textAppearanceListItemSecondary"
-            android:textColor="@android:color/tertiary_text_light" />
-</RelativeLayout>
+            android:textColor="@android:color/tertiary_text_light"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintStart_toEndOf="@id/icon"
+            app:layout_constraintTop_toBottomOf="@+id/text_title"
+            tools:text="SubTitle" />
+</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/app/src/main/res/values/array.xml b/app/src/main/res/values/array.xml
index 37bc2d27..ffba65c5 100644
--- a/app/src/main/res/values/array.xml
+++ b/app/src/main/res/values/array.xml
@@ -15,10 +15,12 @@
     <string-array name="layout_type">
         <item>List</item>
         <item>Grid</item>
+        <item>Grid Compact</item>
     </string-array>
     <string-array name="layout_type_val">
         <item>0</item>
         <item>1</item>
+        <item>2</item>
     </string-array>
     <string-array name="app_theme">
         <item>Light</item>
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
new file mode 100644
index 00000000..0e947602
--- /dev/null
+++ b/app/src/main/res/values/dimens.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <dimen name="app_card_margin">8dp</dimen>
+    <dimen name="app_card_margin_half">4dp</dimen>
+</resources>
\ No newline at end of file