Merge branch 'internal-subscriptions'
This commit is contained in:
commit
1c0275d69f
38 changed files with 1090 additions and 294 deletions
|
@ -34,6 +34,7 @@
|
||||||
"singleQuote": true
|
"singleQuote": true
|
||||||
}],
|
}],
|
||||||
"func-names": ["warn", "as-needed"],
|
"func-names": ["warn", "as-needed"],
|
||||||
"jsx-a11y/label-has-for": 0
|
"jsx-a11y/label-has-for": 0,
|
||||||
|
"import/prefer-default-export": 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
6
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
6
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<profile version="1.0">
|
||||||
|
<option name="myName" value="Project Default" />
|
||||||
|
<inspection_tool class="Eslint" enabled="true" level="ERROR" enabled_by_default="true" />
|
||||||
|
</profile>
|
||||||
|
</component>
|
12
.idea/lbry-app.iml
generated
Normal file
12
.idea/lbry-app.iml
generated
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="WEB_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/temp" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/tmp" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
6
.idea/misc.xml
generated
Normal file
6
.idea/misc.xml
generated
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="JavaScriptSettings">
|
||||||
|
<option name="languageLevel" value="FLOW" />
|
||||||
|
</component>
|
||||||
|
</project>
|
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/lbry-app.iml" filepath="$PROJECT_DIR$/.idea/lbry-app.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
547
.idea/workspace.xml
generated
Normal file
547
.idea/workspace.xml
generated
Normal file
|
@ -0,0 +1,547 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ChangeListManager">
|
||||||
|
<list default="true" id="061e089e-71dc-4d6b-b27c-9c614b097257" name="Default" comment="">
|
||||||
|
<change type="NEW" beforePath="" afterPath="$PROJECT_DIR$/src/renderer/types/claim.js" />
|
||||||
|
<change type="MODIFICATION" beforePath="$PROJECT_DIR$/src/renderer/component/fileDetails/view.jsx" afterPath="$PROJECT_DIR$/src/renderer/component/fileDetails/view.jsx" />
|
||||||
|
<change type="MODIFICATION" beforePath="$PROJECT_DIR$/src/renderer/component/uriIndicator/view.jsx" afterPath="$PROJECT_DIR$/src/renderer/component/uriIndicator/view.jsx" />
|
||||||
|
<change type="MODIFICATION" beforePath="$PROJECT_DIR$/src/renderer/component/video/view.jsx" afterPath="$PROJECT_DIR$/src/renderer/component/video/view.jsx" />
|
||||||
|
<change type="MODIFICATION" beforePath="$PROJECT_DIR$/src/renderer/component/walletSendTip/view.jsx" afterPath="$PROJECT_DIR$/src/renderer/component/walletSendTip/view.jsx" />
|
||||||
|
<change type="MODIFICATION" beforePath="$PROJECT_DIR$/src/renderer/page/channel/view.jsx" afterPath="$PROJECT_DIR$/src/renderer/page/channel/view.jsx" />
|
||||||
|
<change type="MODIFICATION" beforePath="$PROJECT_DIR$/src/renderer/page/file/view.jsx" afterPath="$PROJECT_DIR$/src/renderer/page/file/view.jsx" />
|
||||||
|
<change type="MODIFICATION" beforePath="$PROJECT_DIR$/src/renderer/page/show/view.jsx" afterPath="$PROJECT_DIR$/src/renderer/page/show/view.jsx" />
|
||||||
|
<change type="MODIFICATION" beforePath="$PROJECT_DIR$/src/renderer/page/subscriptions/view.jsx" afterPath="$PROJECT_DIR$/src/renderer/page/subscriptions/view.jsx" />
|
||||||
|
</list>
|
||||||
|
<ignored path="$PROJECT_DIR$/.tmp/" />
|
||||||
|
<ignored path="$PROJECT_DIR$/temp/" />
|
||||||
|
<ignored path="$PROJECT_DIR$/tmp/" />
|
||||||
|
<option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
|
||||||
|
<option name="TRACKING_ENABLED" value="true" />
|
||||||
|
<option name="SHOW_DIALOG" value="false" />
|
||||||
|
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||||
|
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||||
|
<option name="LAST_RESOLUTION" value="IGNORE" />
|
||||||
|
</component>
|
||||||
|
<component name="FileEditorManager">
|
||||||
|
<leaf SIDE_TABS_SIZE_LIMIT_KEY="300">
|
||||||
|
<file leaf-file-name="view.jsx" pinned="false" current-in-tab="false">
|
||||||
|
<entry file="file://$PROJECT_DIR$/src/renderer/modal/modalRouter/view.jsx">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="0">
|
||||||
|
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
||||||
|
<folding>
|
||||||
|
<element signature="e#0#26#0" expanded="true" />
|
||||||
|
<marker date="1526068149928" expanded="true" signature="5366:5471" ph="{...}" />
|
||||||
|
</folding>
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
</file>
|
||||||
|
<file leaf-file-name="index.js" pinned="false" current-in-tab="false">
|
||||||
|
<entry file="file://$PROJECT_DIR$/src/renderer/modal/modalRouter/index.js">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="216">
|
||||||
|
<caret line="12" column="0" lean-forward="false" selection-start-line="12" selection-start-column="0" selection-end-line="12" selection-end-column="0" />
|
||||||
|
<folding>
|
||||||
|
<marker date="1525123536618" expanded="true" signature="1172:1177" ph="{...}" />
|
||||||
|
</folding>
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
</file>
|
||||||
|
<file leaf-file-name="package.json" pinned="false" current-in-tab="false">
|
||||||
|
<entry file="file://$PROJECT_DIR$/package.json">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="1332">
|
||||||
|
<caret line="74" column="0" lean-forward="false" selection-start-line="74" selection-start-column="0" selection-end-line="74" selection-end-column="0" />
|
||||||
|
<folding>
|
||||||
|
<marker date="1526397284183" expanded="true" signature="2668:3140" ph="{"axios": "^0.18.0"...}" />
|
||||||
|
</folding>
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
</file>
|
||||||
|
<file leaf-file-name="join.js" pinned="false" current-in-tab="false">
|
||||||
|
<entry file="file://$PROJECT_DIR$/node_modules/bluebird/js/release/join.js">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="144">
|
||||||
|
<caret line="8" column="11" lean-forward="false" selection-start-line="8" selection-start-column="11" selection-end-line="8" selection-end-column="11" />
|
||||||
|
<folding />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
</file>
|
||||||
|
<file leaf-file-name="view.jsx" pinned="false" current-in-tab="true">
|
||||||
|
<entry file="file://$PROJECT_DIR$/src/renderer/page/file/view.jsx">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="287">
|
||||||
|
<caret line="18" column="15" lean-forward="false" selection-start-line="18" selection-start-column="14" selection-end-line="18" selection-end-column="15" />
|
||||||
|
<folding />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
</file>
|
||||||
|
</leaf>
|
||||||
|
</component>
|
||||||
|
<component name="FindInProjectRecents">
|
||||||
|
<findStrings>
|
||||||
|
<find>TYPE_FEATURED_DOWNLOAD</find>
|
||||||
|
<find>TYPE_FEATURED_DOW</find>
|
||||||
|
<find>doOpen</find>
|
||||||
|
<find>doNotify</find>
|
||||||
|
<find>settings</find>
|
||||||
|
</findStrings>
|
||||||
|
</component>
|
||||||
|
<component name="Git.Settings">
|
||||||
|
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
||||||
|
</component>
|
||||||
|
<component name="IdeDocumentHistory">
|
||||||
|
<option name="CHANGED_PATHS">
|
||||||
|
<list>
|
||||||
|
<option value="$PROJECT_DIR$/src/renderer/modal/modalRouter/index.js" />
|
||||||
|
<option value="$PROJECT_DIR$/package.json" />
|
||||||
|
<option value="$PROJECT_DIR$/README.md" />
|
||||||
|
<option value="$PROJECT_DIR$/src/renderer/page/file/view.jsx" />
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
<component name="JsBuildToolGruntFileManager" detection-done="true" sorting="DEFINITION_ORDER" />
|
||||||
|
<component name="JsBuildToolPackageJson" detection-done="true" sorting="DEFINITION_ORDER">
|
||||||
|
<package-json value="$PROJECT_DIR$/package.json" />
|
||||||
|
</component>
|
||||||
|
<component name="JsFlowSettings">
|
||||||
|
<service-enabled>true</service-enabled>
|
||||||
|
<exe-path />
|
||||||
|
<annotation-enable>false</annotation-enable>
|
||||||
|
<other-services-enabled>true</other-services-enabled>
|
||||||
|
<auto-save>true</auto-save>
|
||||||
|
</component>
|
||||||
|
<component name="JsGulpfileManager">
|
||||||
|
<detection-done>true</detection-done>
|
||||||
|
<sorting>DEFINITION_ORDER</sorting>
|
||||||
|
</component>
|
||||||
|
<component name="NodeModulesDirectoryManager">
|
||||||
|
<handled-path value="$PROJECT_DIR$/dist/linux-unpacked/resources/app.asar.unpacked/node_modules" />
|
||||||
|
<handled-path value="$PROJECT_DIR$/node_modules" />
|
||||||
|
</component>
|
||||||
|
<component name="PhpWorkspaceProjectConfiguration" backward_compatibility_performed="true" />
|
||||||
|
<component name="ProjectFrameBounds" extendedState="6">
|
||||||
|
<option name="y" value="24" />
|
||||||
|
<option name="width" value="1920" />
|
||||||
|
<option name="height" value="1056" />
|
||||||
|
</component>
|
||||||
|
<component name="ProjectLevelVcsManager" settingsEditedManually="true" />
|
||||||
|
<component name="ProjectView">
|
||||||
|
<navigator currentView="ProjectPane" proportions="" version="1">
|
||||||
|
<flattenPackages />
|
||||||
|
<showMembers />
|
||||||
|
<showModules />
|
||||||
|
<showLibraryContents />
|
||||||
|
<hideEmptyPackages />
|
||||||
|
<abbreviatePackageNames />
|
||||||
|
<autoscrollToSource />
|
||||||
|
<autoscrollFromSource />
|
||||||
|
<sortByType />
|
||||||
|
<manualOrder />
|
||||||
|
<foldersAlwaysOnTop value="true" />
|
||||||
|
</navigator>
|
||||||
|
<panes>
|
||||||
|
<pane id="Scope" />
|
||||||
|
<pane id="ProjectPane">
|
||||||
|
<subPane>
|
||||||
|
<expand>
|
||||||
|
<path>
|
||||||
|
<item name="lbry-app" type="b2602c69:ProjectViewProjectNode" />
|
||||||
|
<item name="lbry-app" type="2a2b976b:PhpTreeStructureProvider$1" />
|
||||||
|
</path>
|
||||||
|
</expand>
|
||||||
|
<select />
|
||||||
|
</subPane>
|
||||||
|
</pane>
|
||||||
|
<pane id="Scratches" />
|
||||||
|
</panes>
|
||||||
|
</component>
|
||||||
|
<component name="PropertiesComponent">
|
||||||
|
<property name="WebServerToolWindowFactoryState" value="false" />
|
||||||
|
<property name="nodejs_interpreter_path" value="/usr/local/bin/node" />
|
||||||
|
<property name="HbShouldOpenHtmlAsHb" value="" />
|
||||||
|
<property name="node.js.path.for.package.eslint" value="project" />
|
||||||
|
<property name="node.js.detected.package.eslint" value="true" />
|
||||||
|
<property name="node.js.selected.package.eslint" value="$PROJECT_DIR$/node_modules/eslint" />
|
||||||
|
<property name="last_opened_file_path" value="$PROJECT_DIR$" />
|
||||||
|
</component>
|
||||||
|
<component name="RunDashboard">
|
||||||
|
<option name="ruleStates">
|
||||||
|
<list>
|
||||||
|
<RuleState>
|
||||||
|
<option name="name" value="ConfigurationTypeDashboardGroupingRule" />
|
||||||
|
</RuleState>
|
||||||
|
<RuleState>
|
||||||
|
<option name="name" value="StatusDashboardGroupingRule" />
|
||||||
|
</RuleState>
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
<component name="ShelveChangesManager" show_recycled="false">
|
||||||
|
<option name="remove_strategy" value="false" />
|
||||||
|
</component>
|
||||||
|
<component name="SvnConfiguration">
|
||||||
|
<configuration />
|
||||||
|
</component>
|
||||||
|
<component name="TaskManager">
|
||||||
|
<task active="true" id="Default" summary="Default task">
|
||||||
|
<changelist id="061e089e-71dc-4d6b-b27c-9c614b097257" name="Default" comment="" />
|
||||||
|
<created>1522354295512</created>
|
||||||
|
<option name="number" value="Default" />
|
||||||
|
<option name="presentableId" value="Default" />
|
||||||
|
<updated>1522354295512</updated>
|
||||||
|
<workItem from="1522354299246" duration="1866000" />
|
||||||
|
<workItem from="1522643117648" duration="2000" />
|
||||||
|
<workItem from="1524064618567" duration="2674000" />
|
||||||
|
<workItem from="1525381677126" duration="197000" />
|
||||||
|
<workItem from="1525382363305" duration="597000" />
|
||||||
|
<workItem from="1525461458836" duration="70000" />
|
||||||
|
<workItem from="1526067492327" duration="897000" />
|
||||||
|
<workItem from="1526397339713" duration="27000" />
|
||||||
|
</task>
|
||||||
|
<servers />
|
||||||
|
</component>
|
||||||
|
<component name="TimeTrackingManager">
|
||||||
|
<option name="totallyTimeSpent" value="6330000" />
|
||||||
|
</component>
|
||||||
|
<component name="ToolWindowManager">
|
||||||
|
<frame x="0" y="24" width="1920" height="1055" extended-state="6" />
|
||||||
|
<editor active="true" />
|
||||||
|
<layout>
|
||||||
|
<window_info id="Project" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="0" side_tool="false" content_ui="combo" />
|
||||||
|
<window_info id="TODO" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="6" side_tool="false" content_ui="tabs" />
|
||||||
|
<window_info id="Event Log" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="true" content_ui="tabs" />
|
||||||
|
<window_info id="Version Control" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
|
||||||
|
<window_info id="npm" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="true" content_ui="tabs" />
|
||||||
|
<window_info id="Run" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" />
|
||||||
|
<window_info id="Structure" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
|
||||||
|
<window_info id="Terminal" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
|
||||||
|
<window_info id="Favorites" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="true" content_ui="tabs" />
|
||||||
|
<window_info id="Debug" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
|
||||||
|
<window_info id="Cvs" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="4" side_tool="false" content_ui="tabs" />
|
||||||
|
<window_info id="Message" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
|
||||||
|
<window_info id="Commander" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
|
||||||
|
<window_info id="Inspection" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="5" side_tool="false" content_ui="tabs" />
|
||||||
|
<window_info id="Hierarchy" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="2" side_tool="false" content_ui="combo" />
|
||||||
|
<window_info id="Find" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
|
||||||
|
<window_info id="Database" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
|
||||||
|
<window_info id="Ant Build" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
|
||||||
|
</layout>
|
||||||
|
</component>
|
||||||
|
<component name="TypeScriptGeneratedFilesManager">
|
||||||
|
<option name="version" value="1" />
|
||||||
|
</component>
|
||||||
|
<component name="VcsContentAnnotationSettings">
|
||||||
|
<option name="myLimit" value="2678400000" />
|
||||||
|
</component>
|
||||||
|
<component name="XDebuggerManager">
|
||||||
|
<breakpoint-manager />
|
||||||
|
<watches-manager />
|
||||||
|
</component>
|
||||||
|
<component name="editorHistoryManager">
|
||||||
|
<entry file="file://$PROJECT_DIR$/src/renderer/modal/modalRouter/view.jsx">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="0">
|
||||||
|
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
||||||
|
<folding>
|
||||||
|
<element signature="e#0#26#0" expanded="true" />
|
||||||
|
<marker date="1526068149928" expanded="true" signature="5366:5471" ph="{...}" />
|
||||||
|
</folding>
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/src/renderer/modal/modalRouter/index.js">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="216">
|
||||||
|
<caret line="12" column="0" lean-forward="false" selection-start-line="12" selection-start-column="0" selection-end-line="12" selection-end-column="0" />
|
||||||
|
<folding>
|
||||||
|
<marker date="1525123536618" expanded="true" signature="1172:1177" ph="{...}" />
|
||||||
|
</folding>
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/package.json">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="1332">
|
||||||
|
<caret line="74" column="0" lean-forward="false" selection-start-line="74" selection-start-column="0" selection-end-line="74" selection-end-column="0" />
|
||||||
|
<folding>
|
||||||
|
<marker date="1526397284183" expanded="true" signature="2668:3140" ph="{"axios": "^0.18.0"...}" />
|
||||||
|
</folding>
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/node_modules/bluebird/js/release/join.js">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="144">
|
||||||
|
<caret line="8" column="11" lean-forward="false" selection-start-line="8" selection-start-column="11" selection-end-line="8" selection-end-column="11" />
|
||||||
|
<folding />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/src/renderer/modal/modalRouter/view.jsx">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="0">
|
||||||
|
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
||||||
|
<folding>
|
||||||
|
<element signature="e#0#26#0" expanded="true" />
|
||||||
|
<marker date="1526068149928" expanded="true" signature="5366:5471" ph="{...}" />
|
||||||
|
</folding>
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/package.json">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="1332">
|
||||||
|
<caret line="74" column="0" lean-forward="false" selection-start-line="74" selection-start-column="0" selection-end-line="74" selection-end-column="0" />
|
||||||
|
<folding>
|
||||||
|
<marker date="1526397284183" expanded="true" signature="2668:3140" ph="{"axios": "^0.18.0"...}" />
|
||||||
|
</folding>
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/src/renderer/modal/modalRouter/index.js">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="216">
|
||||||
|
<caret line="12" column="0" lean-forward="false" selection-start-line="12" selection-start-column="0" selection-end-line="12" selection-end-column="0" />
|
||||||
|
<folding>
|
||||||
|
<marker date="1525123536618" expanded="true" signature="1172:1177" ph="{...}" />
|
||||||
|
</folding>
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/node_modules/bluebird/js/release/join.js">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="0">
|
||||||
|
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
||||||
|
<folding />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/src/renderer/modal/modalRouter/view.jsx">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="0">
|
||||||
|
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
||||||
|
<folding>
|
||||||
|
<element signature="e#0#26#0" expanded="true" />
|
||||||
|
<marker date="1526068149928" expanded="true" signature="5366:5471" ph="{...}" />
|
||||||
|
</folding>
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/src/renderer/modal/modalRouter/index.js">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="216">
|
||||||
|
<caret line="12" column="0" lean-forward="false" selection-start-line="12" selection-start-column="0" selection-end-line="12" selection-end-column="0" />
|
||||||
|
<folding>
|
||||||
|
<marker date="1525123536618" expanded="true" signature="1172:1177" ph="{...}" />
|
||||||
|
</folding>
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/package.json">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="2322">
|
||||||
|
<caret line="129" column="38" lean-forward="false" selection-start-line="129" selection-start-column="38" selection-end-line="129" selection-end-column="38" />
|
||||||
|
<folding>
|
||||||
|
<marker date="1526397284183" expanded="true" signature="2668:3140" ph="{"axios": "^0.18.0"...}" />
|
||||||
|
</folding>
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/src/renderer/modal/modalRouter/view.jsx">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="0">
|
||||||
|
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
||||||
|
<folding>
|
||||||
|
<element signature="e#0#26#0" expanded="true" />
|
||||||
|
<marker date="1526068149928" expanded="true" signature="5366:5471" ph="{...}" />
|
||||||
|
</folding>
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/src/renderer/modal/modalRouter/index.js">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="144">
|
||||||
|
<caret line="19" column="68" lean-forward="true" selection-start-line="19" selection-start-column="68" selection-end-line="19" selection-end-column="68" />
|
||||||
|
<folding>
|
||||||
|
<marker date="1525123536618" expanded="true" signature="1172:1177" ph="{...}" />
|
||||||
|
</folding>
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/src/renderer/page/rewards/view.jsx">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="-122">
|
||||||
|
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/src/renderer/redux/reducers/rewards.js">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="-28">
|
||||||
|
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/src/renderer/redux/actions/rewards.js">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="-832">
|
||||||
|
<caret line="13" column="61" lean-forward="false" selection-start-line="13" selection-start-column="36" selection-end-line="13" selection-end-column="61" />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/src/renderer/rewards.js">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="324">
|
||||||
|
<caret line="18" column="0" lean-forward="false" selection-start-line="18" selection-start-column="0" selection-end-line="18" selection-end-column="0" />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/src/renderer/modal/modalRouter/view.jsx">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="0">
|
||||||
|
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
||||||
|
<folding>
|
||||||
|
<element signature="e#0#26#0" expanded="true" />
|
||||||
|
<marker date="1526068149928" expanded="true" signature="5366:5471" ph="{...}" />
|
||||||
|
</folding>
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/src/renderer/modal/modalRouter/index.js">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="216">
|
||||||
|
<caret line="12" column="0" lean-forward="false" selection-start-line="12" selection-start-column="0" selection-end-line="12" selection-end-column="0" />
|
||||||
|
<folding>
|
||||||
|
<marker date="1525123536618" expanded="true" signature="1172:1177" ph="{...}" />
|
||||||
|
</folding>
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/package.json">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="693">
|
||||||
|
<caret line="129" column="38" lean-forward="false" selection-start-line="129" selection-start-column="38" selection-end-line="129" selection-end-column="38" />
|
||||||
|
<folding>
|
||||||
|
<marker date="1526397284183" expanded="true" signature="2668:3140" ph="{"axios": "^0.18.0"...}" />
|
||||||
|
</folding>
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/src/renderer/modal/modalRouter/view.jsx">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="0">
|
||||||
|
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
||||||
|
<folding>
|
||||||
|
<element signature="e#0#26#0" expanded="true" />
|
||||||
|
<marker date="1526068149928" expanded="true" signature="5366:5471" ph="{...}" />
|
||||||
|
</folding>
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/src/renderer/modal/modalRouter/index.js">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="144">
|
||||||
|
<caret line="19" column="68" lean-forward="true" selection-start-line="19" selection-start-column="68" selection-end-line="19" selection-end-column="68" />
|
||||||
|
<folding>
|
||||||
|
<marker date="1525123536618" expanded="true" signature="1172:1177" ph="{...}" />
|
||||||
|
</folding>
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/src/renderer/page/rewards/view.jsx">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="-122">
|
||||||
|
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/src/renderer/redux/reducers/rewards.js">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="-28">
|
||||||
|
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/src/renderer/redux/actions/rewards.js">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="-832">
|
||||||
|
<caret line="13" column="61" lean-forward="false" selection-start-line="13" selection-start-column="36" selection-end-line="13" selection-end-column="61" />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/src/renderer/rewards.js">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="324">
|
||||||
|
<caret line="18" column="0" lean-forward="false" selection-start-line="18" selection-start-column="0" selection-end-line="18" selection-end-column="0" />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/src/renderer/modal/modalRouter/view.jsx">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="0">
|
||||||
|
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
||||||
|
<folding>
|
||||||
|
<element signature="e#0#26#0" expanded="true" />
|
||||||
|
<marker date="1526068149928" expanded="true" signature="5366:5471" ph="{...}" />
|
||||||
|
</folding>
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/src/renderer/modal/modalRouter/index.js">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="216">
|
||||||
|
<caret line="12" column="0" lean-forward="false" selection-start-line="12" selection-start-column="0" selection-end-line="12" selection-end-column="0" />
|
||||||
|
<folding>
|
||||||
|
<marker date="1525123536618" expanded="true" signature="1172:1177" ph="{...}" />
|
||||||
|
</folding>
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/package.json">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="1332">
|
||||||
|
<caret line="74" column="0" lean-forward="false" selection-start-line="74" selection-start-column="0" selection-end-line="74" selection-end-column="0" />
|
||||||
|
<folding>
|
||||||
|
<marker date="1526397284183" expanded="true" signature="2668:3140" ph="{"axios": "^0.18.0"...}" />
|
||||||
|
</folding>
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/CONTRIBUTING.md">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="540">
|
||||||
|
<caret line="168" column="0" lean-forward="true" selection-start-line="168" selection-start-column="0" selection-end-line="168" selection-end-column="0" />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/README.md">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="846">
|
||||||
|
<caret line="47" column="81" lean-forward="true" selection-start-line="47" selection-start-column="81" selection-end-line="47" selection-end-column="81" />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/node_modules/bluebird/js/release/join.js">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="144">
|
||||||
|
<caret line="8" column="11" lean-forward="false" selection-start-line="8" selection-start-column="11" selection-end-line="8" selection-end-column="11" />
|
||||||
|
<folding />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/src/renderer/page/file/view.jsx">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="287">
|
||||||
|
<caret line="18" column="15" lean-forward="false" selection-start-line="18" selection-start-column="14" selection-end-line="18" selection-end-column="15" />
|
||||||
|
<folding />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
</component>
|
||||||
|
</project>
|
|
@ -18,6 +18,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/).
|
||||||
### Changed
|
### Changed
|
||||||
* Add flair to snackbar ([#1313](https://github.com/lbryio/lbry-app/pull/1313))
|
* Add flair to snackbar ([#1313](https://github.com/lbryio/lbry-app/pull/1313))
|
||||||
* Made font in price badge larger ([#1420](https://github.com/lbryio/lbry-app/pull/1420))
|
* Made font in price badge larger ([#1420](https://github.com/lbryio/lbry-app/pull/1420))
|
||||||
|
* Store subscriptions in internal database ([#1424](https://github.com/lbryio/lbry-app/pull/1424))
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
* Fix content-type not shown correctly in file description ([#863](https://github.com/lbryio/lbry-app/pull/863))
|
* Fix content-type not shown correctly in file description ([#863](https://github.com/lbryio/lbry-app/pull/863))
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
import mixpanel from 'mixpanel-browser';
|
import mixpanel from 'mixpanel-browser';
|
||||||
import Lbryio from 'lbryio';
|
import Lbryio from 'lbryio';
|
||||||
import isDev from 'electron-is-dev';
|
import isDev from 'electron-is-dev';
|
||||||
import type { Subscription } from 'redux/reducers/subscriptions';
|
|
||||||
|
|
||||||
if (isDev) {
|
if (isDev) {
|
||||||
mixpanel.init('691723e855cabb9d27a7a79002216967');
|
mixpanel.init('691723e855cabb9d27a7a79002216967');
|
||||||
|
@ -15,8 +14,6 @@ type Analytics = {
|
||||||
setUser: Object => void,
|
setUser: Object => void,
|
||||||
toggle: (boolean, ?boolean) => void,
|
toggle: (boolean, ?boolean) => void,
|
||||||
apiLogView: (string, string, string) => void,
|
apiLogView: (string, string, string) => void,
|
||||||
apiLogSubscribe: Subscription => void,
|
|
||||||
apiLogUnsubscribe: Subscription => void,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let analyticsEnabled: boolean = false;
|
let analyticsEnabled: boolean = false;
|
||||||
|
@ -56,20 +53,6 @@ const analytics: Analytics = {
|
||||||
}).catch(() => {});
|
}).catch(() => {});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
apiLogSubscribe: (subscription: Subscription): void => {
|
|
||||||
if (analyticsEnabled) {
|
|
||||||
Lbryio.call('subscription', 'new', {
|
|
||||||
subscription,
|
|
||||||
}).catch(() => {});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
apiLogUnsubscribe: (subscription: Subscription): void => {
|
|
||||||
if (analyticsEnabled) {
|
|
||||||
Lbryio.call('subscription', 'delete', {
|
|
||||||
subscription,
|
|
||||||
}).catch(() => {});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default analytics;
|
export default analytics;
|
||||||
|
|
|
@ -1,28 +0,0 @@
|
||||||
// @flow
|
|
||||||
import * as React from 'react';
|
|
||||||
import classnames from 'classnames';
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
dark?: boolean,
|
|
||||||
};
|
|
||||||
|
|
||||||
class Spinner extends React.Component<Props> {
|
|
||||||
static defaultProps = {
|
|
||||||
dark: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { dark } = this.props;
|
|
||||||
return (
|
|
||||||
<div className={classnames('spinner', { 'spinner--dark': dark })}>
|
|
||||||
<div className="rect rect1" />
|
|
||||||
<div className="rect rect2" />
|
|
||||||
<div className="rect rect3" />
|
|
||||||
<div className="rect rect4" />
|
|
||||||
<div className="rect rect5" />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Spinner;
|
|
|
@ -3,9 +3,10 @@ import * as React from 'react';
|
||||||
import ReactMarkdown from 'react-markdown';
|
import ReactMarkdown from 'react-markdown';
|
||||||
import Button from 'component/button';
|
import Button from 'component/button';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
import type { Claim } from 'types/claim';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
claim: {},
|
claim: Claim,
|
||||||
fileInfo: {
|
fileInfo: {
|
||||||
download_path: string,
|
download_path: string,
|
||||||
},
|
},
|
||||||
|
|
|
@ -53,7 +53,6 @@ class FileList extends React.PureComponent<Props, State> {
|
||||||
if (fileInfo1.pending) {
|
if (fileInfo1.pending) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
const height1 = this.props.claimsById[fileInfo1.claim_id]
|
const height1 = this.props.claimsById[fileInfo1.claim_id]
|
||||||
? this.props.claimsById[fileInfo1.claim_id].height
|
? this.props.claimsById[fileInfo1.claim_id].height
|
||||||
: 0;
|
: 0;
|
||||||
|
@ -145,6 +144,10 @@ class FileList extends React.PureComponent<Props, State> {
|
||||||
const { sortBy } = this.state;
|
const { sortBy } = this.state;
|
||||||
const content = [];
|
const content = [];
|
||||||
|
|
||||||
|
if (!fileInfos) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
this.sortFunctions[sortBy](fileInfos).forEach(fileInfo => {
|
this.sortFunctions[sortBy](fileInfos).forEach(fileInfo => {
|
||||||
const {
|
const {
|
||||||
channel_name: channelName,
|
channel_name: channelName,
|
||||||
|
|
|
@ -1,33 +1,98 @@
|
||||||
// @flow
|
// @flow
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
|
import Spinner from 'component/spinner';
|
||||||
|
import { isShowingChildren } from 'util/dom';
|
||||||
|
|
||||||
|
// time in ms to wait to show loading spinner
|
||||||
|
const LOADER_TIMEOUT = 1500;
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
children: React.Node,
|
children: React.Node | Array<React.Node>,
|
||||||
pageTitle: ?string,
|
pageTitle: ?string,
|
||||||
noPadding: ?boolean,
|
noPadding: ?boolean,
|
||||||
extraPadding: ?boolean,
|
extraPadding: ?boolean,
|
||||||
notContained: ?boolean, // No max-width, but keep the padding
|
notContained: ?boolean, // No max-width, but keep the padding
|
||||||
|
loading: ?boolean,
|
||||||
};
|
};
|
||||||
|
|
||||||
const Page = (props: Props) => {
|
type State = {
|
||||||
const { pageTitle, children, noPadding, extraPadding, notContained } = props;
|
showLoader: ?boolean,
|
||||||
return (
|
|
||||||
<main
|
|
||||||
className={classnames('main', {
|
|
||||||
'main--contained': !notContained && !noPadding && !extraPadding,
|
|
||||||
'main--no-padding': noPadding,
|
|
||||||
'main--extra-padding': extraPadding,
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
{pageTitle && (
|
|
||||||
<div className="page__header">
|
|
||||||
{pageTitle && <h1 className="page__title">{pageTitle}</h1>}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{children}
|
|
||||||
</main>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Page extends React.PureComponent<Props, State> {
|
||||||
|
static getDerivedStateFromProps(nextProps: Props, prevState: State) {
|
||||||
|
const { children } = nextProps;
|
||||||
|
const { showLoader } = prevState;
|
||||||
|
|
||||||
|
// If we aren't showing the loader, don't bother updating
|
||||||
|
if (!showLoader) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isShowingChildren(children)) {
|
||||||
|
return {
|
||||||
|
showLoader: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
showLoader: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
this.loaderTimeout = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
const { children } = this.props;
|
||||||
|
|
||||||
|
if (!isShowingChildren(children))
|
||||||
|
this.loaderTimeout = setTimeout(() => {
|
||||||
|
this.setState({ showLoader: true });
|
||||||
|
}, LOADER_TIMEOUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
this.loaderTimeout = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
loaderTimeout: ?TimeoutID;
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { pageTitle, children, noPadding, extraPadding, notContained, loading } = this.props;
|
||||||
|
const { showLoader } = this.state;
|
||||||
|
|
||||||
|
// We don't want to show the loading spinner right away if it will only flash on the
|
||||||
|
// screen for a short time, wait until we know it will be loading for a bit before showing it
|
||||||
|
const shouldShowLoader = !isShowingChildren(children) && showLoader;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<main
|
||||||
|
className={classnames('main', {
|
||||||
|
'main--contained': !notContained && !noPadding && !extraPadding,
|
||||||
|
'main--no-padding': noPadding,
|
||||||
|
'main--extra-padding': extraPadding,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
{pageTitle && (
|
||||||
|
<div className="page__header">
|
||||||
|
{pageTitle && <h1 className="page__title">{pageTitle}</h1>}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{!loading && children}
|
||||||
|
{shouldShowLoader && (
|
||||||
|
<div className="page__empty">
|
||||||
|
<Spinner />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export default Page;
|
export default Page;
|
||||||
|
|
9
src/renderer/component/spinner/index.js
Normal file
9
src/renderer/component/spinner/index.js
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { selectTheme } from 'redux/selectors/settings';
|
||||||
|
import Spinner from './view';
|
||||||
|
|
||||||
|
const mapStateToProps = state => ({
|
||||||
|
theme: selectTheme(state),
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, null)(Spinner);
|
36
src/renderer/component/spinner/view.jsx
Normal file
36
src/renderer/component/spinner/view.jsx
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
// @flow
|
||||||
|
import * as React from 'react';
|
||||||
|
import classnames from 'classnames';
|
||||||
|
import { DARK_THEME, LIGHT_THEME } from 'constants/themes';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
dark?: boolean, // always a dark spinner
|
||||||
|
light?: boolean, // always a light spinner
|
||||||
|
theme: string,
|
||||||
|
};
|
||||||
|
|
||||||
|
const Spinner = (props: Props) => {
|
||||||
|
const { dark, light, theme } = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={classnames('spinner', {
|
||||||
|
'spinner--dark': !light && (dark || theme === LIGHT_THEME),
|
||||||
|
'spinner--light': !dark && (light || theme === DARK_THEME),
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<div className="rect rect1" />
|
||||||
|
<div className="rect rect2" />
|
||||||
|
<div className="rect rect3" />
|
||||||
|
<div className="rect rect4" />
|
||||||
|
<div className="rect rect5" />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
Spinner.defaultProps = {
|
||||||
|
dark: false,
|
||||||
|
light: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Spinner;
|
|
@ -3,7 +3,7 @@ import React from 'react';
|
||||||
import { MODALS } from 'lbry-redux';
|
import { MODALS } from 'lbry-redux';
|
||||||
import * as icons from 'constants/icons';
|
import * as icons from 'constants/icons';
|
||||||
import Button from 'component/button';
|
import Button from 'component/button';
|
||||||
import type { Subscription } from 'redux/reducers/subscriptions';
|
import type { Subscription } from 'types/subscription';
|
||||||
|
|
||||||
type SubscribtionArgs = {
|
type SubscribtionArgs = {
|
||||||
channelName: string,
|
channelName: string,
|
||||||
|
|
|
@ -3,21 +3,18 @@ import React from 'react';
|
||||||
import Button from 'component/button';
|
import Button from 'component/button';
|
||||||
import { buildURI } from 'lbry-redux';
|
import { buildURI } from 'lbry-redux';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
// import Icon from 'component/common/icon';
|
import type { Claim } from 'types/claim';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
isResolvingUri: boolean,
|
isResolvingUri: boolean,
|
||||||
resolveUri: string => void,
|
claim: Claim,
|
||||||
claim: {
|
|
||||||
channel_name: string,
|
|
||||||
has_signature: boolean,
|
|
||||||
signature_is_valid: boolean,
|
|
||||||
value: {
|
|
||||||
publisherSignature: { certificateId: string },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
uri: string,
|
|
||||||
link: ?boolean,
|
link: ?boolean,
|
||||||
|
// Lint thinks we aren't using these, even though we are.
|
||||||
|
// Possibly because the resolve function is an arrow function that is passed in props?
|
||||||
|
/* eslint-disable react/no-unused-prop-types */
|
||||||
|
resolveUri: string => void,
|
||||||
|
uri: string,
|
||||||
|
/* eslint-enable react/no-unused-prop-types */
|
||||||
};
|
};
|
||||||
|
|
||||||
class UriIndicator extends React.PureComponent<Props> {
|
class UriIndicator extends React.PureComponent<Props> {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// @flow
|
// @flow
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Spinner from 'component/common/spinner';
|
import Spinner from 'component/spinner';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
spinner: boolean,
|
spinner: boolean,
|
||||||
|
@ -16,7 +16,7 @@ class LoadingScreen extends React.PureComponent<Props> {
|
||||||
const { status, spinner } = this.props;
|
const { status, spinner } = this.props;
|
||||||
return (
|
return (
|
||||||
<div className="content__loading">
|
<div className="content__loading">
|
||||||
{spinner && <Spinner />}
|
{spinner && <Spinner light />}
|
||||||
|
|
||||||
<span className="content__loading-text">{status}</span>
|
<span className="content__loading-text">{status}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Lbry } from 'lbry-redux';
|
import { Lbry } from 'lbry-redux';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
|
import type { Claim } from 'types/claim';
|
||||||
import VideoPlayer from './internal/player';
|
import VideoPlayer from './internal/player';
|
||||||
import VideoPlayButton from './internal/play-button';
|
import VideoPlayButton from './internal/play-button';
|
||||||
import LoadingScreen from './internal/loading-screen';
|
import LoadingScreen from './internal/loading-screen';
|
||||||
|
@ -26,7 +27,7 @@ type Props = {
|
||||||
contentType: string,
|
contentType: string,
|
||||||
changeVolume: number => void,
|
changeVolume: number => void,
|
||||||
volume: number,
|
volume: number,
|
||||||
claim: {},
|
claim: Claim,
|
||||||
uri: string,
|
uri: string,
|
||||||
doPlay: () => void,
|
doPlay: () => void,
|
||||||
doPause: () => void,
|
doPause: () => void,
|
||||||
|
|
|
@ -3,11 +3,12 @@ import React from 'react';
|
||||||
import Button from 'component/button';
|
import Button from 'component/button';
|
||||||
import { FormField } from 'component/common/form';
|
import { FormField } from 'component/common/form';
|
||||||
import UriIndicator from 'component/uriIndicator';
|
import UriIndicator from 'component/uriIndicator';
|
||||||
|
import type { Claim } from 'types/claim';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
uri: string,
|
uri: string,
|
||||||
title: string,
|
title: string,
|
||||||
claim: { claim_id: string },
|
claim: Claim,
|
||||||
errorMessage: string,
|
errorMessage: string,
|
||||||
isPending: boolean,
|
isPending: boolean,
|
||||||
sendSupport: (number, string, string) => void,
|
sendSupport: (number, string, string) => void,
|
||||||
|
|
|
@ -1,3 +1,13 @@
|
||||||
|
/*
|
||||||
|
Constants for redux actions
|
||||||
|
All names should be in present tense
|
||||||
|
ex:
|
||||||
|
XXX_START
|
||||||
|
XXX_SUCCESS
|
||||||
|
XXX_FAIL
|
||||||
|
XXX_COMPLETE // if there is no fail case
|
||||||
|
*/
|
||||||
|
|
||||||
export const WINDOW_FOCUSED = 'WINDOW_FOCUSED';
|
export const WINDOW_FOCUSED = 'WINDOW_FOCUSED';
|
||||||
export const DAEMON_READY = 'DAEMON_READY';
|
export const DAEMON_READY = 'DAEMON_READY';
|
||||||
export const DAEMON_VERSION_MATCH = 'DAEMON_VERSION_MATCH';
|
export const DAEMON_VERSION_MATCH = 'DAEMON_VERSION_MATCH';
|
||||||
|
@ -166,6 +176,9 @@ export const SET_SUBSCRIPTION_NOTIFICATIONS = 'SET_SUBSCRIPTION_NOTIFICATIONS';
|
||||||
export const CHECK_SUBSCRIPTION_STARTED = 'CHECK_SUBSCRIPTION_STARTED';
|
export const CHECK_SUBSCRIPTION_STARTED = 'CHECK_SUBSCRIPTION_STARTED';
|
||||||
export const CHECK_SUBSCRIPTION_COMPLETED = 'CHECK_SUBSCRIPTION_COMPLETED';
|
export const CHECK_SUBSCRIPTION_COMPLETED = 'CHECK_SUBSCRIPTION_COMPLETED';
|
||||||
export const CHECK_SUBSCRIPTIONS_SUBSCRIBE = 'CHECK_SUBSCRIPTIONS_SUBSCRIBE';
|
export const CHECK_SUBSCRIPTIONS_SUBSCRIBE = 'CHECK_SUBSCRIPTIONS_SUBSCRIBE';
|
||||||
|
export const FETCH_SUBSCRIPTIONS_START = 'FETCH_SUBSCRIPTIONS_START';
|
||||||
|
export const FETCH_SUBSCRIPTIONS_FAIL = 'FETCH_SUBSCRIPTIONS_FAIL';
|
||||||
|
export const FETCH_SUBSCRIPTIONS_SUCCESS = 'FETCH_SUBSCRIPTIONS_SUCCESS';
|
||||||
|
|
||||||
// Video controls
|
// Video controls
|
||||||
export const SET_VIDEO_PAUSE = 'SET_VIDEO_PAUSE';
|
export const SET_VIDEO_PAUSE = 'SET_VIDEO_PAUSE';
|
||||||
|
|
4
src/renderer/constants/themes.js
Normal file
4
src/renderer/constants/themes.js
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
// css theme values
|
||||||
|
// saved in settings and found at /static/themes/{theme}.css
|
||||||
|
export const DARK_THEME = 'dark';
|
||||||
|
export const LIGHT_THEME = 'light';
|
|
@ -6,6 +6,7 @@ import ReactPaginate from 'react-paginate';
|
||||||
import SubscribeButton from 'component/subscribeButton';
|
import SubscribeButton from 'component/subscribeButton';
|
||||||
import Page from 'component/page';
|
import Page from 'component/page';
|
||||||
import FileList from 'component/fileList';
|
import FileList from 'component/fileList';
|
||||||
|
import type { Claim } from 'types/claim';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
uri: string,
|
uri: string,
|
||||||
|
@ -13,10 +14,7 @@ type Props = {
|
||||||
totalPages: number,
|
totalPages: number,
|
||||||
fetching: boolean,
|
fetching: boolean,
|
||||||
params: { page: number },
|
params: { page: number },
|
||||||
claim: {
|
claim: Claim,
|
||||||
name: string,
|
|
||||||
claim_id: string,
|
|
||||||
},
|
|
||||||
claimsInChannel: Array<{}>,
|
claimsInChannel: Array<{}>,
|
||||||
fetchClaims: (string, number) => void,
|
fetchClaims: (string, number) => void,
|
||||||
fetchClaimCount: string => void,
|
fetchClaimCount: string => void,
|
||||||
|
@ -58,8 +56,8 @@ class ChannelPage extends React.PureComponent<Props> {
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { fetching, claimsInChannel, claim, uri, page, totalPages } = this.props;
|
const { fetching, claimsInChannel, claim, page, totalPages } = this.props;
|
||||||
const { name } = claim;
|
const { name, permanent_url: permanentUrl } = claim;
|
||||||
|
|
||||||
let contentList;
|
let contentList;
|
||||||
if (fetching) {
|
if (fetching) {
|
||||||
|
@ -78,7 +76,7 @@ class ChannelPage extends React.PureComponent<Props> {
|
||||||
<section className="card__channel-info card__channel-info--large">
|
<section className="card__channel-info card__channel-info--large">
|
||||||
<h1>{name}</h1>
|
<h1>{name}</h1>
|
||||||
<div className="card__actions card__actions--no-margin">
|
<div className="card__actions card__actions--no-margin">
|
||||||
<SubscribeButton uri={uri} channelName={name} />
|
<SubscribeButton uri={permanentUrl} channelName={name} />
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<section>{contentList}</section>
|
<section>{contentList}</section>
|
||||||
|
|
|
@ -16,18 +16,10 @@ import SubscribeButton from 'component/subscribeButton';
|
||||||
import Page from 'component/page';
|
import Page from 'component/page';
|
||||||
import player from 'render-media';
|
import player from 'render-media';
|
||||||
import * as settings from 'constants/settings';
|
import * as settings from 'constants/settings';
|
||||||
|
import type { Claim } from 'types/claim';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
claim: {
|
claim: Claim,
|
||||||
claim_id: string,
|
|
||||||
height: number,
|
|
||||||
channel_name: string,
|
|
||||||
value: {
|
|
||||||
publisherSignature: ?{
|
|
||||||
certificateId: ?string,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
fileInfo: {},
|
fileInfo: {},
|
||||||
metadata: {
|
metadata: {
|
||||||
title: string,
|
title: string,
|
||||||
|
|
|
@ -5,16 +5,13 @@ import ChannelPage from 'page/channel';
|
||||||
import FilePage from 'page/file';
|
import FilePage from 'page/file';
|
||||||
import Page from 'component/page';
|
import Page from 'component/page';
|
||||||
import Button from 'component/button';
|
import Button from 'component/button';
|
||||||
|
import type { Claim } from 'types/claim';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
isResolvingUri: boolean,
|
isResolvingUri: boolean,
|
||||||
resolveUri: string => void,
|
resolveUri: string => void,
|
||||||
uri: string,
|
uri: string,
|
||||||
claim: {
|
claim: Claim,
|
||||||
name: string,
|
|
||||||
txid: string,
|
|
||||||
nout: number,
|
|
||||||
},
|
|
||||||
blackListedOutpoints: Array<{
|
blackListedOutpoints: Array<{
|
||||||
txid: string,
|
txid: string,
|
||||||
nout: number,
|
nout: number,
|
||||||
|
|
|
@ -1,27 +1,25 @@
|
||||||
import React from 'react';
|
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import {
|
import {
|
||||||
selectSubscriptionsFromClaims,
|
selectSubscriptionClaims,
|
||||||
selectSubscriptions,
|
selectSubscriptions,
|
||||||
selectHasFetchedSubscriptions,
|
selectSubscriptionsBeingFetched,
|
||||||
|
selectIsFetchingSubscriptions,
|
||||||
selectNotifications,
|
selectNotifications,
|
||||||
} from 'redux/selectors/subscriptions';
|
} from 'redux/selectors/subscriptions';
|
||||||
import { doFetchClaimsByChannel } from 'redux/actions/content';
|
import { doFetchClaimsByChannel } from 'redux/actions/content';
|
||||||
import {
|
import { setSubscriptionNotifications, doFetchMySubscriptions } from 'redux/actions/subscriptions';
|
||||||
setHasFetchedSubscriptions,
|
|
||||||
setSubscriptionNotifications,
|
|
||||||
} from 'redux/actions/subscriptions';
|
|
||||||
import SubscriptionsPage from './view';
|
import SubscriptionsPage from './view';
|
||||||
|
|
||||||
const select = state => ({
|
const select = state => ({
|
||||||
hasFetchedSubscriptions: state.subscriptions.hasFetchedSubscriptions,
|
isFetchingSubscriptions: selectIsFetchingSubscriptions(state),
|
||||||
savedSubscriptions: selectSubscriptions(state),
|
subscriptionsBeingFetched: selectSubscriptionsBeingFetched(state),
|
||||||
subscriptions: selectSubscriptionsFromClaims(state),
|
subscriptions: selectSubscriptions(state),
|
||||||
|
subscriptionClaims: selectSubscriptionClaims(state),
|
||||||
notifications: selectNotifications(state),
|
notifications: selectNotifications(state),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(select, {
|
export default connect(select, {
|
||||||
doFetchClaimsByChannel,
|
doFetchClaimsByChannel,
|
||||||
setHasFetchedSubscriptions,
|
|
||||||
setSubscriptionNotifications,
|
setSubscriptionNotifications,
|
||||||
|
doFetchMySubscriptions,
|
||||||
})(SubscriptionsPage);
|
})(SubscriptionsPage);
|
||||||
|
|
|
@ -1,39 +1,28 @@
|
||||||
// @flow
|
// @flow
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Page from 'component/page';
|
import Page from 'component/page';
|
||||||
import CategoryList from 'component/common/category-list';
|
import type { Subscription } from 'types/subscription';
|
||||||
import type { Subscription } from 'redux/reducers/subscriptions';
|
|
||||||
import * as NOTIFICATION_TYPES from 'constants/notification_types';
|
import * as NOTIFICATION_TYPES from 'constants/notification_types';
|
||||||
import Button from 'component/button';
|
import Button from 'component/button';
|
||||||
|
import FileList from 'component/fileList';
|
||||||
type SavedSubscriptions = Array<Subscription>;
|
import type { Claim } from 'types/claim';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
doFetchClaimsByChannel: (string, number) => any,
|
doFetchClaimsByChannel: (string, number) => void,
|
||||||
savedSubscriptions: SavedSubscriptions,
|
doFetchMySubscriptions: () => void,
|
||||||
// TODO build out claim types
|
setSubscriptionNotifications: ({}) => void,
|
||||||
subscriptions: Array<any>,
|
subscriptions: Array<Subscription>,
|
||||||
setHasFetchedSubscriptions: () => void,
|
isFetchingSubscriptions: boolean,
|
||||||
hasFetchedSubscriptions: boolean,
|
subscriptionClaims: Array<{ uri: string, claims: Array<Claim> }>,
|
||||||
|
subscriptionsBeingFetched: {},
|
||||||
|
notifications: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class extends React.PureComponent<Props> {
|
export default class extends React.PureComponent<Props> {
|
||||||
// setHasFetchedSubscriptions is a terrible hack
|
|
||||||
// it allows the subscriptions to load correctly when refresing on the subscriptions page
|
|
||||||
// currently the page is rendered before the state is rehyrdated
|
|
||||||
// that causes this component to be rendered with zero savedSubscriptions
|
|
||||||
// we need to wait until persist/REHYDRATE has fired before rendering the page
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
const {
|
const { notifications, setSubscriptionNotifications, doFetchMySubscriptions } = this.props;
|
||||||
savedSubscriptions,
|
doFetchMySubscriptions();
|
||||||
setHasFetchedSubscriptions,
|
|
||||||
notifications,
|
|
||||||
setSubscriptionNotifications,
|
|
||||||
} = this.props;
|
|
||||||
if (savedSubscriptions.length) {
|
|
||||||
this.fetchSubscriptions(savedSubscriptions);
|
|
||||||
setHasFetchedSubscriptions();
|
|
||||||
}
|
|
||||||
const newNotifications = {};
|
const newNotifications = {};
|
||||||
Object.keys(notifications).forEach(cur => {
|
Object.keys(notifications).forEach(cur => {
|
||||||
if (notifications[cur].type === NOTIFICATION_TYPES.DOWNLOADING) {
|
if (notifications[cur].type === NOTIFICATION_TYPES.DOWNLOADING) {
|
||||||
|
@ -43,40 +32,37 @@ export default class extends React.PureComponent<Props> {
|
||||||
setSubscriptionNotifications(newNotifications);
|
setSubscriptionNotifications(newNotifications);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillReceiveProps(props: Props) {
|
componentDidUpdate() {
|
||||||
const { savedSubscriptions, hasFetchedSubscriptions, setHasFetchedSubscriptions } = props;
|
const {
|
||||||
|
subscriptions,
|
||||||
|
subscriptionClaims,
|
||||||
|
doFetchClaimsByChannel,
|
||||||
|
subscriptionsBeingFetched,
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
if (!hasFetchedSubscriptions && savedSubscriptions.length) {
|
const subscriptionClaimMap = {};
|
||||||
this.fetchSubscriptions(savedSubscriptions);
|
subscriptionClaims.forEach(claim => {
|
||||||
setHasFetchedSubscriptions();
|
subscriptionClaimMap[claim.uri] = 1;
|
||||||
}
|
});
|
||||||
}
|
|
||||||
|
|
||||||
fetchSubscriptions(savedSubscriptions: SavedSubscriptions) {
|
subscriptions.forEach(sub => {
|
||||||
const { doFetchClaimsByChannel } = this.props;
|
if (!subscriptionClaimMap[sub.uri] && !subscriptionsBeingFetched[sub.uri]) {
|
||||||
if (savedSubscriptions.length) {
|
|
||||||
// can this use batchActions?
|
|
||||||
savedSubscriptions.forEach(sub => {
|
|
||||||
doFetchClaimsByChannel(sub.uri, 1);
|
doFetchClaimsByChannel(sub.uri, 1);
|
||||||
});
|
}
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { subscriptions, savedSubscriptions } = this.props;
|
const { subscriptions, subscriptionClaims, isFetchingSubscriptions } = this.props;
|
||||||
|
|
||||||
// TODO: if you are subscribed to an empty channel, this will always be true (but it should not be)
|
let claimList = [];
|
||||||
const someClaimsNotLoaded = Boolean(
|
subscriptionClaims.forEach(claimData => {
|
||||||
subscriptions.find(subscription => !subscription.claims.length)
|
claimList = claimList.concat(claimData.claims);
|
||||||
);
|
});
|
||||||
|
|
||||||
const fetchingSubscriptions =
|
|
||||||
!!savedSubscriptions.length &&
|
|
||||||
(subscriptions.length !== savedSubscriptions.length || someClaimsNotLoaded);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Page noPadding isLoading={fetchingSubscriptions}>
|
<Page notContained loading={isFetchingSubscriptions}>
|
||||||
{!savedSubscriptions.length && (
|
{!subscriptions.length && (
|
||||||
<div className="page__empty">
|
<div className="page__empty">
|
||||||
{__("It looks like you aren't subscribed to any channels yet.")}
|
{__("It looks like you aren't subscribed to any channels yet.")}
|
||||||
<div className="card__actions card__actions--center">
|
<div className="card__actions card__actions--center">
|
||||||
|
@ -84,28 +70,7 @@ export default class extends React.PureComponent<Props> {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{!!savedSubscriptions.length && (
|
{!!claimList.length && <FileList hideFilter sortByHeight fileInfos={claimList} />}
|
||||||
<div>
|
|
||||||
{!!subscriptions.length &&
|
|
||||||
subscriptions.map(subscription => {
|
|
||||||
if (!subscription.claims.length) {
|
|
||||||
// will need to update when you can subscribe to empty channels
|
|
||||||
// for now this prevents issues with FeaturedCategory being rendered
|
|
||||||
// before the names (claim uris) are populated
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<CategoryList
|
|
||||||
key={subscription.channelName}
|
|
||||||
categoryLink={subscription.uri}
|
|
||||||
category={subscription.channelName}
|
|
||||||
names={subscription.claims}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</Page>
|
</Page>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -138,6 +138,7 @@ export function doUpdateLoadStatus(uri, outpoint) {
|
||||||
: acc,
|
: acc,
|
||||||
0
|
0
|
||||||
);
|
);
|
||||||
|
|
||||||
const notif = new window.Notification(notifications[uri].subscription.channelName, {
|
const notif = new window.Notification(notifications[uri].subscription.channelName, {
|
||||||
body: `Posted ${fileInfo.metadata.title}${
|
body: `Posted ${fileInfo.metadata.title}${
|
||||||
count > 1 && count < 10 ? ` and ${count - 1} other new items` : ''
|
count > 1 && count < 10 ? ` and ${count - 1} other new items` : ''
|
||||||
|
|
|
@ -2,56 +2,127 @@
|
||||||
import * as ACTIONS from 'constants/action_types';
|
import * as ACTIONS from 'constants/action_types';
|
||||||
import * as NOTIFICATION_TYPES from 'constants/notification_types';
|
import * as NOTIFICATION_TYPES from 'constants/notification_types';
|
||||||
import type {
|
import type {
|
||||||
Subscription,
|
|
||||||
Dispatch,
|
Dispatch,
|
||||||
SubscriptionState,
|
SubscriptionState,
|
||||||
SubscriptionNotifications,
|
SubscriptionNotifications,
|
||||||
} from 'redux/reducers/subscriptions';
|
} from 'redux/reducers/subscriptions';
|
||||||
|
import type { Subscription } from 'types/subscription';
|
||||||
import { selectSubscriptions } from 'redux/selectors/subscriptions';
|
import { selectSubscriptions } from 'redux/selectors/subscriptions';
|
||||||
import { Lbry, buildURI } from 'lbry-redux';
|
import { Lbry, buildURI, parseURI } from 'lbry-redux';
|
||||||
import { doPurchaseUri } from 'redux/actions/content';
|
import { doPurchaseUri } from 'redux/actions/content';
|
||||||
import { doNavigate } from 'redux/actions/navigation';
|
import Promise from 'bluebird';
|
||||||
import analytics from 'analytics';
|
import Lbryio from 'lbryio';
|
||||||
|
|
||||||
const CHECK_SUBSCRIPTIONS_INTERVAL = 60 * 60 * 1000;
|
const CHECK_SUBSCRIPTIONS_INTERVAL = 60 * 60 * 1000;
|
||||||
const SUBSCRIPTION_DOWNLOAD_LIMIT = 1;
|
const SUBSCRIPTION_DOWNLOAD_LIMIT = 1;
|
||||||
|
|
||||||
export const doChannelSubscribe = (subscription: Subscription) => (dispatch: Dispatch) => {
|
export const doFetchMySubscriptions = () => (dispatch: Dispatch, getState: () => any) => {
|
||||||
dispatch({
|
const {
|
||||||
type: ACTIONS.CHANNEL_SUBSCRIBE,
|
subscriptions: subscriptionState,
|
||||||
data: subscription,
|
settings: { daemonSettings },
|
||||||
});
|
} = getState();
|
||||||
|
const { subscriptions: reduxSubscriptions } = subscriptionState;
|
||||||
|
const { share_usage_data: isSharingData } = daemonSettings;
|
||||||
|
|
||||||
analytics.apiLogSubscribe(subscription);
|
if (!isSharingData && isSharingData !== undefined) {
|
||||||
|
// They aren't sharing their data, subscriptions will be handled by persisted redux state
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
dispatch(doCheckSubscription(subscription, true));
|
// most of this logic comes from scenarios where the db isn't synced with redux
|
||||||
|
// this will happen if the user stops sharing data
|
||||||
|
dispatch({ type: ACTIONS.FETCH_SUBSCRIPTIONS_START });
|
||||||
|
|
||||||
|
Lbryio.call('subscription', 'list')
|
||||||
|
.then(dbSubscriptions => {
|
||||||
|
const storedSubscriptions = dbSubscriptions || [];
|
||||||
|
|
||||||
|
// User has no subscriptions in db or redux
|
||||||
|
if (!storedSubscriptions.length && (!reduxSubscriptions || !reduxSubscriptions.length)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// There is some mismatch between redux state and db state
|
||||||
|
// If something is in the db, but not in redux, add it to redux
|
||||||
|
// If something is in redux, but not in the db, add it to the db
|
||||||
|
if (storedSubscriptions.length !== reduxSubscriptions.length) {
|
||||||
|
const dbSubMap = {};
|
||||||
|
const reduxSubMap = {};
|
||||||
|
const subsNotInDB = [];
|
||||||
|
const subscriptionsToReturn = reduxSubscriptions.slice();
|
||||||
|
|
||||||
|
storedSubscriptions.forEach(sub => {
|
||||||
|
dbSubMap[sub.claim_id] = 1;
|
||||||
|
});
|
||||||
|
|
||||||
|
reduxSubscriptions.forEach(sub => {
|
||||||
|
const { claimId } = parseURI(sub.uri);
|
||||||
|
reduxSubMap[claimId] = 1;
|
||||||
|
|
||||||
|
if (!dbSubMap[claimId]) {
|
||||||
|
subsNotInDB.push({
|
||||||
|
claim_id: claimId,
|
||||||
|
channel_name: sub.channelName,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
storedSubscriptions.forEach(sub => {
|
||||||
|
if (!reduxSubMap[sub.claim_id]) {
|
||||||
|
const uri = `lbry://${sub.channel_name}#${sub.claim_id}`;
|
||||||
|
subscriptionsToReturn.push({ uri, channelName: sub.channel_name });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return Promise.all(subsNotInDB.map(payload => Lbryio.call('subscription', 'new', payload)))
|
||||||
|
.then(() => subscriptionsToReturn)
|
||||||
|
.catch(
|
||||||
|
() =>
|
||||||
|
// let it fail, we will try again when the navigate to the subscriptions page
|
||||||
|
subscriptionsToReturn
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// DB is already synced, just return the subscriptions in redux
|
||||||
|
return reduxSubscriptions;
|
||||||
|
})
|
||||||
|
.then(subscriptions => {
|
||||||
|
dispatch({
|
||||||
|
type: ACTIONS.FETCH_SUBSCRIPTIONS_SUCCESS,
|
||||||
|
data: subscriptions,
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
dispatch({
|
||||||
|
type: ACTIONS.FETCH_SUBSCRIPTIONS_FAIL,
|
||||||
|
});
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const doChannelUnsubscribe = (subscription: Subscription) => (dispatch: Dispatch) => {
|
export const setSubscriptionLatest = (subscription: Subscription, uri: string) => (
|
||||||
|
dispatch: Dispatch
|
||||||
|
) =>
|
||||||
dispatch({
|
dispatch({
|
||||||
type: ACTIONS.CHANNEL_UNSUBSCRIBE,
|
type: ACTIONS.SET_SUBSCRIPTION_LATEST,
|
||||||
data: subscription,
|
data: {
|
||||||
|
subscription,
|
||||||
|
uri,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
analytics.apiLogUnsubscribe(subscription);
|
export const setSubscriptionNotification = (
|
||||||
};
|
subscription: Subscription,
|
||||||
|
uri: string,
|
||||||
export const doCheckSubscriptions = () => (
|
notificationType: string
|
||||||
dispatch: Dispatch,
|
) => (dispatch: Dispatch) =>
|
||||||
getState: () => SubscriptionState
|
|
||||||
) => {
|
|
||||||
const checkSubscriptionsTimer = setInterval(
|
|
||||||
() =>
|
|
||||||
selectSubscriptions(getState()).map((subscription: Subscription) =>
|
|
||||||
dispatch(doCheckSubscription(subscription, true))
|
|
||||||
),
|
|
||||||
CHECK_SUBSCRIPTIONS_INTERVAL
|
|
||||||
);
|
|
||||||
dispatch({
|
dispatch({
|
||||||
type: ACTIONS.CHECK_SUBSCRIPTIONS_SUBSCRIBE,
|
type: ACTIONS.SET_SUBSCRIPTION_NOTIFICATION,
|
||||||
data: { checkSubscriptionsTimer },
|
data: {
|
||||||
|
subscription,
|
||||||
|
uri,
|
||||||
|
type: notificationType,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
};
|
|
||||||
|
|
||||||
export const doCheckSubscription = (subscription: Subscription, notify?: boolean) => (
|
export const doCheckSubscription = (subscription: Subscription, notify?: boolean) => (
|
||||||
dispatch: Dispatch
|
dispatch: Dispatch
|
||||||
|
@ -114,31 +185,6 @@ export const doCheckSubscription = (subscription: Subscription, notify?: boolean
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const setSubscriptionLatest = (subscription: Subscription, uri: string) => (
|
|
||||||
dispatch: Dispatch
|
|
||||||
) =>
|
|
||||||
dispatch({
|
|
||||||
type: ACTIONS.SET_SUBSCRIPTION_LATEST,
|
|
||||||
data: {
|
|
||||||
subscription,
|
|
||||||
uri,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export const setSubscriptionNotification = (
|
|
||||||
subscription: Subscription,
|
|
||||||
uri: string,
|
|
||||||
notificationType: string
|
|
||||||
) => (dispatch: Dispatch) =>
|
|
||||||
dispatch({
|
|
||||||
type: ACTIONS.SET_SUBSCRIPTION_NOTIFICATION,
|
|
||||||
data: {
|
|
||||||
subscription,
|
|
||||||
uri,
|
|
||||||
type: notificationType,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export const setSubscriptionNotifications = (notifications: SubscriptionNotifications) => (
|
export const setSubscriptionNotifications = (notifications: SubscriptionNotifications) => (
|
||||||
dispatch: Dispatch
|
dispatch: Dispatch
|
||||||
) =>
|
) =>
|
||||||
|
@ -149,5 +195,68 @@ export const setSubscriptionNotifications = (notifications: SubscriptionNotifica
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export const setHasFetchedSubscriptions = () => (dispatch: Dispatch) =>
|
export const doChannelSubscribe = (subscription: Subscription) => (
|
||||||
dispatch({ type: ACTIONS.HAS_FETCHED_SUBSCRIPTIONS });
|
dispatch: Dispatch,
|
||||||
|
getState: () => any
|
||||||
|
) => {
|
||||||
|
const {
|
||||||
|
settings: { daemonSettings },
|
||||||
|
} = getState();
|
||||||
|
const { share_usage_data: isSharingData } = daemonSettings;
|
||||||
|
|
||||||
|
dispatch({
|
||||||
|
type: ACTIONS.CHANNEL_SUBSCRIBE,
|
||||||
|
data: subscription,
|
||||||
|
});
|
||||||
|
|
||||||
|
// if the user isn't sharing data, keep the subscriptions entirely in the app
|
||||||
|
if (isSharingData) {
|
||||||
|
const { claimId } = parseURI(subscription.uri);
|
||||||
|
// They are sharing data, we can store their subscriptions in our internal database
|
||||||
|
Lbryio.call('subscription', 'new', {
|
||||||
|
channel_name: subscription.channelName,
|
||||||
|
claim_id: claimId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch(doCheckSubscription(subscription, true));
|
||||||
|
};
|
||||||
|
|
||||||
|
export const doChannelUnsubscribe = (subscription: Subscription) => (
|
||||||
|
dispatch: Dispatch,
|
||||||
|
getState: () => any
|
||||||
|
) => {
|
||||||
|
const {
|
||||||
|
settings: { daemonSettings },
|
||||||
|
} = getState();
|
||||||
|
const { share_usage_data: isSharingData } = daemonSettings;
|
||||||
|
|
||||||
|
dispatch({
|
||||||
|
type: ACTIONS.CHANNEL_UNSUBSCRIBE,
|
||||||
|
data: subscription,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (isSharingData) {
|
||||||
|
const { claimId } = parseURI(subscription.uri);
|
||||||
|
Lbryio.call('subscription', 'delete', {
|
||||||
|
claim_id: claimId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const doCheckSubscriptions = () => (
|
||||||
|
dispatch: Dispatch,
|
||||||
|
getState: () => SubscriptionState
|
||||||
|
) => {
|
||||||
|
const checkSubscriptionsTimer = setInterval(
|
||||||
|
() =>
|
||||||
|
selectSubscriptions(getState()).map((subscription: Subscription) =>
|
||||||
|
dispatch(doCheckSubscription(subscription, true))
|
||||||
|
),
|
||||||
|
CHECK_SUBSCRIPTIONS_INTERVAL
|
||||||
|
);
|
||||||
|
dispatch({
|
||||||
|
type: ACTIONS.CHECK_SUBSCRIPTIONS_SUBSCRIBE,
|
||||||
|
data: { checkSubscriptionsTimer },
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
|
@ -2,12 +2,7 @@
|
||||||
import * as ACTIONS from 'constants/action_types';
|
import * as ACTIONS from 'constants/action_types';
|
||||||
import * as NOTIFICATION_TYPES from 'constants/notification_types';
|
import * as NOTIFICATION_TYPES from 'constants/notification_types';
|
||||||
import { handleActions } from 'util/redux-utils';
|
import { handleActions } from 'util/redux-utils';
|
||||||
|
import type { Subscription } from 'types/subscription';
|
||||||
export type Subscription = {
|
|
||||||
channelName: string,
|
|
||||||
uri: string,
|
|
||||||
latest: ?string,
|
|
||||||
};
|
|
||||||
|
|
||||||
export type NotificationType =
|
export type NotificationType =
|
||||||
| NOTIFICATION_TYPES.DOWNLOADING
|
| NOTIFICATION_TYPES.DOWNLOADING
|
||||||
|
@ -24,8 +19,8 @@ export type SubscriptionNotifications = {
|
||||||
// Subscription redux types
|
// Subscription redux types
|
||||||
export type SubscriptionState = {
|
export type SubscriptionState = {
|
||||||
subscriptions: Array<Subscription>,
|
subscriptions: Array<Subscription>,
|
||||||
hasFetchedSubscriptions: boolean,
|
|
||||||
notifications: SubscriptionNotifications,
|
notifications: SubscriptionNotifications,
|
||||||
|
loading: boolean,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Subscription action types
|
// Subscription action types
|
||||||
|
@ -39,10 +34,6 @@ type doChannelUnsubscribe = {
|
||||||
data: Subscription,
|
data: Subscription,
|
||||||
};
|
};
|
||||||
|
|
||||||
type HasFetchedSubscriptions = {
|
|
||||||
type: ACTIONS.HAS_FETCHED_SUBSCRIPTIONS,
|
|
||||||
};
|
|
||||||
|
|
||||||
type setSubscriptionLatest = {
|
type setSubscriptionLatest = {
|
||||||
type: ACTIONS.SET_SUBSCRIPTION_LATEST,
|
type: ACTIONS.SET_SUBSCRIPTION_LATEST,
|
||||||
data: {
|
data: {
|
||||||
|
@ -75,10 +66,14 @@ type CheckSubscriptionCompleted = {
|
||||||
type: ACTIONS.CHECK_SUBSCRIPTION_COMPLETED,
|
type: ACTIONS.CHECK_SUBSCRIPTION_COMPLETED,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type fetchedSubscriptionsSucess = {
|
||||||
|
type: ACTIONS.FETCH_SUBSCRIPTIONS_SUCCESS,
|
||||||
|
data: Array<Subscription>,
|
||||||
|
};
|
||||||
|
|
||||||
export type Action =
|
export type Action =
|
||||||
| doChannelSubscribe
|
| doChannelSubscribe
|
||||||
| doChannelUnsubscribe
|
| doChannelUnsubscribe
|
||||||
| HasFetchedSubscriptions
|
|
||||||
| setSubscriptionLatest
|
| setSubscriptionLatest
|
||||||
| setSubscriptionNotification
|
| setSubscriptionNotification
|
||||||
| CheckSubscriptionStarted
|
| CheckSubscriptionStarted
|
||||||
|
@ -88,8 +83,8 @@ export type Dispatch = (action: Action) => any;
|
||||||
|
|
||||||
const defaultState = {
|
const defaultState = {
|
||||||
subscriptions: [],
|
subscriptions: [],
|
||||||
hasFetchedSubscriptions: false,
|
|
||||||
notifications: {},
|
notifications: {},
|
||||||
|
loading: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default handleActions(
|
export default handleActions(
|
||||||
|
@ -122,10 +117,6 @@ export default handleActions(
|
||||||
subscriptions: newSubscriptions,
|
subscriptions: newSubscriptions,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
[ACTIONS.HAS_FETCHED_SUBSCRIPTIONS]: (state: SubscriptionState): SubscriptionState => ({
|
|
||||||
...state,
|
|
||||||
hasFetchedSubscriptions: true,
|
|
||||||
}),
|
|
||||||
[ACTIONS.SET_SUBSCRIPTION_LATEST]: (
|
[ACTIONS.SET_SUBSCRIPTION_LATEST]: (
|
||||||
state: SubscriptionState,
|
state: SubscriptionState,
|
||||||
action: setSubscriptionLatest
|
action: setSubscriptionLatest
|
||||||
|
@ -155,6 +146,22 @@ export default handleActions(
|
||||||
...state,
|
...state,
|
||||||
notifications: action.data.notifications,
|
notifications: action.data.notifications,
|
||||||
}),
|
}),
|
||||||
|
[ACTIONS.FETCH_SUBSCRIPTIONS_START]: (state: SubscriptionState): SubscriptionState => ({
|
||||||
|
...state,
|
||||||
|
loading: true,
|
||||||
|
}),
|
||||||
|
[ACTIONS.FETCH_SUBSCRIPTIONS_FAIL]: (state: SubscriptionState): SubscriptionState => ({
|
||||||
|
...state,
|
||||||
|
loading: false,
|
||||||
|
}),
|
||||||
|
[ACTIONS.FETCH_SUBSCRIPTIONS_SUCCESS]: (
|
||||||
|
state: SubscriptionState,
|
||||||
|
action: fetchedSubscriptionsSucess
|
||||||
|
): SubscriptionState => ({
|
||||||
|
...state,
|
||||||
|
loading: false,
|
||||||
|
subscriptions: action.data,
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
defaultState
|
defaultState
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,15 +1,21 @@
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
import { selectAllClaimsByChannel, selectClaimsById } from 'lbry-redux';
|
import {
|
||||||
|
selectAllClaimsByChannel,
|
||||||
|
selectClaimsById,
|
||||||
|
selectAllFetchingChannelClaims,
|
||||||
|
} from 'lbry-redux';
|
||||||
|
|
||||||
// get the entire subscriptions state
|
// get the entire subscriptions state
|
||||||
const selectState = state => state.subscriptions || {};
|
const selectState = state => state.subscriptions || {};
|
||||||
|
|
||||||
|
export const selectIsFetchingSubscriptions = createSelector(selectState, state => state.loading);
|
||||||
|
|
||||||
export const selectNotifications = createSelector(selectState, state => state.notifications);
|
export const selectNotifications = createSelector(selectState, state => state.notifications);
|
||||||
|
|
||||||
// list of saved channel names and uris
|
// list of saved channel names and uris
|
||||||
export const selectSubscriptions = createSelector(selectState, state => state.subscriptions);
|
export const selectSubscriptions = createSelector(selectState, state => state.subscriptions);
|
||||||
|
|
||||||
export const selectSubscriptionsFromClaims = createSelector(
|
export const selectSubscriptionClaims = createSelector(
|
||||||
selectAllClaimsByChannel,
|
selectAllClaimsByChannel,
|
||||||
selectClaimsById,
|
selectClaimsById,
|
||||||
selectSubscriptions,
|
selectSubscriptions,
|
||||||
|
@ -37,9 +43,6 @@ export const selectSubscriptionsFromClaims = createSelector(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// all we really need is a uri for each claim
|
|
||||||
channelClaims = channelClaims.map(claim => `${claim.name}#${claim.claim_id}`);
|
|
||||||
|
|
||||||
fetchedSubscriptions.push({
|
fetchedSubscriptions.push({
|
||||||
claims: channelClaims,
|
claims: channelClaims,
|
||||||
channelName: subscription.channelName,
|
channelName: subscription.channelName,
|
||||||
|
@ -50,3 +53,19 @@ export const selectSubscriptionsFromClaims = createSelector(
|
||||||
return fetchedSubscriptions;
|
return fetchedSubscriptions;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const selectSubscriptionsBeingFetched = createSelector(
|
||||||
|
selectSubscriptions,
|
||||||
|
selectAllFetchingChannelClaims,
|
||||||
|
(subscriptions, fetchingChannelClaims) => {
|
||||||
|
const fetchingSubscriptionMap = {};
|
||||||
|
subscriptions.forEach(sub => {
|
||||||
|
const isFetching = fetchingChannelClaims && fetchingChannelClaims[sub.uri];
|
||||||
|
if (isFetching) {
|
||||||
|
fetchingSubscriptionMap[sub.uri] = 1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return fetchingSubscriptionMap;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
|
@ -221,6 +221,9 @@ p {
|
||||||
margin-top: 200px;
|
margin-top: 200px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-family: 'metropolis-medium';
|
font-family: 'metropolis-medium';
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.columns {
|
.columns {
|
||||||
|
|
|
@ -299,23 +299,10 @@
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
margin-bottom: 60px;
|
margin-bottom: 60px;
|
||||||
|
width: calc((100% / 4) - (60px / 4));
|
||||||
|
|
||||||
@media only screen and (max-width: $medium-breakpoint) {
|
&:not(:nth-child(4n + 1)) {
|
||||||
width: calc((100% / 3) - (40px / 3));
|
margin-left: 20px;
|
||||||
|
|
||||||
&:not(:nth-child(3n + 1)) {
|
|
||||||
margin-left: 20px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media only screen and (min-width: $medium-breakpoint) {
|
|
||||||
.card {
|
|
||||||
width: calc((100% / 4) - (60px / 4));
|
|
||||||
|
|
||||||
&:not(:nth-child(4n + 1)) {
|
|
||||||
margin-left: 20px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -341,8 +328,8 @@
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
overflow: visible;
|
overflow: visible;
|
||||||
// 35 px to handle to padding between cards
|
// 31 px to handle to padding between cards
|
||||||
width: calc((100% / 3) - 35px);
|
width: calc((100% / 4) - 31px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.card:not(:first-of-type) {
|
.card:not(:first-of-type) {
|
||||||
|
@ -352,13 +339,6 @@
|
||||||
.card:last-of-type {
|
.card:last-of-type {
|
||||||
margin-right: 20px;
|
margin-right: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media only screen and (min-width: $medium-breakpoint) {
|
|
||||||
.card {
|
|
||||||
// 31 px to handle to padding between cards
|
|
||||||
width: calc((100% / 4) - 31px);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.card__success-msg {
|
.card__success-msg {
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 6px;
|
width: 6px;
|
||||||
margin: 0 2px;
|
margin: 0 2px;
|
||||||
background-color: var(--color-white);
|
|
||||||
animation: sk-stretchdelay 1.2s infinite ease-in-out;
|
animation: sk-stretchdelay 1.2s infinite ease-in-out;
|
||||||
|
|
||||||
&.rect2 {
|
&.rect2 {
|
||||||
|
@ -31,6 +30,12 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.spinner--light {
|
||||||
|
.rect {
|
||||||
|
background-color: var(--color-white);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.spinner--dark {
|
.spinner--dark {
|
||||||
.rect {
|
.rect {
|
||||||
background-color: var(--color-black);
|
background-color: var(--color-black);
|
||||||
|
|
|
@ -102,6 +102,7 @@ const store = createStore(
|
||||||
const compressor = createCompressor();
|
const compressor = createCompressor();
|
||||||
const saveClaimsFilter = createFilter('claims', ['byId', 'claimsByUri']);
|
const saveClaimsFilter = createFilter('claims', ['byId', 'claimsByUri']);
|
||||||
const subscriptionsFilter = createFilter('subscriptions', ['subscriptions']);
|
const subscriptionsFilter = createFilter('subscriptions', ['subscriptions']);
|
||||||
|
|
||||||
// We only need to persist the receiveAddress for the wallet
|
// We only need to persist the receiveAddress for the wallet
|
||||||
const walletFilter = createFilter('wallet', ['receiveAddress']);
|
const walletFilter = createFilter('wallet', ['receiveAddress']);
|
||||||
|
|
||||||
|
|
30
src/renderer/types/claim.js
Normal file
30
src/renderer/types/claim.js
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
// @flow
|
||||||
|
|
||||||
|
// Actual claim type has more values than this
|
||||||
|
// Add them as they are used
|
||||||
|
export type Claim = {
|
||||||
|
address: string,
|
||||||
|
amount: number,
|
||||||
|
claim_id: string,
|
||||||
|
claim_sequence: number,
|
||||||
|
decoded_claim: boolean,
|
||||||
|
depth: number,
|
||||||
|
effective_amount: number,
|
||||||
|
has_signature: boolean,
|
||||||
|
height: number,
|
||||||
|
has_signature: boolean,
|
||||||
|
hex: string,
|
||||||
|
name: string,
|
||||||
|
nout: number,
|
||||||
|
permanent_url: string,
|
||||||
|
channel_name: ?string,
|
||||||
|
txid: string,
|
||||||
|
nout: number,
|
||||||
|
signature_is_valid: boolean,
|
||||||
|
valid_at_height: number,
|
||||||
|
value: {
|
||||||
|
publisherSignature: ?{
|
||||||
|
certificateId: ?string,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
7
src/renderer/types/subscription.js
Normal file
7
src/renderer/types/subscription.js
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
// @flow
|
||||||
|
|
||||||
|
export type Subscription = {
|
||||||
|
channelName: string, // @CryptoCandor,
|
||||||
|
uri: string, // lbry://@CryptoCandor#9152f3b054f692076a6882d1b58a30e8781cc8e6
|
||||||
|
latest: string, // substratum#b0ab143243020e7831fd070d9f871e1fda948620
|
||||||
|
};
|
12
src/renderer/util/dom.js
Normal file
12
src/renderer/util/dom.js
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
// @flow
|
||||||
|
import * as React from 'react';
|
||||||
|
|
||||||
|
// is a child component being rendered?
|
||||||
|
export const isShowingChildren = (children: React.Node): boolean => {
|
||||||
|
if (Array.isArray(children)) {
|
||||||
|
const firstChildIndex = children.findIndex(child => child);
|
||||||
|
return firstChildIndex > -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return !!children;
|
||||||
|
};
|
Loading…
Add table
Reference in a new issue