1 /* 2 * Copyright 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.photopicker.core.selection 18 19 import com.android.photopicker.data.model.Grantable 20 21 /** 22 * A specialized set implementation that is aware of both user selections and pre-granted elements. 23 * 24 * This class extends the behavior of a standard set by incorporating pre-granted elements 25 * into its logic. An element is considered to be part of the set if either: 26 * 27 * 1. It has been explicitly selected by the user. 28 * 2. It is pre-granted and hasn't been explicitly de-selected by the user. 29 * 30 * **This class should be used for the following custom implementations :** 31 * - Provides an accurate `size` reflecting both selected and pre-granted elements. 32 * - `contains()` method which checks if the element should be reflected as selected on the UI. 33 * 34 * @property selection The set of elements explicitly selected by the user. 35 * @property deSelection The set of pre-granted elements that have been explicitly de-selected. 36 * @property preGrantedelementsCount The number of pre-granted elements (not including those in `deSelection`). 37 */ 38 class GrantsAwareSet<T : Grantable>( 39 val selection: Set<T>, 40 val deSelection: Set<T>, 41 val preGrantedelementsCount: Int = 0, 42 ) : Set<T> { 43 44 /** 45 * Size of the set based on current selection and preGranted elements. 46 */ 47 override val size: Int = selection.size - deSelection.size + preGrantedelementsCount 48 49 /** 50 * Checks if the set contains a specific element. 51 * 52 * This implementation considers two scenarios: 53 * 54 * 1. **Direct Presence in the Selection:** 55 * - Returns `true` if the `element` is directly present in the current user selection. 56 * 57 * 2. **Pre-Granted Media:** 58 * - If the `element` is a `Media` object: 59 * - Returns `true` if the `Media` is pre-granted (via `isPreGranted()`) AND 60 * it is not present in the deSelection set (i.e., the user has not explicitly 61 * de-selected it). 62 * 63 * @param element The element to check for. 64 * @return `true` if the element is considered to be in the set, `false` otherwise. 65 */ containsnull66 override fun contains(element: T): Boolean { 67 // Return true if the element to be checked is part of the selection list. 68 if (selection.contains(element)) { 69 return true 70 } 71 // If the element is preGranted and is not present in the deSelection set i.e. the element 72 // has not been de-selected by the user then return true. 73 if (element.isPreGranted && !deSelection.contains(element)) { 74 return true 75 } 76 return false 77 } 78 79 /** 80 * Returns true when: 81 * - No element has been selected by the user. 82 * - No preGranted elements are present for the current package and user. 83 * - If preGrants are present, all of them have been de-selected by the user. 84 * 85 * Returns false is all other cases. 86 */ isEmptynull87 override fun isEmpty(): Boolean { 88 return size == 0 89 } 90 91 /** 92 * Provides an iterator to iterated only over the current user selection. 93 * 94 * Does not include preGrants. 95 */ iteratornull96 override fun iterator(): Iterator<T> { 97 return selection.iterator() 98 } 99 100 /** 101 * Checks if all elements provided in the input are present in the set. 102 */ containsAllnull103 override fun containsAll(elements: Collection<T>): Boolean { 104 for (element in elements) { 105 if (!contains(element)) { 106 return false 107 } 108 } 109 return true 110 } 111 }