Line data Source code
1 : // ignore_for_file: hash_and_equals 2 : 3 : import 'package:meta/meta.dart'; 4 : 5 : import 'providers_container.dart'; 6 : 7 : /// base class for all Providers 8 : 9 : abstract class BaseProvider<E, A> { 10 4 : BaseProvider( 11 : CreatorCallback<E, A> callback, { 12 : bool autoDispose = true, 13 4 : }) : _creator = Creator( 14 : callback, 15 : autoDispose, 16 : ); 17 : 18 : /// defines how an [E] is created 19 : late final Creator<E, A> _creator; 20 : 21 1 : @protected 22 1 : Creator<E, A> get creator => _creator; 23 : 24 : /// elements saved inside the [ProvidersContainer] 25 4 : @protected 26 : Map<String, Element> get containerElements => 27 8 : ProvidersContainer.instance.elements; 28 : 29 : /// For testing use this to override a provider behavior 30 1 : @protected 31 : @visibleForTesting 32 : void overrideCreator( 33 : CreatorCallback<E, A> callback, { 34 : bool? autoDispose, 35 : }) { 36 : // ignore: invalid_use_of_protected_member 37 2 : _creator.overrideCreator( 38 : callback, 39 : autoDispose: autoDispose, 40 : ); 41 : 42 3 : ProvidersContainer.instance.overriddenCreators.putIfAbsent( 43 2 : _creator.hashCode, 44 2 : () => _creator, 45 : ); 46 : } 47 : 48 : /// save arguments into the provider [Ref] 49 2 : void setArguments( 50 : A args, { 51 : String? tag, 52 : }) { 53 2 : final key = getKey(tag); 54 4 : final element = containerElements.putIfAbsent( 55 : key, 56 4 : () => Element<E>( 57 2 : ref: Ref<A>(tag: tag), 58 : ), 59 : ); 60 4 : element.ref.setArguments(args); 61 : } 62 : 63 : /// check if the current provider has a valid Element value into the 64 : ///[ProvidersContainer] 65 4 : bool mounted({ 66 : String? tag, 67 : }) { 68 16 : return containerElements[getKey(tag)]?.value != null; 69 : } 70 : 71 : /// return the [E] associated to the provider, if the [E] is not 72 : /// saved into the [ProvidersContainer] the Element will be created 73 4 : E read({ 74 : String? tag, 75 : }) { 76 4 : final key = getKey(tag); 77 8 : final element = containerElements[key] as Element<E>?; 78 4 : if (element?.value != null) { 79 4 : return element!.value!; 80 : } 81 : 82 6 : final ref = element?.ref as Ref<A>? ?? Ref<A>(tag: tag); 83 : 84 4 : final createdElement = element ?? Element(ref: ref); 85 : 86 4 : createdElement.set( 87 12 : _creator.callback(ref), 88 : ); 89 : 90 8 : containerElements[key] = createdElement; 91 4 : onElementValueAssigned( 92 : createdElement, 93 8 : _creator.autoDispose, 94 : ); 95 4 : return createdElement.value!; 96 : } 97 : 98 1 : @protected 99 : void onElementValueAssigned(Element<E> element, bool autoDispose) {} 100 : 101 : /// generate a key to be used into the [ProvidersContainer] 102 4 : @protected 103 : String getKey(String? tag) { 104 8 : return '$_cachedHash${tag ?? ''}'; 105 : } 106 : 107 4 : @mustCallSuper 108 : Element<E>? dispose({String? tag}) { 109 4 : if (mounted(tag: tag)) { 110 4 : final key = getKey(tag); 111 8 : final element = containerElements[key]!; 112 : // ignore: invalid_use_of_protected_member 113 8 : element.ref.dispose(); 114 : 115 8 : return containerElements.remove(key) as Element<E>; 116 : } 117 : return null; 118 : } 119 : 120 : // Custom implementation of hash code optimized for reading providers. 121 : @override // coverage:ignore-line 122 : int get hashCode => _cachedHash; // coverage:ignore-line 123 : final int _cachedHash = _nextHashCode = (_nextHashCode + 1) % 0xffffff; 124 : static int _nextHashCode = 1; 125 : }