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
|
||||
}],
|
||||
"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
|
||||
* 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))
|
||||
* Store subscriptions in internal database ([#1424](https://github.com/lbryio/lbry-app/pull/1424))
|
||||
|
||||
### Fixed
|
||||
* 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 Lbryio from 'lbryio';
|
||||
import isDev from 'electron-is-dev';
|
||||
import type { Subscription } from 'redux/reducers/subscriptions';
|
||||
|
||||
if (isDev) {
|
||||
mixpanel.init('691723e855cabb9d27a7a79002216967');
|
||||
|
@ -15,8 +14,6 @@ type Analytics = {
|
|||
setUser: Object => void,
|
||||
toggle: (boolean, ?boolean) => void,
|
||||
apiLogView: (string, string, string) => void,
|
||||
apiLogSubscribe: Subscription => void,
|
||||
apiLogUnsubscribe: Subscription => void,
|
||||
};
|
||||
|
||||
let analyticsEnabled: boolean = false;
|
||||
|
@ -56,20 +53,6 @@ const analytics: Analytics = {
|
|||
}).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;
|
||||
|
|
|
@ -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 Button from 'component/button';
|
||||
import path from 'path';
|
||||
import type { Claim } from 'types/claim';
|
||||
|
||||
type Props = {
|
||||
claim: {},
|
||||
claim: Claim,
|
||||
fileInfo: {
|
||||
download_path: string,
|
||||
},
|
||||
|
|
|
@ -53,7 +53,6 @@ class FileList extends React.PureComponent<Props, State> {
|
|||
if (fileInfo1.pending) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
const height1 = this.props.claimsById[fileInfo1.claim_id]
|
||||
? this.props.claimsById[fileInfo1.claim_id].height
|
||||
: 0;
|
||||
|
@ -145,6 +144,10 @@ class FileList extends React.PureComponent<Props, State> {
|
|||
const { sortBy } = this.state;
|
||||
const content = [];
|
||||
|
||||
if (!fileInfos) {
|
||||
return null;
|
||||
}
|
||||
|
||||
this.sortFunctions[sortBy](fileInfos).forEach(fileInfo => {
|
||||
const {
|
||||
channel_name: channelName,
|
||||
|
|
|
@ -1,17 +1,76 @@
|
|||
// @flow
|
||||
import * as React from 'react';
|
||||
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 = {
|
||||
children: React.Node,
|
||||
children: React.Node | Array<React.Node>,
|
||||
pageTitle: ?string,
|
||||
noPadding: ?boolean,
|
||||
extraPadding: ?boolean,
|
||||
notContained: ?boolean, // No max-width, but keep the padding
|
||||
loading: ?boolean,
|
||||
};
|
||||
|
||||
const Page = (props: Props) => {
|
||||
const { pageTitle, children, noPadding, extraPadding, notContained } = props;
|
||||
type State = {
|
||||
showLoader: ?boolean,
|
||||
};
|
||||
|
||||
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', {
|
||||
|
@ -25,9 +84,15 @@ const Page = (props: Props) => {
|
|||
{pageTitle && <h1 className="page__title">{pageTitle}</h1>}
|
||||
</div>
|
||||
)}
|
||||
{children}
|
||||
{!loading && children}
|
||||
{shouldShowLoader && (
|
||||
<div className="page__empty">
|
||||
<Spinner />
|
||||
</div>
|
||||
)}
|
||||
</main>
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
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 * as icons from 'constants/icons';
|
||||
import Button from 'component/button';
|
||||
import type { Subscription } from 'redux/reducers/subscriptions';
|
||||
import type { Subscription } from 'types/subscription';
|
||||
|
||||
type SubscribtionArgs = {
|
||||
channelName: string,
|
||||
|
|
|
@ -3,21 +3,18 @@ import React from 'react';
|
|||
import Button from 'component/button';
|
||||
import { buildURI } from 'lbry-redux';
|
||||
import classnames from 'classnames';
|
||||
// import Icon from 'component/common/icon';
|
||||
import type { Claim } from 'types/claim';
|
||||
|
||||
type Props = {
|
||||
isResolvingUri: boolean,
|
||||
resolveUri: string => void,
|
||||
claim: {
|
||||
channel_name: string,
|
||||
has_signature: boolean,
|
||||
signature_is_valid: boolean,
|
||||
value: {
|
||||
publisherSignature: { certificateId: string },
|
||||
},
|
||||
},
|
||||
uri: string,
|
||||
claim: Claim,
|
||||
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> {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// @flow
|
||||
import React from 'react';
|
||||
import Spinner from 'component/common/spinner';
|
||||
import Spinner from 'component/spinner';
|
||||
|
||||
type Props = {
|
||||
spinner: boolean,
|
||||
|
@ -16,7 +16,7 @@ class LoadingScreen extends React.PureComponent<Props> {
|
|||
const { status, spinner } = this.props;
|
||||
return (
|
||||
<div className="content__loading">
|
||||
{spinner && <Spinner />}
|
||||
{spinner && <Spinner light />}
|
||||
|
||||
<span className="content__loading-text">{status}</span>
|
||||
</div>
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
import React from 'react';
|
||||
import { Lbry } from 'lbry-redux';
|
||||
import classnames from 'classnames';
|
||||
import type { Claim } from 'types/claim';
|
||||
import VideoPlayer from './internal/player';
|
||||
import VideoPlayButton from './internal/play-button';
|
||||
import LoadingScreen from './internal/loading-screen';
|
||||
|
@ -26,7 +27,7 @@ type Props = {
|
|||
contentType: string,
|
||||
changeVolume: number => void,
|
||||
volume: number,
|
||||
claim: {},
|
||||
claim: Claim,
|
||||
uri: string,
|
||||
doPlay: () => void,
|
||||
doPause: () => void,
|
||||
|
|
|
@ -3,11 +3,12 @@ import React from 'react';
|
|||
import Button from 'component/button';
|
||||
import { FormField } from 'component/common/form';
|
||||
import UriIndicator from 'component/uriIndicator';
|
||||
import type { Claim } from 'types/claim';
|
||||
|
||||
type Props = {
|
||||
uri: string,
|
||||
title: string,
|
||||
claim: { claim_id: string },
|
||||
claim: Claim,
|
||||
errorMessage: string,
|
||||
isPending: boolean,
|
||||
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 DAEMON_READY = 'DAEMON_READY';
|
||||
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_COMPLETED = 'CHECK_SUBSCRIPTION_COMPLETED';
|
||||
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
|
||||
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 Page from 'component/page';
|
||||
import FileList from 'component/fileList';
|
||||
import type { Claim } from 'types/claim';
|
||||
|
||||
type Props = {
|
||||
uri: string,
|
||||
|
@ -13,10 +14,7 @@ type Props = {
|
|||
totalPages: number,
|
||||
fetching: boolean,
|
||||
params: { page: number },
|
||||
claim: {
|
||||
name: string,
|
||||
claim_id: string,
|
||||
},
|
||||
claim: Claim,
|
||||
claimsInChannel: Array<{}>,
|
||||
fetchClaims: (string, number) => void,
|
||||
fetchClaimCount: string => void,
|
||||
|
@ -58,8 +56,8 @@ class ChannelPage extends React.PureComponent<Props> {
|
|||
}
|
||||
|
||||
render() {
|
||||
const { fetching, claimsInChannel, claim, uri, page, totalPages } = this.props;
|
||||
const { name } = claim;
|
||||
const { fetching, claimsInChannel, claim, page, totalPages } = this.props;
|
||||
const { name, permanent_url: permanentUrl } = claim;
|
||||
|
||||
let contentList;
|
||||
if (fetching) {
|
||||
|
@ -78,7 +76,7 @@ class ChannelPage extends React.PureComponent<Props> {
|
|||
<section className="card__channel-info card__channel-info--large">
|
||||
<h1>{name}</h1>
|
||||
<div className="card__actions card__actions--no-margin">
|
||||
<SubscribeButton uri={uri} channelName={name} />
|
||||
<SubscribeButton uri={permanentUrl} channelName={name} />
|
||||
</div>
|
||||
</section>
|
||||
<section>{contentList}</section>
|
||||
|
|
|
@ -16,18 +16,10 @@ import SubscribeButton from 'component/subscribeButton';
|
|||
import Page from 'component/page';
|
||||
import player from 'render-media';
|
||||
import * as settings from 'constants/settings';
|
||||
import type { Claim } from 'types/claim';
|
||||
|
||||
type Props = {
|
||||
claim: {
|
||||
claim_id: string,
|
||||
height: number,
|
||||
channel_name: string,
|
||||
value: {
|
||||
publisherSignature: ?{
|
||||
certificateId: ?string,
|
||||
},
|
||||
},
|
||||
},
|
||||
claim: Claim,
|
||||
fileInfo: {},
|
||||
metadata: {
|
||||
title: string,
|
||||
|
|
|
@ -5,16 +5,13 @@ import ChannelPage from 'page/channel';
|
|||
import FilePage from 'page/file';
|
||||
import Page from 'component/page';
|
||||
import Button from 'component/button';
|
||||
import type { Claim } from 'types/claim';
|
||||
|
||||
type Props = {
|
||||
isResolvingUri: boolean,
|
||||
resolveUri: string => void,
|
||||
uri: string,
|
||||
claim: {
|
||||
name: string,
|
||||
txid: string,
|
||||
nout: number,
|
||||
},
|
||||
claim: Claim,
|
||||
blackListedOutpoints: Array<{
|
||||
txid: string,
|
||||
nout: number,
|
||||
|
|
|
@ -1,27 +1,25 @@
|
|||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import {
|
||||
selectSubscriptionsFromClaims,
|
||||
selectSubscriptionClaims,
|
||||
selectSubscriptions,
|
||||
selectHasFetchedSubscriptions,
|
||||
selectSubscriptionsBeingFetched,
|
||||
selectIsFetchingSubscriptions,
|
||||
selectNotifications,
|
||||
} from 'redux/selectors/subscriptions';
|
||||
import { doFetchClaimsByChannel } from 'redux/actions/content';
|
||||
import {
|
||||
setHasFetchedSubscriptions,
|
||||
setSubscriptionNotifications,
|
||||
} from 'redux/actions/subscriptions';
|
||||
import { setSubscriptionNotifications, doFetchMySubscriptions } from 'redux/actions/subscriptions';
|
||||
import SubscriptionsPage from './view';
|
||||
|
||||
const select = state => ({
|
||||
hasFetchedSubscriptions: state.subscriptions.hasFetchedSubscriptions,
|
||||
savedSubscriptions: selectSubscriptions(state),
|
||||
subscriptions: selectSubscriptionsFromClaims(state),
|
||||
isFetchingSubscriptions: selectIsFetchingSubscriptions(state),
|
||||
subscriptionsBeingFetched: selectSubscriptionsBeingFetched(state),
|
||||
subscriptions: selectSubscriptions(state),
|
||||
subscriptionClaims: selectSubscriptionClaims(state),
|
||||
notifications: selectNotifications(state),
|
||||
});
|
||||
|
||||
export default connect(select, {
|
||||
doFetchClaimsByChannel,
|
||||
setHasFetchedSubscriptions,
|
||||
setSubscriptionNotifications,
|
||||
doFetchMySubscriptions,
|
||||
})(SubscriptionsPage);
|
||||
|
|
|
@ -1,39 +1,28 @@
|
|||
// @flow
|
||||
import React from 'react';
|
||||
import Page from 'component/page';
|
||||
import CategoryList from 'component/common/category-list';
|
||||
import type { Subscription } from 'redux/reducers/subscriptions';
|
||||
import type { Subscription } from 'types/subscription';
|
||||
import * as NOTIFICATION_TYPES from 'constants/notification_types';
|
||||
import Button from 'component/button';
|
||||
|
||||
type SavedSubscriptions = Array<Subscription>;
|
||||
import FileList from 'component/fileList';
|
||||
import type { Claim } from 'types/claim';
|
||||
|
||||
type Props = {
|
||||
doFetchClaimsByChannel: (string, number) => any,
|
||||
savedSubscriptions: SavedSubscriptions,
|
||||
// TODO build out claim types
|
||||
subscriptions: Array<any>,
|
||||
setHasFetchedSubscriptions: () => void,
|
||||
hasFetchedSubscriptions: boolean,
|
||||
doFetchClaimsByChannel: (string, number) => void,
|
||||
doFetchMySubscriptions: () => void,
|
||||
setSubscriptionNotifications: ({}) => void,
|
||||
subscriptions: Array<Subscription>,
|
||||
isFetchingSubscriptions: boolean,
|
||||
subscriptionClaims: Array<{ uri: string, claims: Array<Claim> }>,
|
||||
subscriptionsBeingFetched: {},
|
||||
notifications: {},
|
||||
};
|
||||
|
||||
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() {
|
||||
const {
|
||||
savedSubscriptions,
|
||||
setHasFetchedSubscriptions,
|
||||
notifications,
|
||||
setSubscriptionNotifications,
|
||||
} = this.props;
|
||||
if (savedSubscriptions.length) {
|
||||
this.fetchSubscriptions(savedSubscriptions);
|
||||
setHasFetchedSubscriptions();
|
||||
}
|
||||
const { notifications, setSubscriptionNotifications, doFetchMySubscriptions } = this.props;
|
||||
doFetchMySubscriptions();
|
||||
|
||||
const newNotifications = {};
|
||||
Object.keys(notifications).forEach(cur => {
|
||||
if (notifications[cur].type === NOTIFICATION_TYPES.DOWNLOADING) {
|
||||
|
@ -43,40 +32,37 @@ export default class extends React.PureComponent<Props> {
|
|||
setSubscriptionNotifications(newNotifications);
|
||||
}
|
||||
|
||||
componentWillReceiveProps(props: Props) {
|
||||
const { savedSubscriptions, hasFetchedSubscriptions, setHasFetchedSubscriptions } = props;
|
||||
componentDidUpdate() {
|
||||
const {
|
||||
subscriptions,
|
||||
subscriptionClaims,
|
||||
doFetchClaimsByChannel,
|
||||
subscriptionsBeingFetched,
|
||||
} = this.props;
|
||||
|
||||
if (!hasFetchedSubscriptions && savedSubscriptions.length) {
|
||||
this.fetchSubscriptions(savedSubscriptions);
|
||||
setHasFetchedSubscriptions();
|
||||
}
|
||||
}
|
||||
|
||||
fetchSubscriptions(savedSubscriptions: SavedSubscriptions) {
|
||||
const { doFetchClaimsByChannel } = this.props;
|
||||
if (savedSubscriptions.length) {
|
||||
// can this use batchActions?
|
||||
savedSubscriptions.forEach(sub => {
|
||||
doFetchClaimsByChannel(sub.uri, 1);
|
||||
const subscriptionClaimMap = {};
|
||||
subscriptionClaims.forEach(claim => {
|
||||
subscriptionClaimMap[claim.uri] = 1;
|
||||
});
|
||||
|
||||
subscriptions.forEach(sub => {
|
||||
if (!subscriptionClaimMap[sub.uri] && !subscriptionsBeingFetched[sub.uri]) {
|
||||
doFetchClaimsByChannel(sub.uri, 1);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
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)
|
||||
const someClaimsNotLoaded = Boolean(
|
||||
subscriptions.find(subscription => !subscription.claims.length)
|
||||
);
|
||||
|
||||
const fetchingSubscriptions =
|
||||
!!savedSubscriptions.length &&
|
||||
(subscriptions.length !== savedSubscriptions.length || someClaimsNotLoaded);
|
||||
let claimList = [];
|
||||
subscriptionClaims.forEach(claimData => {
|
||||
claimList = claimList.concat(claimData.claims);
|
||||
});
|
||||
|
||||
return (
|
||||
<Page noPadding isLoading={fetchingSubscriptions}>
|
||||
{!savedSubscriptions.length && (
|
||||
<Page notContained loading={isFetchingSubscriptions}>
|
||||
{!subscriptions.length && (
|
||||
<div className="page__empty">
|
||||
{__("It looks like you aren't subscribed to any channels yet.")}
|
||||
<div className="card__actions card__actions--center">
|
||||
|
@ -84,28 +70,7 @@ export default class extends React.PureComponent<Props> {
|
|||
</div>
|
||||
</div>
|
||||
)}
|
||||
{!!savedSubscriptions.length && (
|
||||
<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>
|
||||
)}
|
||||
{!!claimList.length && <FileList hideFilter sortByHeight fileInfos={claimList} />}
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -138,6 +138,7 @@ export function doUpdateLoadStatus(uri, outpoint) {
|
|||
: acc,
|
||||
0
|
||||
);
|
||||
|
||||
const notif = new window.Notification(notifications[uri].subscription.channelName, {
|
||||
body: `Posted ${fileInfo.metadata.title}${
|
||||
count > 1 && count < 10 ? ` and ${count - 1} other new items` : ''
|
||||
|
|
|
@ -2,57 +2,128 @@
|
|||
import * as ACTIONS from 'constants/action_types';
|
||||
import * as NOTIFICATION_TYPES from 'constants/notification_types';
|
||||
import type {
|
||||
Subscription,
|
||||
Dispatch,
|
||||
SubscriptionState,
|
||||
SubscriptionNotifications,
|
||||
} from 'redux/reducers/subscriptions';
|
||||
import type { Subscription } from 'types/subscription';
|
||||
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 { doNavigate } from 'redux/actions/navigation';
|
||||
import analytics from 'analytics';
|
||||
import Promise from 'bluebird';
|
||||
import Lbryio from 'lbryio';
|
||||
|
||||
const CHECK_SUBSCRIPTIONS_INTERVAL = 60 * 60 * 1000;
|
||||
const SUBSCRIPTION_DOWNLOAD_LIMIT = 1;
|
||||
|
||||
export const doChannelSubscribe = (subscription: Subscription) => (dispatch: Dispatch) => {
|
||||
dispatch({
|
||||
type: ACTIONS.CHANNEL_SUBSCRIBE,
|
||||
data: subscription,
|
||||
export const doFetchMySubscriptions = () => (dispatch: Dispatch, getState: () => any) => {
|
||||
const {
|
||||
subscriptions: subscriptionState,
|
||||
settings: { daemonSettings },
|
||||
} = getState();
|
||||
const { subscriptions: reduxSubscriptions } = subscriptionState;
|
||||
const { share_usage_data: isSharingData } = daemonSettings;
|
||||
|
||||
if (!isSharingData && isSharingData !== undefined) {
|
||||
// They aren't sharing their data, subscriptions will be handled by persisted redux state
|
||||
return;
|
||||
}
|
||||
|
||||
// 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;
|
||||
});
|
||||
|
||||
analytics.apiLogSubscribe(subscription);
|
||||
reduxSubscriptions.forEach(sub => {
|
||||
const { claimId } = parseURI(sub.uri);
|
||||
reduxSubMap[claimId] = 1;
|
||||
|
||||
dispatch(doCheckSubscription(subscription, true));
|
||||
};
|
||||
|
||||
export const doChannelUnsubscribe = (subscription: Subscription) => (dispatch: Dispatch) => {
|
||||
dispatch({
|
||||
type: ACTIONS.CHANNEL_UNSUBSCRIBE,
|
||||
data: subscription,
|
||||
if (!dbSubMap[claimId]) {
|
||||
subsNotInDB.push({
|
||||
claim_id: claimId,
|
||||
channel_name: sub.channelName,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
analytics.apiLogUnsubscribe(subscription);
|
||||
};
|
||||
storedSubscriptions.forEach(sub => {
|
||||
if (!reduxSubMap[sub.claim_id]) {
|
||||
const uri = `lbry://${sub.channel_name}#${sub.claim_id}`;
|
||||
subscriptionsToReturn.push({ uri, channelName: sub.channel_name });
|
||||
}
|
||||
});
|
||||
|
||||
export const doCheckSubscriptions = () => (
|
||||
dispatch: Dispatch,
|
||||
getState: () => SubscriptionState
|
||||
) => {
|
||||
const checkSubscriptionsTimer = setInterval(
|
||||
return Promise.all(subsNotInDB.map(payload => Lbryio.call('subscription', 'new', payload)))
|
||||
.then(() => subscriptionsToReturn)
|
||||
.catch(
|
||||
() =>
|
||||
selectSubscriptions(getState()).map((subscription: Subscription) =>
|
||||
dispatch(doCheckSubscription(subscription, true))
|
||||
),
|
||||
CHECK_SUBSCRIPTIONS_INTERVAL
|
||||
// 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.CHECK_SUBSCRIPTIONS_SUBSCRIBE,
|
||||
data: { checkSubscriptionsTimer },
|
||||
type: ACTIONS.FETCH_SUBSCRIPTIONS_SUCCESS,
|
||||
data: subscriptions,
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
dispatch({
|
||||
type: ACTIONS.FETCH_SUBSCRIPTIONS_FAIL,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
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 doCheckSubscription = (subscription: Subscription, notify?: boolean) => (
|
||||
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) => (
|
||||
dispatch: Dispatch
|
||||
) =>
|
||||
|
@ -149,5 +195,68 @@ export const setSubscriptionNotifications = (notifications: SubscriptionNotifica
|
|||
},
|
||||
});
|
||||
|
||||
export const setHasFetchedSubscriptions = () => (dispatch: Dispatch) =>
|
||||
dispatch({ type: ACTIONS.HAS_FETCHED_SUBSCRIPTIONS });
|
||||
export const doChannelSubscribe = (subscription: Subscription) => (
|
||||
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 NOTIFICATION_TYPES from 'constants/notification_types';
|
||||
import { handleActions } from 'util/redux-utils';
|
||||
|
||||
export type Subscription = {
|
||||
channelName: string,
|
||||
uri: string,
|
||||
latest: ?string,
|
||||
};
|
||||
import type { Subscription } from 'types/subscription';
|
||||
|
||||
export type NotificationType =
|
||||
| NOTIFICATION_TYPES.DOWNLOADING
|
||||
|
@ -24,8 +19,8 @@ export type SubscriptionNotifications = {
|
|||
// Subscription redux types
|
||||
export type SubscriptionState = {
|
||||
subscriptions: Array<Subscription>,
|
||||
hasFetchedSubscriptions: boolean,
|
||||
notifications: SubscriptionNotifications,
|
||||
loading: boolean,
|
||||
};
|
||||
|
||||
// Subscription action types
|
||||
|
@ -39,10 +34,6 @@ type doChannelUnsubscribe = {
|
|||
data: Subscription,
|
||||
};
|
||||
|
||||
type HasFetchedSubscriptions = {
|
||||
type: ACTIONS.HAS_FETCHED_SUBSCRIPTIONS,
|
||||
};
|
||||
|
||||
type setSubscriptionLatest = {
|
||||
type: ACTIONS.SET_SUBSCRIPTION_LATEST,
|
||||
data: {
|
||||
|
@ -75,10 +66,14 @@ type CheckSubscriptionCompleted = {
|
|||
type: ACTIONS.CHECK_SUBSCRIPTION_COMPLETED,
|
||||
};
|
||||
|
||||
type fetchedSubscriptionsSucess = {
|
||||
type: ACTIONS.FETCH_SUBSCRIPTIONS_SUCCESS,
|
||||
data: Array<Subscription>,
|
||||
};
|
||||
|
||||
export type Action =
|
||||
| doChannelSubscribe
|
||||
| doChannelUnsubscribe
|
||||
| HasFetchedSubscriptions
|
||||
| setSubscriptionLatest
|
||||
| setSubscriptionNotification
|
||||
| CheckSubscriptionStarted
|
||||
|
@ -88,8 +83,8 @@ export type Dispatch = (action: Action) => any;
|
|||
|
||||
const defaultState = {
|
||||
subscriptions: [],
|
||||
hasFetchedSubscriptions: false,
|
||||
notifications: {},
|
||||
loading: false,
|
||||
};
|
||||
|
||||
export default handleActions(
|
||||
|
@ -122,10 +117,6 @@ export default handleActions(
|
|||
subscriptions: newSubscriptions,
|
||||
};
|
||||
},
|
||||
[ACTIONS.HAS_FETCHED_SUBSCRIPTIONS]: (state: SubscriptionState): SubscriptionState => ({
|
||||
...state,
|
||||
hasFetchedSubscriptions: true,
|
||||
}),
|
||||
[ACTIONS.SET_SUBSCRIPTION_LATEST]: (
|
||||
state: SubscriptionState,
|
||||
action: setSubscriptionLatest
|
||||
|
@ -155,6 +146,22 @@ export default handleActions(
|
|||
...state,
|
||||
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
|
||||
);
|
||||
|
|
|
@ -1,15 +1,21 @@
|
|||
import { createSelector } from 'reselect';
|
||||
import { selectAllClaimsByChannel, selectClaimsById } from 'lbry-redux';
|
||||
import {
|
||||
selectAllClaimsByChannel,
|
||||
selectClaimsById,
|
||||
selectAllFetchingChannelClaims,
|
||||
} from 'lbry-redux';
|
||||
|
||||
// get the entire subscriptions state
|
||||
const selectState = state => state.subscriptions || {};
|
||||
|
||||
export const selectIsFetchingSubscriptions = createSelector(selectState, state => state.loading);
|
||||
|
||||
export const selectNotifications = createSelector(selectState, state => state.notifications);
|
||||
|
||||
// list of saved channel names and uris
|
||||
export const selectSubscriptions = createSelector(selectState, state => state.subscriptions);
|
||||
|
||||
export const selectSubscriptionsFromClaims = createSelector(
|
||||
export const selectSubscriptionClaims = createSelector(
|
||||
selectAllClaimsByChannel,
|
||||
selectClaimsById,
|
||||
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({
|
||||
claims: channelClaims,
|
||||
channelName: subscription.channelName,
|
||||
|
@ -50,3 +53,19 @@ export const selectSubscriptionsFromClaims = createSelector(
|
|||
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;
|
||||
text-align: center;
|
||||
font-family: 'metropolis-medium';
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.columns {
|
||||
|
|
|
@ -299,25 +299,12 @@
|
|||
display: inline-block;
|
||||
vertical-align: top;
|
||||
margin-bottom: 60px;
|
||||
|
||||
@media only screen and (max-width: $medium-breakpoint) {
|
||||
width: calc((100% / 3) - (40px / 3));
|
||||
|
||||
&: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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.card__list--rewards {
|
||||
|
@ -341,8 +328,8 @@
|
|||
display: inline-block;
|
||||
vertical-align: top;
|
||||
overflow: visible;
|
||||
// 35 px to handle to padding between cards
|
||||
width: calc((100% / 3) - 35px);
|
||||
// 31 px to handle to padding between cards
|
||||
width: calc((100% / 4) - 31px);
|
||||
}
|
||||
|
||||
.card:not(:first-of-type) {
|
||||
|
@ -352,13 +339,6 @@
|
|||
.card:last-of-type {
|
||||
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 {
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
height: 100%;
|
||||
width: 6px;
|
||||
margin: 0 2px;
|
||||
background-color: var(--color-white);
|
||||
animation: sk-stretchdelay 1.2s infinite ease-in-out;
|
||||
|
||||
&.rect2 {
|
||||
|
@ -31,6 +30,12 @@
|
|||
}
|
||||
}
|
||||
|
||||
.spinner--light {
|
||||
.rect {
|
||||
background-color: var(--color-white);
|
||||
}
|
||||
}
|
||||
|
||||
.spinner--dark {
|
||||
.rect {
|
||||
background-color: var(--color-black);
|
||||
|
|
|
@ -102,6 +102,7 @@ const store = createStore(
|
|||
const compressor = createCompressor();
|
||||
const saveClaimsFilter = createFilter('claims', ['byId', 'claimsByUri']);
|
||||
const subscriptionsFilter = createFilter('subscriptions', ['subscriptions']);
|
||||
|
||||
// We only need to persist the receiveAddress for the wallet
|
||||
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