diff --git a/app/src/main/java/com/example/nerbos/MainActivity.kt b/app/src/main/java/com/example/nerbos/MainActivity.kt
index 6d8eeeff1eb15860623002c357be67c0256fa461..7e20fe6bb5a6d5518bf8d2ec0cc7b3ee1ed679c2 100644
--- a/app/src/main/java/com/example/nerbos/MainActivity.kt
+++ b/app/src/main/java/com/example/nerbos/MainActivity.kt
@@ -7,6 +7,7 @@ import androidx.appcompat.app.AppCompatActivity
 import androidx.fragment.app.Fragment
 import com.example.nerbos.databinding.ActivityMainBinding
 import com.example.nerbos.fragments.scan.ScanFragment
+import com.example.nerbos.fragments.twibbon.TwibbonFragment
 import com.example.nerbos.fragments.statistic.StatisticFragment
 import com.example.nerbos.fragments.transaction.TransactionFragment
 import com.example.nerbos.fragments.user.UserFragment
@@ -18,12 +19,14 @@ class MainActivity : AppCompatActivity() {
     private val fragments = mapOf(
         R.id.transaction to TransactionFragment(),
         R.id.scan to ScanFragment(),
+        R.id.twibbon to TwibbonFragment(),
         R.id.statistic to StatisticFragment(),
         R.id.user to UserFragment()
     )
     private val fragmentTitles = mapOf(
         R.id.transaction to R.string.navbar_transaction,
         R.id.scan to R.string.navbar_scan,
+        R.id.twibbon to R.string.navbar_twibbon,
         R.id.statistic to R.string.navbar_statistic,
         R.id.user to R.string.navbar_user
     )
diff --git a/app/src/main/java/com/example/nerbos/fragments/scan/ScanFragment.kt b/app/src/main/java/com/example/nerbos/fragments/scan/ScanFragment.kt
index f4c1d9c548598f2a0ce589070244d120c0c90651..81bedaa9f664cf07f7ec62551c6b819aba39ffb5 100644
--- a/app/src/main/java/com/example/nerbos/fragments/scan/ScanFragment.kt
+++ b/app/src/main/java/com/example/nerbos/fragments/scan/ScanFragment.kt
@@ -2,7 +2,6 @@ package com.example.nerbos.fragments.scan
 
 import android.Manifest
 import android.app.Activity
-import android.content.Context
 import android.content.Intent
 import android.content.pm.PackageManager
 import android.graphics.Bitmap
@@ -68,23 +67,11 @@ class ScanFragment : Fragment() {
     private lateinit var fusedLocationProviderClient: FusedLocationProviderClient
     private lateinit var geocoder: Geocoder
     private var networkManagerService: NetworkManagerService = NetworkManagerService()
-    private var fragmentContext: Context? = null
-
     private val requestCameraPermissionCode = Manifest.permission.CAMERA
     private val uploadURL: String by lazy {
         requireContext().getString(R.string.backend_api_scan)
     }
 
-    override fun onAttach(context: Context) {
-        super.onAttach(context)
-        fragmentContext = context
-    }
-
-    override fun onDetach() {
-        super.onDetach()
-        fragmentContext = null
-    }
-
     override fun onCreateView(
         inflater: LayoutInflater, container: ViewGroup?,
         savedInstanceState: Bundle?
diff --git a/app/src/main/java/com/example/nerbos/fragments/twibbon/TwibbonFragment.kt b/app/src/main/java/com/example/nerbos/fragments/twibbon/TwibbonFragment.kt
new file mode 100644
index 0000000000000000000000000000000000000000..1cd5e7ecadeb8b0dd4bae53fe2eae5887b9444f4
--- /dev/null
+++ b/app/src/main/java/com/example/nerbos/fragments/twibbon/TwibbonFragment.kt
@@ -0,0 +1,349 @@
+package com.example.nerbos.fragments.twibbon
+
+import android.Manifest
+import android.content.ContentValues
+import android.content.pm.PackageManager
+import android.graphics.Bitmap
+import android.graphics.BitmapFactory
+import android.graphics.Canvas
+import android.graphics.Matrix
+import android.graphics.Paint
+import android.os.Bundle
+import android.os.Handler
+import android.os.Looper
+import android.provider.MediaStore
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.EditText
+import android.widget.ImageButton
+import android.widget.ImageView
+import android.widget.Toast
+import androidx.activity.result.contract.ActivityResultContracts
+import androidx.appcompat.app.AlertDialog
+import androidx.camera.core.CameraSelector
+import androidx.camera.core.ImageCapture
+import androidx.camera.core.ImageCaptureException
+import androidx.camera.core.Preview
+import androidx.camera.lifecycle.ProcessCameraProvider
+import androidx.camera.view.PreviewView
+import androidx.core.content.ContextCompat
+import androidx.core.net.toUri
+import androidx.exifinterface.media.ExifInterface
+import androidx.fragment.app.Fragment
+import com.example.nerbos.R
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import java.io.File
+import java.io.IOException
+import java.util.concurrent.ExecutorService
+import java.util.concurrent.Executors
+
+class TwibbonFragment : Fragment() {
+
+    private lateinit var previewView: PreviewView
+    private lateinit var cameraExecutor: ExecutorService
+    private lateinit var imageCapture: ImageCapture
+    private lateinit var twibbonImageView: ImageView
+    private var currentTwibbonIndex = 0
+    private val twibbonTemplates = arrayOf(
+        R.drawable.twibbon_template_1,
+        R.drawable.twibbon_template_2,
+        R.drawable.twibbon_template_3,
+        R.drawable.twibbon_template_4,
+        R.drawable.twibbon_template_5
+    )
+    private val requestCameraPermissionCode = Manifest.permission.CAMERA
+
+    override fun onCreateView(
+        inflater: LayoutInflater, container: ViewGroup?,
+        savedInstanceState: Bundle?
+    ): View? {
+        // Inflate the layout for this fragment
+        val view = inflater.inflate(R.layout.fragment_twibbon, container, false)
+        previewView = view.findViewById(R.id.previewView)
+        twibbonImageView = view.findViewById(R.id.twibbonImageView)
+        return view
+    }
+
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        super.onViewCreated(view, savedInstanceState)
+        cameraExecutor = Executors.newSingleThreadExecutor()
+
+        if (allPermissionsGranted()) {
+            startCamera()
+        } else {
+            requestCameraPermission.launch(requestCameraPermissionCode)
+        }
+
+        view.findViewById<ImageButton>(R.id.captureButton).setOnClickListener {
+            takePicture()
+        }
+
+        view.findViewById<ImageButton>(R.id.leftButton).setOnClickListener {
+            currentTwibbonIndex = (currentTwibbonIndex - 1 + twibbonTemplates.size) % twibbonTemplates.size
+            updateTwibbonTemplate()
+        }
+
+        view.findViewById<ImageButton>(R.id.rightButton).setOnClickListener {
+            currentTwibbonIndex = (currentTwibbonIndex + 1) % twibbonTemplates.size
+            updateTwibbonTemplate()
+        }
+    }
+
+    private fun updateTwibbonTemplate() {
+        twibbonImageView.setImageResource(twibbonTemplates[currentTwibbonIndex])
+    }
+
+    private fun allPermissionsGranted() = ContextCompat.checkSelfPermission(
+        requireContext(),
+        Manifest.permission.CAMERA
+    ) == PackageManager.PERMISSION_GRANTED
+
+    private fun startCamera() {
+        val cameraProviderFuture = ProcessCameraProvider.getInstance(requireContext())
+
+        cameraProviderFuture.addListener({
+            val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()
+
+            val preview = Preview.Builder()
+                .build()
+                .also {
+                    it.setSurfaceProvider(previewView.surfaceProvider)
+                }
+
+            imageCapture = ImageCapture.Builder().build()
+
+            val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
+
+            try {
+                cameraProvider.unbindAll()
+                cameraProvider.bindToLifecycle(this, cameraSelector, preview, imageCapture)
+            } catch (e: Exception) {
+                e.printStackTrace()
+            }
+
+        }, ContextCompat.getMainExecutor(requireContext()))
+    }
+
+    private fun takePicture() {
+        val imageCapture = imageCapture
+
+        // Create output file to hold the captured image
+        val externalFilesDirs = requireContext().getExternalFilesDirs(null)
+        val photoFile = File(externalFilesDirs.firstOrNull(), "${System.currentTimeMillis()}.jpg")
+
+        // Setup image capture metadata
+        val outputOptions = ImageCapture.OutputFileOptions.Builder(photoFile).build()
+
+        // Capture the image
+        imageCapture.takePicture(
+            outputOptions,
+            ContextCompat.getMainExecutor(requireContext()),
+            object : ImageCapture.OnImageSavedCallback {
+                override fun onError(exc: ImageCaptureException) {
+                    Toast.makeText(requireContext(), "Error capturing image: ${exc.message}", Toast.LENGTH_SHORT).show()
+                }
+
+                override fun onImageSaved(output: ImageCapture.OutputFileResults) {
+                    // Image captured successfully, read orientation metadata
+                    val savedUri = photoFile.toUri()
+                    val cameraBitmap = BitmapFactory.decodeFile(savedUri.path)
+                    val rotatedCameraBitmap = savedUri.path?.let {
+                        rotateImageIfRequired(cameraBitmap,
+                            it
+                        )
+                    }
+                    val twibbonBitmap = BitmapFactory.decodeResource(resources, twibbonTemplates[currentTwibbonIndex])
+
+                    val combinedBitmap = overlayBitmap(rotatedCameraBitmap!!, twibbonBitmap)
+                    showImagePopup(combinedBitmap)
+                }
+            })
+    }
+
+    private fun overlayBitmap(cameraBitmap: Bitmap, twibbonBitmap: Bitmap): Bitmap {
+        // Determine the side length of the square image
+        val sideLength = minOf(cameraBitmap.width, cameraBitmap.height)
+
+        // Calculate the position to draw the twibbon image to center it
+        val left = (cameraBitmap.width - sideLength) / 2
+        val top = (cameraBitmap.height - sideLength) / 2
+
+        // Crop or resize the camera image to make it square
+        val croppedCameraBitmap = Bitmap.createBitmap(cameraBitmap, 0, 0, sideLength, sideLength)
+
+        // Resize the twibbon image to match the dimensions of the cropped camera image
+        val resizedTwibbonBitmap = Bitmap.createScaledBitmap(twibbonBitmap, sideLength, sideLength, true)
+
+        // Create a new bitmap with the combined images
+        val combinedBitmap = Bitmap.createBitmap(cameraBitmap.width, cameraBitmap.height, Bitmap.Config.ARGB_8888)
+        val canvas = Canvas(combinedBitmap)
+        val paint = Paint(Paint.FILTER_BITMAP_FLAG)
+
+        // Draw the cropped camera image onto the canvas
+        canvas.drawBitmap(croppedCameraBitmap, Matrix(), paint)
+
+        // Draw the resized twibbon image onto the canvas at the calculated position
+        canvas.drawBitmap(resizedTwibbonBitmap, left.toFloat(), top.toFloat(), paint)
+
+        return combinedBitmap
+    }
+
+    private fun rotateImageIfRequired(bitmap: Bitmap, path: String): Bitmap {
+        val ei = ExifInterface(path)
+        val orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL)
+
+        return when (orientation) {
+            ExifInterface.ORIENTATION_ROTATE_90 -> rotateImage(bitmap, 90f)
+            ExifInterface.ORIENTATION_ROTATE_180 -> rotateImage(bitmap, 180f)
+            ExifInterface.ORIENTATION_ROTATE_270 -> rotateImage(bitmap, 270f)
+            else -> bitmap
+        }
+    }
+
+    private fun rotateImage(source: Bitmap, angle: Float): Bitmap {
+        val matrix = Matrix()
+        matrix.postRotate(angle)
+        return Bitmap.createBitmap(source, 0, 0, source.width, source.height, matrix, true)
+    }
+
+    private fun showImagePopup(imageBitmap: Bitmap?) {
+        if (imageBitmap != null) {
+            MaterialAlertDialogBuilder(requireContext())
+                .setTitle("Save this picture?")
+                .setPositiveButton("Yes") { dialog, _ ->
+                    showFilenameInputDialog(imageBitmap)
+                    dialog.dismiss()
+                }
+                .setNegativeButton("No") { dialog, _ ->
+                    dialog.dismiss()
+                }
+                .setView(ImageView(requireContext()).apply {
+                    setImageBitmap(imageBitmap)
+                    adjustViewBounds = true
+                })
+                .show()
+                .apply {
+                    getButton(AlertDialog.BUTTON_POSITIVE)?.setTextColor(
+                        ContextCompat.getColor(
+                            requireContext(),
+                            R.color.white
+                        )
+                    )
+                    getButton(AlertDialog.BUTTON_NEGATIVE)?.setTextColor(
+                        ContextCompat.getColor(
+                            requireContext(),
+                            R.color.white
+                        )
+                    )
+                }
+        } else {
+            showToastOnUIThread("Failed to load image")
+        }
+    }
+
+    private fun showFilenameInputDialog(imageBitmap: Bitmap) {
+        val inputView = LayoutInflater.from(requireContext()).inflate(R.layout.twibbon_filename, null)
+        val filenameEditText = inputView.findViewById<EditText>(R.id.filenameInput)
+
+        MaterialAlertDialogBuilder(requireContext())
+            .setTitle("Save Image")
+            .setView(inputView)
+            .setPositiveButton("Save") { dialog, _ ->
+                val filename = filenameEditText.text.toString().trim()
+                if (filename.isNotEmpty()) {
+                    saveImage(imageBitmap, filename)
+                } else {
+                    Toast.makeText(requireContext(), "Please enter a filename", Toast.LENGTH_SHORT).show()
+                    showFilenameInputDialog(imageBitmap)
+                }
+                dialog.dismiss()
+            }
+            .setNegativeButton("Cancel") { dialog, _ ->
+                dialog.dismiss()
+            }
+            .show()
+            .apply {
+                getButton(AlertDialog.BUTTON_POSITIVE)?.setTextColor(
+                    ContextCompat.getColor(
+                        requireContext(),
+                        R.color.white
+                    )
+                )
+                getButton(AlertDialog.BUTTON_NEGATIVE)?.setTextColor(
+                    ContextCompat.getColor(
+                        requireContext(),
+                        R.color.white
+                    )
+                )
+            }
+    }
+
+    private fun saveImage(imageBitmap: Bitmap, filename: String) {
+        // Crop the image to a square (1:1 aspect ratio)
+        val croppedImage = if (imageBitmap.width >= imageBitmap.height) {
+            Bitmap.createBitmap(
+                imageBitmap,
+                (imageBitmap.width - imageBitmap.height) / 2,
+                0,
+                imageBitmap.height,
+                imageBitmap.height
+            )
+        } else {
+            Bitmap.createBitmap(
+                imageBitmap,
+                0,
+                (imageBitmap.height - imageBitmap.width) / 2,
+                imageBitmap.width,
+                imageBitmap.width
+            )
+        }
+
+        // Prepare values for saving the image
+        val contentValues = ContentValues().apply {
+            put(MediaStore.Images.Media.DISPLAY_NAME, "$filename.jpg")
+            put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg")
+        }
+
+        // Insert the image into MediaStore and get its URI
+        val resolver = requireContext().contentResolver
+        val uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)
+
+        try {
+            // Save the image to the specified URI
+            if (uri != null) {
+                resolver.openOutputStream(uri)?.use { outputStream ->
+                    croppedImage.compress(Bitmap.CompressFormat.JPEG, 100, outputStream)
+                    outputStream.close()
+                    Toast.makeText(requireContext(), "Twibbon saved successfully", Toast.LENGTH_SHORT).show()
+                }
+            } else {
+                showToastOnUIThread("Failed to save image")
+            }
+        } catch (e: IOException) {
+            e.printStackTrace()
+            showToastOnUIThread("Failed to save image")
+        }
+    }
+
+    private fun showToastOnUIThread(message: String) {
+        Handler(Looper.getMainLooper()).post {
+            Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT).show()
+        }
+    }
+
+    private val requestCameraPermission =
+        registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
+            if (isGranted) {
+                startCamera()
+            } else {
+                // Handle the case where the user denied the permission
+                Toast.makeText(requireContext(), "Camera permission denied", Toast.LENGTH_SHORT).show()
+            }
+        }
+
+    override fun onDestroy() {
+        super.onDestroy()
+        cameraExecutor.shutdown()
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_camera.xml b/app/src/main/res/drawable/ic_camera.xml
new file mode 100644
index 0000000000000000000000000000000000000000..0ef209cb5eea5084b96347ca94d7a76385da450e
--- /dev/null
+++ b/app/src/main/res/drawable/ic_camera.xml
@@ -0,0 +1,8 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:height="25dp" android:viewportHeight="20" android:viewportWidth="20" android:width="25dp">
+      
+    <path android:fillColor="#7B78AA" android:pathData="M9.4,7H17.4C16.95,5.85 16.263,4.862 15.338,4.037C14.413,3.212 13.351,2.633 12.15,2.3L9.4,7ZM7.1,9L11.1,2.1C10.917,2.067 10.733,2.042 10.55,2.025C10.367,2.008 10.183,2 10,2C8.9,2 7.875,2.208 6.925,2.625C5.975,3.042 5.133,3.6 4.4,4.3L7.1,9ZM2.25,12H7.7L3.7,5.1C3.167,5.783 2.75,6.538 2.45,7.363C2.15,8.188 2,9.067 2,10C2,10.35 2.021,10.688 2.063,11.013C2.105,11.338 2.167,11.667 2.25,12ZM7.85,17.7L10.55,13H2.6C3.05,14.15 3.738,15.138 4.663,15.963C5.588,16.788 6.651,17.367 7.85,17.7ZM10,18C11.1,18 12.125,17.792 13.075,17.375C14.025,16.958 14.867,16.4 15.6,15.7L12.9,11L8.9,17.9C9.083,17.933 9.263,17.958 9.438,17.975C9.613,17.992 9.801,18 10,18ZM16.3,14.9C16.833,14.217 17.25,13.463 17.55,12.638C17.85,11.813 18,10.934 18,10C18,9.65 17.979,9.313 17.938,8.988C17.897,8.663 17.834,8.334 17.75,8H12.3L16.3,14.9ZM10,20C8.633,20 7.342,19.737 6.125,19.212C4.908,18.687 3.846,17.97 2.938,17.062C2.029,16.154 1.313,15.092 0.788,13.875C0.263,12.658 0.001,11.367 0,10C0,8.617 0.263,7.321 0.788,6.113C1.313,4.905 2.03,3.847 2.938,2.938C3.846,2.029 4.908,1.313 6.124,0.788C7.34,0.263 8.632,0.001 10,0C11.383,0 12.679,0.263 13.888,0.788C15.097,1.313 16.155,2.03 17.062,2.938C17.971,3.846 18.687,4.904 19.212,6.113C19.737,7.322 19.999,8.617 20,10C20,11.367 19.737,12.658 19.212,13.875C18.687,15.092 17.97,16.154 17.062,17.063C16.154,17.971 15.096,18.688 13.887,19.213C12.678,19.738 11.383,20.001 10,20Z"
+        tools:ignore="VectorPath" />
+    
+</vector>
diff --git a/app/src/main/res/drawable/twibbon_template_1.png b/app/src/main/res/drawable/twibbon_template_1.png
new file mode 100644
index 0000000000000000000000000000000000000000..850e7da08ddd1d6542627a5226a7c7149dcacac6
Binary files /dev/null and b/app/src/main/res/drawable/twibbon_template_1.png differ
diff --git a/app/src/main/res/drawable/twibbon_template_2.png b/app/src/main/res/drawable/twibbon_template_2.png
new file mode 100644
index 0000000000000000000000000000000000000000..14fe16aa23c5428fb76acaf50ad08924d1335bee
Binary files /dev/null and b/app/src/main/res/drawable/twibbon_template_2.png differ
diff --git a/app/src/main/res/drawable/twibbon_template_3.png b/app/src/main/res/drawable/twibbon_template_3.png
new file mode 100644
index 0000000000000000000000000000000000000000..b05ac30b781b3f3cddcb92d95260df520284ef28
Binary files /dev/null and b/app/src/main/res/drawable/twibbon_template_3.png differ
diff --git a/app/src/main/res/drawable/twibbon_template_4.png b/app/src/main/res/drawable/twibbon_template_4.png
new file mode 100644
index 0000000000000000000000000000000000000000..c1f89df8100f4fb1f9c121df2f8f7d5a58033364
Binary files /dev/null and b/app/src/main/res/drawable/twibbon_template_4.png differ
diff --git a/app/src/main/res/drawable/twibbon_template_5.png b/app/src/main/res/drawable/twibbon_template_5.png
new file mode 100644
index 0000000000000000000000000000000000000000..ce6de569876dc13b115ce2606052c2bcae6e25d8
Binary files /dev/null and b/app/src/main/res/drawable/twibbon_template_5.png differ
diff --git a/app/src/main/res/layout-land/activity_main.xml b/app/src/main/res/layout-land/activity_main.xml
index 73537e63124d0ee65fe692acbf7096989604395b..8990f7d29bc6aed64acbd43bd1a02296e23fddd8 100644
--- a/app/src/main/res/layout-land/activity_main.xml
+++ b/app/src/main/res/layout-land/activity_main.xml
@@ -44,7 +44,7 @@
         android:layout_width="80dp"
         android:layout_height="0dp"
         android:orientation="vertical"
-        android:paddingTop="60dp"
+        android:paddingTop="40dp"
         android:background="@color/navbar_bg"
         app:itemBackground="@color/navbar_bg"
         app:itemIconTint="@color/navbar_icon"
diff --git a/app/src/main/res/layout-land/fragment_twibbon.xml b/app/src/main/res/layout-land/fragment_twibbon.xml
new file mode 100644
index 0000000000000000000000000000000000000000..aecb60af05e93f8c3fdb0092731bb556e97adb3d
--- /dev/null
+++ b/app/src/main/res/layout-land/fragment_twibbon.xml
@@ -0,0 +1,101 @@
+<?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="match_parent"
+    android:background="@color/primary_bg"
+    android:orientation="vertical"
+    tools:context=".fragments.twibbon.TwibbonFragment">
+
+    <androidx.constraintlayout.widget.ConstraintLayout
+        android:id="@+id/twibbonConstrantLayout"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+
+        <LinearLayout
+            android:id="@+id/scanHorizontalLayout"
+            android:layout_width="0dp"
+            android:layout_height="match_parent"
+            android:orientation="horizontal"
+            app:layout_constraintTop_toTopOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintEnd_toStartOf="@id/captureButton"
+            app:layout_constraintBottom_toBottomOf="parent"
+            android:layout_marginStart="50dp"
+            android:layout_gravity="center">
+
+            <ImageButton
+                android:id="@+id/leftButton"
+                android:layout_width="0dp"
+                android:layout_height="35dp"
+                android:layout_weight="1"
+                android:layout_gravity="start|center"
+                app:layout_constraintStart_toStartOf="parent"
+                app:layout_constraintEnd_toStartOf="@id/previewView"
+                android:background="@color/transparent"
+                android:layout_marginStart="50dp"
+                android:scaleType="fitCenter"
+                app:srcCompat="@drawable/ic_back"
+                android:contentDescription="@string/left_arrow" />
+
+            <FrameLayout
+                android:layout_width="300dp"
+                android:layout_height="300dp"
+                app:layout_constraintStart_toStartOf="parent"
+                app:layout_constraintEnd_toEndOf="parent"
+                app:layout_constraintTop_toTopOf="parent"
+                app:layout_constraintBottom_toBottomOf="parent"
+                android:layout_gravity="center" >
+
+                <androidx.camera.view.PreviewView
+                    android:id="@+id/previewView"
+                    android:layout_width="match_parent"
+                    android:layout_height="match_parent"
+                    android:layout_gravity="center" />
+
+                <ImageView
+                    android:id="@+id/twibbonImageView"
+                    android:layout_width="match_parent"
+                    android:layout_height="match_parent"
+                    android:scaleType="fitXY"
+                    android:contentDescription="@string/twibbon_preview"
+                    app:srcCompat="@drawable/twibbon_template_1" />
+
+            </FrameLayout>
+
+            <ImageButton
+                android:id="@+id/rightButton"
+                android:layout_width="0dp"
+                android:layout_height="35dp"
+                android:layout_weight="1"
+                android:layout_gravity="end|center"
+                app:layout_constraintEnd_toEndOf="parent"
+                app:layout_constraintStart_toEndOf="@id/previewView"
+                android:background="@color/transparent"
+                android:layout_marginEnd="50dp"
+                android:rotation="180"
+                android:scaleType="fitCenter"
+                app:srcCompat="@drawable/ic_back"
+                android:contentDescription="@string/right_arrow" />
+        </LinearLayout>
+
+        <ImageButton
+            android:id="@+id/captureButton"
+            android:layout_width="75dp"
+            android:layout_height="75dp"
+            android:layout_gravity="center"
+            android:layout_marginEnd="75dp"
+            android:background="@drawable/round_corner_button_weak"
+            android:contentDescription="@string/capture_button"
+            android:scaleType="fitCenter"
+            app:layout_constraintStart_toEndOf="@id/scanHorizontalLayout"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintTop_toTopOf="parent"
+            android:src="@android:drawable/ic_menu_camera"
+            tools:ignore="RedundantDescriptionCheck" />
+
+    </androidx.constraintlayout.widget.ConstraintLayout>
+
+</FrameLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_twibbon.xml b/app/src/main/res/layout/fragment_twibbon.xml
new file mode 100644
index 0000000000000000000000000000000000000000..950dfce9f19885a8431162842db0f3837d29dc81
--- /dev/null
+++ b/app/src/main/res/layout/fragment_twibbon.xml
@@ -0,0 +1,100 @@
+<?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="match_parent"
+    android:background="@color/primary_bg"
+    android:orientation="vertical"
+    tools:context=".fragments.twibbon.TwibbonFragment">
+
+    <androidx.constraintlayout.widget.ConstraintLayout
+        android:id="@+id/twibbonConstrantLayout"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+
+        <LinearLayout
+            android:id="@+id/scanHorizontalLayout"
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            android:orientation="horizontal"
+            app:layout_constraintTop_toTopOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintBottom_toTopOf="@id/captureButton"
+            android:layout_marginTop="50dp"
+            android:layout_marginBottom="50dp"
+            android:layout_gravity="center">
+
+            <ImageButton
+                android:id="@+id/leftButton"
+                android:layout_width="0dp"
+                android:layout_height="35dp"
+                android:layout_weight="1"
+                android:layout_gravity="start|center"
+                app:layout_constraintStart_toStartOf="parent"
+                app:layout_constraintEnd_toStartOf="@id/previewView"
+                android:background="@color/transparent"
+                android:layout_marginStart="20dp"
+                android:scaleType="fitCenter"
+                app:srcCompat="@drawable/ic_back"
+                android:contentDescription="@string/left_arrow" />
+
+            <FrameLayout
+                android:layout_width="300dp"
+                android:layout_height="300dp"
+                app:layout_constraintStart_toStartOf="parent"
+                app:layout_constraintEnd_toEndOf="parent"
+                android:layout_gravity="center" >
+
+                <androidx.camera.view.PreviewView
+                    android:id="@+id/previewView"
+                    android:layout_width="match_parent"
+                    android:layout_height="match_parent"
+                    android:layout_gravity="center" />
+
+                <ImageView
+                    android:id="@+id/twibbonImageView"
+                    android:layout_width="match_parent"
+                    android:layout_height="match_parent"
+                    android:contentDescription="@string/twibbon_preview"
+                    android:scaleType="fitXY"
+                    app:srcCompat="@drawable/twibbon_template_1" />
+
+            </FrameLayout>
+
+            <ImageButton
+                android:id="@+id/rightButton"
+                android:layout_width="0dp"
+                android:layout_height="35dp"
+                android:layout_weight="1"
+                android:layout_gravity="end|center"
+                app:layout_constraintEnd_toEndOf="parent"
+                app:layout_constraintStart_toEndOf="@id/previewView"
+                android:background="@color/transparent"
+                android:layout_marginEnd="20dp"
+                android:rotation="180"
+                android:scaleType="fitCenter"
+                app:srcCompat="@drawable/ic_back"
+                android:contentDescription="@string/right_arrow" />
+        </LinearLayout>
+
+        <ImageButton
+            android:id="@+id/captureButton"
+            android:layout_width="75dp"
+            android:layout_height="75dp"
+            android:layout_gravity="center"
+            android:layout_marginBottom="100dp"
+            android:background="@drawable/round_corner_button_weak"
+            android:contentDescription="@string/capture_button"
+            android:scaleType="fitCenter"
+            app:layout_constraintTop_toBottomOf="@id/scanHorizontalLayout"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintBottom_toBottomOf="parent"
+            android:src="@android:drawable/ic_menu_camera"
+            tools:ignore="RedundantDescriptionCheck" />
+
+    </androidx.constraintlayout.widget.ConstraintLayout>
+
+</FrameLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/twibbon_filename.xml b/app/src/main/res/layout/twibbon_filename.xml
new file mode 100644
index 0000000000000000000000000000000000000000..b149e2a22d81053dba6a40198bd65da98ffa4511
--- /dev/null
+++ b/app/src/main/res/layout/twibbon_filename.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical"
+    android:padding="16dp">
+
+    <EditText
+        android:id="@+id/filenameInput"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:hint="@string/name"
+        android:inputType="text"
+        android:autofillHints="Twibbon Filename" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/app/src/main/res/menu/bottom_navbar.xml b/app/src/main/res/menu/bottom_navbar.xml
index 538d095be0d805970514b71b2619e143c4db09c2..4b073f0cc6853ed0bb39422996b9872594eafc14 100644
--- a/app/src/main/res/menu/bottom_navbar.xml
+++ b/app/src/main/res/menu/bottom_navbar.xml
@@ -6,6 +6,9 @@
     <item android:title="@string/navbar_scan"
         android:id="@+id/scan"
         android:icon="@drawable/ic_scan"/>
+    <item android:title="@string/navbar_twibbon"
+        android:id="@+id/twibbon"
+        android:icon="@drawable/ic_camera"/>
     <item android:title="@string/navbar_statistic"
         android:id="@+id/statistic"
         android:icon="@drawable/ic_statistic"/>
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index ebab2ec94a85baefa1fdfb70130d6d4f05b6f469..0fdc113eb07c5459bf6fe24290ecbd1b1a226c42 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -70,5 +70,9 @@
     <string name="back_button">Back Button</string>
     <string name="autofill_location_button">AutoFill Location Button</string>
     <string name="randomize_transaction_button">Randomize Transaction Button</string>
+    <string name="navbar_twibbon">Twibbon</string>
+    <string name="left_arrow">Left Arrow</string>
+    <string name="right_arrow">Right Arrow</string>
+    <string name="twibbon_preview">Twibbon Preview</string>
 
 </resources>
\ No newline at end of file