 
     // MARK: - Properties - Cell Swipe Actions
 
+    fileprivate struct CellSwipeData {
+        var activelyPannedCellIndexPath: IndexPath? // `IndexPath` of actively panned or open or opening cell
+        var activelyPannedCellTranslationX: CGFloat? // current translation on x-axis of open or opening cell
+
+        func activeCell(in collectionView: UICollectionView) -> NotificationsCenterCell? {
+            guard let activelyPannedCellIndexPath = activelyPannedCellIndexPath else {
+                return nil
+            }
+
+            return collectionView.cellForItem(at: activelyPannedCellIndexPath) as? NotificationsCenterCell
+        }
+
+        mutating func resetActiveData() {
+            activelyPannedCellIndexPath = nil
+            activelyPannedCellTranslationX = nil
+        }
+    }
+
     fileprivate lazy var cellPanGestureRecognizer = UIPanGestureRecognizer()
-    fileprivate var activelyPannedCellIndexPath: IndexPath?
+    fileprivate lazy var cellSwipeData = CellSwipeData()
 
     // MARK: - Lifecycle
 

// MARK: - Cell Swipe Actions

@objc extension NotificationsCenterViewController: UIGestureRecognizerDelegate {

    /// Only allow cell pan gesture if user's horizontal cell panning behavior seems intentional
    func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {

        viewModel.refreshNotifications()
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        closeSwipeActionsPanelIfNecessary()
    }

    override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
        super.traitCollectionDidChange(previousTraitCollection)

        if previousTraitCollection?.preferredContentSizeCategory != traitCollection.preferredContentSizeCategory {
            closeSwipeActionsPanelIfNecessary()
            notificationsView.collectionView.reloadData()
        }
    }
