feature: use internal-apis for subscriptions and add page loader
update subscription types update changelog Simplify subscriptions sync logic add claim type use let over const change spinner color based on theme clean up subscriptions
This commit is contained in:
parent
2bb4287408
commit
492b1601f6
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,33 +1,98 @@
|
|||
// @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;
|
||||
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>
|
||||
);
|
||||
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', {
|
||||
'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;
|
||||
|
|
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();
|
||||
}
|
||||
}
|
||||
const subscriptionClaimMap = {};
|
||||
subscriptionClaims.forEach(claim => {
|
||||
subscriptionClaimMap[claim.uri] = 1;
|
||||
});
|
||||
|
||||
fetchSubscriptions(savedSubscriptions: SavedSubscriptions) {
|
||||
const { doFetchClaimsByChannel } = this.props;
|
||||
if (savedSubscriptions.length) {
|
||||
// can this use batchActions?
|
||||
savedSubscriptions.forEach(sub => {
|
||||
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,56 +2,127 @@
|
|||
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;
|
||||
|
||||
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({
|
||||
type: ACTIONS.CHANNEL_UNSUBSCRIBE,
|
||||
data: subscription,
|
||||
type: ACTIONS.SET_SUBSCRIPTION_LATEST,
|
||||
data: {
|
||||
subscription,
|
||||
uri,
|
||||
},
|
||||
});
|
||||
|
||||
analytics.apiLogUnsubscribe(subscription);
|
||||
};
|
||||
|
||||
export const doCheckSubscriptions = () => (
|
||||
dispatch: Dispatch,
|
||||
getState: () => SubscriptionState
|
||||
) => {
|
||||
const checkSubscriptionsTimer = setInterval(
|
||||
() =>
|
||||
selectSubscriptions(getState()).map((subscription: Subscription) =>
|
||||
dispatch(doCheckSubscription(subscription, true))
|
||||
),
|
||||
CHECK_SUBSCRIPTIONS_INTERVAL
|
||||
);
|
||||
export const setSubscriptionNotification = (
|
||||
subscription: Subscription,
|
||||
uri: string,
|
||||
notificationType: string
|
||||
) => (dispatch: Dispatch) =>
|
||||
dispatch({
|
||||
type: ACTIONS.CHECK_SUBSCRIPTIONS_SUBSCRIBE,
|
||||
data: { checkSubscriptionsTimer },
|
||||
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,23 +299,10 @@
|
|||
display: inline-block;
|
||||
vertical-align: top;
|
||||
margin-bottom: 60px;
|
||||
width: calc((100% / 4) - (60px / 4));
|
||||
|
||||
@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;
|
||||
}
|
||||
&:not(:nth-child(4n + 1)) {
|
||||
margin-left: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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