88
99const PackageJson = require ( '../../package.json' )
1010
11- const { MissingOrderError } = require ( '../util/error' )
11+ const {
12+ CharacterBasedDurationError,
13+ DurationGreaterThanMaxPossibleError,
14+ IconAdjustableError,
15+ MissingOrderError,
16+ ScreenHasVideoAreaError
17+ } = require ( '../util/error' )
18+ const screenDurationUtil = require ( '../util/screen-duration' )
1219const projectDataUtil = require ( '../util/project-data' )
1320
21+ const { AVERAGE_CHARS_IN_WORD } = require ( '../config/config' )
22+
1423class ProjectData {
1524 /**
1625 * @constructor
@@ -218,14 +227,18 @@ class ProjectData {
218227 /**
219228 * @param {Object } screen
220229 * @returns {Object }
221- * @description Construct screen.
230+ * @description Construct screen, adds methods to `screen` object .
222231 */
223232 constructScreen ( screen ) {
224233 const {
225234 id, characterBasedDuration, compositionName, duration, extraVideoSecond, gifBigPath, gifPath, gifThumbnailPath,
226235 hidden, iconAdjustable, isFull, maxDuration, order, path, tags, title, type, areas
227236 } = screen
228237
238+ /**
239+ * @namespace screen
240+ * @description The screen object with it's methods.
241+ */
229242 return {
230243 id,
231244 characterBasedDuration,
@@ -245,10 +258,81 @@ class ProjectData {
245258 title,
246259 type,
247260 areas,
248- getAreas : ( ) => {
249- return areas . map ( ( area ) => {
250- return this . constructArea ( area )
251- } )
261+ /**
262+ * @returns {Object }
263+ * @description Maps through areas array and adds it's methods.
264+ */
265+ getAreas : ( ) => areas . map ( ( area ) => this . constructArea ( area ) ) ,
266+ /**
267+ * @throws {ScreenHasVideoAreaError }
268+ * @return {Object.characterBasedDuration }
269+ * @description Checks if `screen` has video area, then throws error.
270+ * Otherwise returns `characterBasedDuration`.
271+ */
272+ isDurationAdjustable : ( ) => {
273+ const videoAreas = areas . filter ( ( area ) => area . type === 'video' )
274+
275+ if ( videoAreas . length > 0 ) {
276+ throw new ScreenHasVideoAreaError ( 'The screen has video area.' )
277+ }
278+
279+ return characterBasedDuration
280+ } ,
281+ /**
282+ * @return {number }
283+ * @description Calculates screen duration using screen duration utility.
284+ * Detailed description can be found in screen duration util.
285+ */
286+ calculateScreenDuration : ( ) => screenDurationUtil . getScreenDuration ( screen ) ,
287+ /**
288+ * @returns {number }
289+ * @description Filters ares to find only video ones.
290+ * Checks if count of video areas is more than 0, then counts sum of `wordCount`s.
291+ * Otherwise returns `maxDuration` or `duration`.
292+ */
293+ getMaxPossibleDuration : ( ) => {
294+ const videoAreas = areas . filter ( ( area ) => area . type === 'video' )
295+
296+ if ( videoAreas . length > 0 ) {
297+ return videoAreas . reduce ( ( acc , videoArea ) => acc + videoArea . wordCount , 0 )
298+ }
299+
300+ return maxDuration || duration
301+ } ,
302+ /**
303+ * @param {number } duration - The new duration to set.
304+ * @throws {CharacterBasedDurationError, DurationGreaterThanMaxPossibleError }
305+ * @description Checks if `characterBasedDuration` is falsy, then throws error.
306+ * If `duration` is more than maximum possible duration, then throws error.
307+ * Otherwise sets `selectedDuration`.
308+ */
309+ setDuration : function ( duration ) {
310+ if ( ! characterBasedDuration ) {
311+ throw new CharacterBasedDurationError ( 'Current screen\'s duration is not adjustable.' )
312+ }
313+
314+ if ( duration > this . getMaxPossibleDuration ( ) ) {
315+ throw new DurationGreaterThanMaxPossibleError ( 'Given `value` is greater than maximum possible duration.' )
316+ }
317+
318+ this . selectedDuration = duration
319+ } ,
320+ /**
321+ * @return {boolean }
322+ * @description Checks if icon position is adjustable by double negation.
323+ */
324+ isIconPositionAdjustable : ( ) => iconAdjustable ,
325+ /**
326+ * @throws {IconAdjustableError }
327+ * @description Checks if icon position is not adjustable then throws error.
328+ * Otherwise does `xor` bitwise operation with `iconAdjustable` and 3.
329+ * Number `3` stands for converting 1->2 and 2->1.
330+ */
331+ toggleIconPosition : function ( ) {
332+ if ( ! this . isIconPositionAdjustable ( ) ) {
333+ throw new IconAdjustableError ( 'Icon position is not adjustable.' )
334+ }
335+ this . iconAdjustable ^= 3
252336 }
253337 }
254338 }
@@ -271,6 +355,8 @@ class ProjectData {
271355 area . value = text
272356 this . patchProperties . push ( 'screens' )
273357 }
358+
359+ result . getRecommendedCharacterCount = ( ) => Math . floor ( parseInt ( wordCount ) * AVERAGE_CHARS_IN_WORD )
274360 }
275361
276362 if ( area . type === 'image' ) {
0 commit comments