@applicaster/zapp-react-native-utils 13.0.0-alpha.3322736490 → 13.0.0-alpha.3332871333
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/appUtils/localizationsHelper.ts +30 -0
- package/appUtils/playerManager/usePlayerTitleSummaryOverlay.tsx +7 -1
- package/componentsUtils/__tests__/isFirstComponentGallery.test.ts +33 -0
- package/componentsUtils/__tests__/isFirstComponentScreenPicker.test.ts +33 -0
- package/componentsUtils/__tests__/isGallery.test.ts +33 -0
- package/componentsUtils/__tests__/isScreenPicker.test.ts +33 -0
- package/componentsUtils/index.ts +32 -0
- package/dateUtils/index.ts +17 -0
- package/localizationUtils/index.ts +5 -10
- package/manifestUtils/defaultManifestConfigurations/player.js +6 -0
- package/manifestUtils/keys.js +9 -0
- package/navigationUtils/__tests__/__snapshots__/navigationUtils.test.js.snap +1 -0
- package/navigationUtils/index.ts +3 -1
- package/package.json +2 -2
- package/playerUtils/configurationGenerator.ts +6 -0
- package/reactHooks/feed/useFeedLoader.tsx +13 -6
|
@@ -65,6 +65,36 @@ export function getUILanguage() {
|
|
|
65
65
|
return getLanguageCode();
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
+
/**
|
|
69
|
+
* fallback to en for missing dayjslocalization
|
|
70
|
+
* converts the locale code to a dayjs compatible locale code
|
|
71
|
+
* lowercase input code is expected, e.g. "en-GB" => "en-gb"
|
|
72
|
+
* @param {string} code - locale code, e.g. "en", "fr", "es-LA"
|
|
73
|
+
* */
|
|
74
|
+
export const toDayJSLocaleMap = (code) => {
|
|
75
|
+
const map = {
|
|
76
|
+
hy: "hy-am",
|
|
77
|
+
fj: null,
|
|
78
|
+
la: null,
|
|
79
|
+
no: null,
|
|
80
|
+
pa: "pa-in",
|
|
81
|
+
qu: null,
|
|
82
|
+
sm: null,
|
|
83
|
+
to: null,
|
|
84
|
+
xh: null,
|
|
85
|
+
"es-LA": "es",
|
|
86
|
+
"en-UK": "en-gb",
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
if (map[code] === null) {
|
|
90
|
+
return "en";
|
|
91
|
+
} else if (map[code]) {
|
|
92
|
+
return map[code];
|
|
93
|
+
} else {
|
|
94
|
+
return code;
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
|
|
68
98
|
/**
|
|
69
99
|
* returns the localization for the app based on the locale. If the locale is null
|
|
70
100
|
* or undefined, or if the given locale doesn't exist in the localizations,
|
|
@@ -3,12 +3,18 @@ import { OverlaysObserver } from "./OverlayObserver/OverlaysObserver";
|
|
|
3
3
|
import { useFeedLoader } from "../../reactHooks";
|
|
4
4
|
import { usePlayer } from "./usePlayer";
|
|
5
5
|
|
|
6
|
+
const getLiveUrl = (url: string) => {
|
|
7
|
+
// Use the replace method with a regular expression to replace all instances of subClass with livePage
|
|
8
|
+
return url.replace(new RegExp("subClass", "g"), "livePage");
|
|
9
|
+
};
|
|
10
|
+
|
|
6
11
|
export const useTitleSummaryOverlay = (
|
|
7
|
-
feedUrl,
|
|
8
12
|
entry,
|
|
9
13
|
isLive = false,
|
|
10
14
|
interval: number
|
|
11
15
|
) => {
|
|
16
|
+
// TODO: Have generic place for live url from configuration. Currently its hardcoded for client.
|
|
17
|
+
const feedUrl = getLiveUrl(entry?.extensions?.live?.channel_src ?? "");
|
|
12
18
|
const player = usePlayer();
|
|
13
19
|
const [title, setTitle] = useState<string | number>(entry?.title || "");
|
|
14
20
|
const [summary, setSummary] = useState<string | number>(entry?.summary || "");
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { isFirstComponentGallery } from "../index";
|
|
2
|
+
|
|
3
|
+
describe("isFirstComponentGallery", () => {
|
|
4
|
+
it("should return true if the first component is a gallery", () => {
|
|
5
|
+
const components = [
|
|
6
|
+
{ component_type: "gallery-qb" },
|
|
7
|
+
{ component_type: "other-component" },
|
|
8
|
+
];
|
|
9
|
+
|
|
10
|
+
expect(isFirstComponentGallery(components)).toBe(true);
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it("should return false if the first component is not a gallery", () => {
|
|
14
|
+
const components = [
|
|
15
|
+
{ component_type: "other-component" },
|
|
16
|
+
{ component_type: "gallery-qb" },
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
expect(isFirstComponentGallery(components)).toBe(false);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it("should return false if the components array is empty", () => {
|
|
23
|
+
const components = [];
|
|
24
|
+
|
|
25
|
+
expect(isFirstComponentGallery(components)).toBe(false);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("should return false if the components array is undefined", () => {
|
|
29
|
+
const components = undefined;
|
|
30
|
+
|
|
31
|
+
expect(isFirstComponentGallery(components)).toBe(false);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { isFirstComponentScreenPicker } from "..";
|
|
2
|
+
|
|
3
|
+
describe("isFirstComponentScreenPicker", () => {
|
|
4
|
+
it("should return true if the first component screen-picker", () => {
|
|
5
|
+
const items = [{ component_type: "screen-picker-qb-tv" }];
|
|
6
|
+
expect(isFirstComponentScreenPicker(items)).toBe(true);
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
it("should return false if the first component type is not screen-picker", () => {
|
|
10
|
+
const items = [{ component_type: "other-component" }];
|
|
11
|
+
expect(isFirstComponentScreenPicker(items)).toBe(false);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it("should return false if the component type is undefined", () => {
|
|
15
|
+
const items = [{ component_type: undefined }];
|
|
16
|
+
expect(isFirstComponentScreenPicker(items)).toBe(false);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it("should return false if the item is null", () => {
|
|
20
|
+
const items = null;
|
|
21
|
+
expect(isFirstComponentScreenPicker(items)).toBe(false);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it("should return false if the item is undefined", () => {
|
|
25
|
+
const items = undefined;
|
|
26
|
+
expect(isFirstComponentScreenPicker(items)).toBe(false);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("should return false if the item is an empty object", () => {
|
|
30
|
+
const items = {};
|
|
31
|
+
expect(isFirstComponentScreenPicker(items)).toBe(false);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { isGallery } from "..";
|
|
2
|
+
|
|
3
|
+
describe("isGallery", () => {
|
|
4
|
+
it("should return true if the component type is 'gallery-qb'", () => {
|
|
5
|
+
const item = { component_type: "gallery-qb" };
|
|
6
|
+
expect(isGallery(item)).toBe(true);
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
it("should return false if the component type is not 'gallery-qb'", () => {
|
|
10
|
+
const item = { component_type: "other-component" };
|
|
11
|
+
expect(isGallery(item)).toBe(false);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it("should return false if the component type is undefined", () => {
|
|
15
|
+
const item = { component_type: undefined };
|
|
16
|
+
expect(isGallery(item)).toBe(false);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it("should return false if the item is null", () => {
|
|
20
|
+
const item = null;
|
|
21
|
+
expect(isGallery(item)).toBe(false);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it("should return false if the item is undefined", () => {
|
|
25
|
+
const item = undefined;
|
|
26
|
+
expect(isGallery(item)).toBe(false);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("should return false if the item is an empty object", () => {
|
|
30
|
+
const item = {};
|
|
31
|
+
expect(isGallery(item)).toBe(false);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { isScreenPicker } from "..";
|
|
2
|
+
|
|
3
|
+
describe("isScreenPicker", () => {
|
|
4
|
+
it("should return true if the component type is 'screen-picker-qb-tv'", () => {
|
|
5
|
+
const item = { component_type: "screen-picker-qb-tv" };
|
|
6
|
+
expect(isScreenPicker(item)).toBe(true);
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
it("should return false if the component type is not 'screen-picker-qb-tv'", () => {
|
|
10
|
+
const item = { component_type: "other-component" };
|
|
11
|
+
expect(isScreenPicker(item)).toBe(false);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it("should return false if the component type is undefined", () => {
|
|
15
|
+
const item = { component_type: undefined };
|
|
16
|
+
expect(isScreenPicker(item)).toBe(false);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it("should return false if the item is null", () => {
|
|
20
|
+
const item = null;
|
|
21
|
+
expect(isScreenPicker(item)).toBe(false);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it("should return false if the item is undefined", () => {
|
|
25
|
+
const item = undefined;
|
|
26
|
+
expect(isScreenPicker(item)).toBe(false);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("should return false if the item is an empty object", () => {
|
|
30
|
+
const item = {};
|
|
31
|
+
expect(isScreenPicker(item)).toBe(false);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
const GROUP = "group-qb";
|
|
2
|
+
const GROUP_INFO = "group-info-qb";
|
|
3
|
+
const EMPTY_GROUP_COMPONENT = "empty_group_component";
|
|
4
|
+
|
|
5
|
+
const GALLERY = "gallery-qb";
|
|
6
|
+
|
|
7
|
+
const SCREEN_PICKER = "screen-picker-qb-tv";
|
|
8
|
+
|
|
9
|
+
export const isGallery = (item): boolean => item?.component_type === GALLERY;
|
|
10
|
+
|
|
11
|
+
export const isScreenPicker = (item): boolean =>
|
|
12
|
+
item?.component_type === SCREEN_PICKER;
|
|
13
|
+
|
|
14
|
+
export const isFirstComponentScreenPicker = (
|
|
15
|
+
components: ZappUIComponent[]
|
|
16
|
+
): boolean => {
|
|
17
|
+
return isScreenPicker(components?.[0]);
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export const isFirstComponentGallery = (
|
|
21
|
+
components: ZappUIComponent[]
|
|
22
|
+
): boolean => {
|
|
23
|
+
return isGallery(components?.[0]);
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export const isGroup = (item): boolean => item?.component_type === GROUP;
|
|
27
|
+
|
|
28
|
+
export const isEmptyGroup = (item): boolean =>
|
|
29
|
+
item?.component_type === EMPTY_GROUP_COMPONENT;
|
|
30
|
+
|
|
31
|
+
export const isGroupInfo = (item): boolean =>
|
|
32
|
+
item?.component_type === GROUP_INFO;
|
package/dateUtils/index.ts
CHANGED
|
@@ -3,6 +3,7 @@ import utc from "dayjs/plugin/utc";
|
|
|
3
3
|
import timezone from "dayjs/plugin/timezone";
|
|
4
4
|
import isoWeek from "dayjs/plugin/isoWeek";
|
|
5
5
|
import duration from "dayjs/plugin/duration";
|
|
6
|
+
import relativeTime from "dayjs/plugin/relativeTime";
|
|
6
7
|
|
|
7
8
|
// Extend dayjs with plugins
|
|
8
9
|
dayjs.extend(utc);
|
|
@@ -10,4 +11,20 @@ dayjs.extend(timezone);
|
|
|
10
11
|
dayjs.extend(isoWeek);
|
|
11
12
|
dayjs.extend(duration);
|
|
12
13
|
|
|
14
|
+
dayjs.extend(relativeTime, {
|
|
15
|
+
thresholds: [
|
|
16
|
+
{ l: "s", r: 1 },
|
|
17
|
+
{ l: "m", r: 1 },
|
|
18
|
+
{ l: "mm", r: 59, d: "minute" },
|
|
19
|
+
{ l: "h", r: 1 },
|
|
20
|
+
{ l: "hh", r: 23, d: "hour" },
|
|
21
|
+
{ l: "d", r: 1 },
|
|
22
|
+
{ l: "dd", r: 29, d: "day" },
|
|
23
|
+
{ l: "M", r: 1 },
|
|
24
|
+
{ l: "MM", r: 11, d: "month" },
|
|
25
|
+
{ l: "y", r: 1 },
|
|
26
|
+
{ l: "yy", d: "year" },
|
|
27
|
+
],
|
|
28
|
+
});
|
|
29
|
+
|
|
13
30
|
export { dayjs };
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import * as R from "ramda";
|
|
2
1
|
import { ViewStyle } from "react-native";
|
|
3
2
|
|
|
4
3
|
import { useMemo } from "react";
|
|
@@ -29,14 +28,16 @@ const RTL_LOCALES = [
|
|
|
29
28
|
"yi", // Yiddish
|
|
30
29
|
];
|
|
31
30
|
|
|
32
|
-
export function useLocalizedStrings({ localizations }) {
|
|
31
|
+
export function useLocalizedStrings({ localizations = {} }) {
|
|
33
32
|
const languageCode = getUILanguage();
|
|
34
33
|
|
|
35
34
|
// TODO: probably we can call getLocalizations here from localizationsHelper.js
|
|
36
35
|
const result = useMemo(
|
|
37
36
|
() =>
|
|
38
37
|
localizations?.[languageCode] ||
|
|
39
|
-
|
|
38
|
+
Object.values(localizations).find(
|
|
39
|
+
(value) => typeof value === "object" && value !== null
|
|
40
|
+
) ||
|
|
40
41
|
{},
|
|
41
42
|
[languageCode, localizations]
|
|
42
43
|
);
|
|
@@ -53,13 +54,7 @@ export function getIsRTL(): boolean {
|
|
|
53
54
|
return false;
|
|
54
55
|
}
|
|
55
56
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
const lowerCaseLanguageCode = languageCode.toLocaleLowerCase();
|
|
59
|
-
|
|
60
|
-
const isRTL = R.contains(lowerCaseLanguageCode, RTL_LOCALES);
|
|
61
|
-
|
|
62
|
-
return isRTL;
|
|
57
|
+
return RTL_LOCALES.includes(uiLanguage.split("-")[0].toLocaleLowerCase());
|
|
63
58
|
}
|
|
64
59
|
|
|
65
60
|
export function useIsRTL(): boolean {
|
|
@@ -2555,6 +2555,12 @@ function getPlayerConfiguration({ platform }) {
|
|
|
2555
2555
|
multiple: false,
|
|
2556
2556
|
label_tooltip: "Choose the default aspect ratio for the artwork",
|
|
2557
2557
|
},
|
|
2558
|
+
{
|
|
2559
|
+
key: "audio_player_artwork_border_radius",
|
|
2560
|
+
label: "Audio Player Artwork Corner Radius",
|
|
2561
|
+
type: "number_input",
|
|
2562
|
+
initial_value: 16,
|
|
2563
|
+
},
|
|
2558
2564
|
]
|
|
2559
2565
|
)
|
|
2560
2566
|
);
|
package/manifestUtils/keys.js
CHANGED
|
@@ -23,6 +23,13 @@ const ZAPPIFEST_FIELDS = {
|
|
|
23
23
|
|
|
24
24
|
const TV_PLATFORMS = ["tvOS", "android", "LG", "samsung", "roku", "vizio"];
|
|
25
25
|
|
|
26
|
+
const MOBILE_PLATFORMS = [
|
|
27
|
+
"ios",
|
|
28
|
+
"ios_for_quickbrick",
|
|
29
|
+
"android",
|
|
30
|
+
"android_for_quickbrick",
|
|
31
|
+
];
|
|
32
|
+
|
|
26
33
|
const FontPropsForTVPlatform = (platform) => ({
|
|
27
34
|
[`${R.toLower(platform)}FontFamily`]: {
|
|
28
35
|
name: `${platform} font family`,
|
|
@@ -2083,4 +2090,6 @@ module.exports = {
|
|
|
2083
2090
|
TV_CELL_BADGE_FIELDS,
|
|
2084
2091
|
progressBarFields,
|
|
2085
2092
|
secondaryImageFields,
|
|
2093
|
+
TV_PLATFORMS,
|
|
2094
|
+
MOBILE_PLATFORMS,
|
|
2086
2095
|
};
|
package/navigationUtils/index.ts
CHANGED
|
@@ -111,6 +111,7 @@ export function getNavigationProps({
|
|
|
111
111
|
assets: ZappNavBarAssets;
|
|
112
112
|
rules: ZappNavBarRules;
|
|
113
113
|
nav_items: NavBarItem[];
|
|
114
|
+
data: MenuItemDataProperties;
|
|
114
115
|
} | null {
|
|
115
116
|
const { activeRiver } = navigator;
|
|
116
117
|
const { navigations, id: selected, home } = activeRiver; // use useRiver hook instead
|
|
@@ -124,7 +125,7 @@ export function getNavigationProps({
|
|
|
124
125
|
return null;
|
|
125
126
|
}
|
|
126
127
|
|
|
127
|
-
const { styles, assets, nav_items, rules } = navigation;
|
|
128
|
+
const { styles, assets, nav_items, rules, data } = navigation;
|
|
128
129
|
|
|
129
130
|
return {
|
|
130
131
|
selected,
|
|
@@ -134,6 +135,7 @@ export function getNavigationProps({
|
|
|
134
135
|
assets: assets as ZappNavBarAssets,
|
|
135
136
|
nav_items: nav_items as any as NavBarItem[],
|
|
136
137
|
rules: rules as any as ZappNavBarRules,
|
|
138
|
+
data: data as MenuItemDataProperties,
|
|
137
139
|
};
|
|
138
140
|
}
|
|
139
141
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@applicaster/zapp-react-native-utils",
|
|
3
|
-
"version": "13.0.0-alpha.
|
|
3
|
+
"version": "13.0.0-alpha.3332871333",
|
|
4
4
|
"description": "Applicaster Zapp React Native utilities package",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
},
|
|
28
28
|
"homepage": "https://github.com/applicaster/quickbrick#readme",
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@applicaster/applicaster-types": "13.0.0-alpha.
|
|
30
|
+
"@applicaster/applicaster-types": "13.0.0-alpha.3332871333",
|
|
31
31
|
"buffer": "^5.2.1",
|
|
32
32
|
"camelize": "^1.0.0",
|
|
33
33
|
"dayjs": "^1.11.10",
|
|
@@ -2557,6 +2557,12 @@ function getPlayerConfiguration({ platform }) {
|
|
|
2557
2557
|
multiple: false,
|
|
2558
2558
|
label_tooltip: "Choose the default aspect ratio for the artwork",
|
|
2559
2559
|
},
|
|
2560
|
+
{
|
|
2561
|
+
key: "audio_player_artwork_border_radius",
|
|
2562
|
+
label: "Audio Player Artwork Corner Radius",
|
|
2563
|
+
type: "number_input",
|
|
2564
|
+
initial_value: 16,
|
|
2565
|
+
},
|
|
2560
2566
|
]
|
|
2561
2567
|
)
|
|
2562
2568
|
);
|
|
@@ -20,6 +20,7 @@ type Props = {
|
|
|
20
20
|
silentRefresh?: boolean;
|
|
21
21
|
method?: "get" | "post";
|
|
22
22
|
bodyParams?: Record<string, unknown>;
|
|
23
|
+
skipLoading?: boolean;
|
|
23
24
|
};
|
|
24
25
|
};
|
|
25
26
|
|
|
@@ -95,7 +96,7 @@ export const useFeedLoader = ({
|
|
|
95
96
|
if (
|
|
96
97
|
shouldDispatchData(callableFeedUrl, currentFeed, pipesOptions.clearCache)
|
|
97
98
|
) {
|
|
98
|
-
if (callableFeedUrl) {
|
|
99
|
+
if (callableFeedUrl && !pipesOptions.skipLoading) {
|
|
99
100
|
dispatch(
|
|
100
101
|
loadPipesData(callableFeedUrl, {
|
|
101
102
|
...pipesOptions,
|
|
@@ -103,26 +104,33 @@ export const useFeedLoader = ({
|
|
|
103
104
|
riverId,
|
|
104
105
|
})
|
|
105
106
|
);
|
|
106
|
-
} else {
|
|
107
|
+
} else if (!callableFeedUrl) {
|
|
107
108
|
logger.info({
|
|
108
109
|
message:
|
|
109
110
|
"Feed is not defined or not inflated, skipping loading. \nMake sure you have correct feedUrl and mapping.",
|
|
110
111
|
jsOnly: true,
|
|
111
112
|
});
|
|
113
|
+
} else {
|
|
114
|
+
logger.info({
|
|
115
|
+
message:
|
|
116
|
+
"Loading skipped as per pipesOptions.skipLoading configuration.",
|
|
117
|
+
data: { url: callableFeedUrl },
|
|
118
|
+
jsOnly: true,
|
|
119
|
+
});
|
|
112
120
|
}
|
|
113
121
|
} else {
|
|
114
122
|
logger.info({
|
|
115
123
|
message:
|
|
116
|
-
"Feed already
|
|
124
|
+
"Feed already exists, skipping loading. \nCall reloadData() if you want to refresh data.",
|
|
117
125
|
data: { url: callableFeedUrl },
|
|
118
126
|
jsOnly: true,
|
|
119
127
|
});
|
|
120
128
|
}
|
|
121
129
|
}, []);
|
|
122
130
|
|
|
123
|
-
// Reload feed when feedUrl changes
|
|
131
|
+
// Reload feed when feedUrl changes, unless skipLoading is true
|
|
124
132
|
useEffect(() => {
|
|
125
|
-
if (!isInitialRender && callableFeedUrl) {
|
|
133
|
+
if (!isInitialRender && callableFeedUrl && !pipesOptions.skipLoading) {
|
|
126
134
|
dispatch(loadPipesData(callableFeedUrl, { ...pipesOptions, riverId }));
|
|
127
135
|
}
|
|
128
136
|
}, [callableFeedUrl]);
|
|
@@ -158,7 +166,6 @@ export const useFeedLoader = ({
|
|
|
158
166
|
currentFeed?.data,
|
|
159
167
|
currentFeed?.error,
|
|
160
168
|
currentFeed?.loading,
|
|
161
|
-
|
|
162
169
|
reloadData,
|
|
163
170
|
loadNext,
|
|
164
171
|
]);
|