• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16class SynchedPropertyObjectOneWayPU<C extends Object>
17  extends ObservedPropertyObjectAbstractPU<C>
18  implements ISinglePropertyChangeSubscriber<C>, IMultiPropertiesChangeSubscriber {
19
20  private wrappedValue_: C;
21  private source_: ObservedPropertyAbstract<C>;
22
23  constructor(source: ObservedPropertyAbstract<C> | C,
24    owningChildView: IPropertySubscriber,
25    thisPropertyName: PropertyInfo) {
26    super(owningChildView, thisPropertyName);
27
28    if (source && (typeof (source) === "object") && ("notifyHasChanged" in source) && ("subscribeMe" in source)) {
29      // code path for @(Local)StorageProp
30      this.source_ = source as ObservedPropertyAbstract<C>;
31      // subscribe to receive value change updates from LocalStorage source property
32      this.source_.subscribeMe(this);
33    } else {
34      // code path for @Prop
35      if (!ObservedObject.IsObservedObject(source)) {
36        stateMgmtConsole.warn(`@Prop ${this.info()}  Provided source object's class
37           lacks @Observed class decorator. Object property changes will not be observed.`);
38      }
39
40      this.source_ = new ObservedPropertyObjectPU<C>(source as C, this, thisPropertyName);
41    }
42
43    // deep copy source Object and wrap it
44    this.setWrapperValue(this.source_.get());
45    stateMgmtConsole.debug(`SynchedPropertyObjectOneWayPU[${this.id__()}, '${this.info() || "unknown"}']: constructor ready with wrappedValue '${JSON.stringify(this.wrappedValue_)}'.`);
46  }
47
48  /*
49  like a destructor, need to call this before deleting
50  the property.
51  */
52  aboutToBeDeleted() {
53    if (this.source_) {
54      this.source_.unlinkSuscriber(this.id__());
55      this.source_ = undefined;
56    }
57    super.aboutToBeDeleted();
58  }
59
60
61  // this object is subscriber to this.source_
62  // when source notifies a property change, copy its value to local backing store
63  // the guard for newValue being an Object is needed because also property changes of wrappedValue_
64  // are notified via this function. We ignore those, these are handled correctly by propertyHasChanged
65  public hasChanged(newValue: C): void {
66    if (typeof newValue == "object") {
67      stateMgmtConsole.debug(`SynchedPropertyObjectOneWayPU[${this.id__()}, '${this.info() || "unknown"}']: hasChanged:  newValue '${JSON.stringify(newValue)}'.`);
68      this.setWrapperValue(newValue);
69      this.notifyHasChanged(ObservedObject.GetRawObject(this.wrappedValue_));
70    }
71  }
72
73  public propertyHasChanged(propName : string) : void {
74    stateMgmtConsole.debug(`SynchedPropertyObjectOneWayPU[${this.id__()}, '${this.info() || "unknown"}']: propertyHasChanged '${propName}'.`);
75    this.notifyHasChanged(ObservedObject.GetRawObject(this.wrappedValue_));
76  }
77
78  public getUnmonitored(): C {
79    stateMgmtConsole.debug(`SynchedPropertyObjectOneWayPU[${this.id__()}, '${this.info() || "unknown"}']: getUnmonitored returns '${JSON.stringify(this.wrappedValue_)}'.`);
80    // unmonitored get access , no call to notifyPropertyRead !
81    return this.wrappedValue_;
82  }
83
84  // get 'read through` from the ObservedObject
85  public get(): C {
86    stateMgmtConsole.debug(`SynchedPropertyObjectOneWayPU[${this.id__()}, '${this.info() || "unknown"}']: get returning ${JSON.stringify(this.wrappedValue_)}.`)
87    this.notifyPropertyRead();
88    return this.wrappedValue_;
89  }
90
91  // assignment to local variable in the form of this.aProp = <object value>
92  // set 'writes through` to the ObservedObject
93  public set(newValue: C): void {
94    if (this.wrappedValue_ == newValue) {
95      stateMgmtConsole.debug(`SynchedPropertyObjectOneWayPU[${this.id__()}IP, '${this.info() || "unknown"}']: set with unchanged value '${JSON.stringify(newValue)}'- ignoring.`);
96      return;
97    }
98
99    stateMgmtConsole.debug(`SynchedPropertyObjectOneWayPU[${this.id__()}, '${this.info() || "unknown"}']: set to newValue: '${JSON.stringify(newValue)}'.`);
100    if (!ObservedObject.IsObservedObject(newValue)) {
101      stateMgmtConsole.warn(`@Prop ${this.info()} Set: Provided new object's class
102         lacks @Observed class decorator. Object property changes will not be observed.`);
103    }
104
105    this.setWrapperValue(newValue);
106    this.notifyHasChanged(this.wrappedValue_);
107  }
108
109  public reset(sourceChangedValue: C): void {
110    stateMgmtConsole.debug(`SynchedPropertyObjectOneWayPU[${this.id__()}, '${this.info() || "unknown"}']: reset from '${JSON.stringify(this.wrappedValue_)}' to '${JSON.stringify(sourceChangedValue)}'.`);
111    // if set causes an actual change, then, ObservedPropertyObject source_ will call hasChanged
112    this.source_.set(sourceChangedValue);
113  }
114
115  private setWrapperValue(value: C): void {
116    let rawValue = ObservedObject.GetRawObject(value);
117    if (rawValue instanceof Array) {
118      this.wrappedValue_ = ObservedObject.createNew([ ...rawValue ], this);
119    } else {
120      this.wrappedValue_ = ObservedObject.createNew({ ...rawValue }, this);
121    }
122  }
123}
124