Merge branch 'master' into video-overlay-new
This commit is contained in:
commit
4b7187a707
139 changed files with 2449 additions and 2318 deletions
|
@ -36,6 +36,8 @@
|
|||
"func-names": ["warn", "as-needed"],
|
||||
"jsx-a11y/label-has-for": 0,
|
||||
"import/prefer-default-export": 0,
|
||||
"no-return-assign": 0
|
||||
"no-return-assign": 0,
|
||||
"react/require-default-props": 0,
|
||||
"react/jsx-closing-tag-location": 0
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,5 +20,6 @@ module.name_mapper='^lbry\(.*\)$' -> '<PROJECT_ROOT>/src/renderer/lbry\1'
|
|||
module.name_mapper='^rewards\(.*\)$' -> '<PROJECT_ROOT>/src/renderer/rewards\1'
|
||||
module.name_mapper='^modal\(.*\)$' -> '<PROJECT_ROOT>/src/renderer/modal\1'
|
||||
module.name_mapper='^app\(.*\)$' -> '<PROJECT_ROOT>/src/renderer/app\1'
|
||||
module.name_mapper='^native\(.*\)$' -> '<PROJECT_ROOT>/src/renderer/native\1'
|
||||
|
||||
[strict]
|
||||
|
|
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -3,3 +3,5 @@
|
|||
/static/daemon/lbrynet*
|
||||
/static/locales
|
||||
yarn-error.log
|
||||
package-lock.json
|
||||
.idea/
|
6
.idea/inspectionProfiles/Project_Default.xml
generated
6
.idea/inspectionProfiles/Project_Default.xml
generated
|
@ -1,6 +0,0 @@
|
|||
<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
12
.idea/lbry-app.iml
generated
|
@ -1,12 +0,0 @@
|
|||
<?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
6
.idea/misc.xml
generated
|
@ -1,6 +0,0 @@
|
|||
<?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
8
.idea/modules.xml
generated
|
@ -1,8 +0,0 @@
|
|||
<?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
6
.idea/vcs.xml
generated
|
@ -1,6 +0,0 @@
|
|||
<?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
547
.idea/workspace.xml
generated
|
@ -1,547 +0,0 @@
|
|||
<?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>
|
20
.travis.yml
20
.travis.yml
|
@ -1,16 +1,19 @@
|
|||
matrix:
|
||||
include:
|
||||
- os: osx
|
||||
env: TARGET=mac
|
||||
osx_image: xcode9.2
|
||||
language: node_js
|
||||
node_js: "9"
|
||||
env:
|
||||
- ELECTRON_CACHE=$HOME/.cache/electron
|
||||
- ELECTRON_BUILDER_CACHE=$HOME/.cache/electron-builder
|
||||
- os: linux
|
||||
env: TARGET=windows
|
||||
services: docker
|
||||
language: node_js
|
||||
node_js: "9"
|
||||
- os: linux
|
||||
env: TARGET=linux
|
||||
language: node_js
|
||||
node_js: "9"
|
||||
cache: false
|
||||
before_install:
|
||||
- |
|
||||
|
@ -20,6 +23,7 @@ before_install:
|
|||
else
|
||||
sudo apt-get -qq update
|
||||
sudo apt-get install -y libsecret-1-dev
|
||||
sudo apt-get install --no-install-recommends -y gcc-multilib g++-multilib
|
||||
curl -o- -L https://yarnpkg.com/install.sh | bash -s -- --version 1.6.0
|
||||
export PATH="$HOME/.yarn/bin:$PATH"
|
||||
fi
|
||||
|
@ -27,17 +31,15 @@ before_script:
|
|||
- git lfs pull
|
||||
script:
|
||||
- |
|
||||
if [ "$TRAVIS_OS_NAME" == "linux" ]; then
|
||||
if [ "$TARGET" == "windows" ]; then
|
||||
docker run --rm \
|
||||
--env-file <(env | grep -iE 'DEBUG|NODE_|ELECTRON_|YARN_|NPM_|CI|CIRCLE|TRAVIS|APPVEYOR_|CSC_|GH_|GITHUB_|BT_|AWS_|STRIP|BUILD_') \
|
||||
-v ${PWD}:/project \
|
||||
-v ~/.cache/electron:/root/.cache/electron \
|
||||
-v ~/.cache/electron-builder:/root/.cache/electron-builder \
|
||||
electronuserland/builder:wine \
|
||||
/bin/bash -c "yarn --link-duplicates --pure-lockfile && yarn build --linux --win --publish onTag"
|
||||
else
|
||||
yarn build --publish onTag
|
||||
/bin/bash -c "yarn --link-duplicates --pure-lockfile && yarn build --win --publish onTag";
|
||||
fi
|
||||
- if [ "$TARGET" == "mac" ]; then yarn build --publish onTag; fi
|
||||
- if [ "$TARGET" == "linux" ]; then yarn --link-duplicates --pure-lockfile && yarn build --linux --publish onTag; fi
|
||||
branches:
|
||||
except:
|
||||
- "/^v\\d+\\.\\d+\\.\\d+$/"
|
||||
|
|
23
CHANGELOG.md
23
CHANGELOG.md
|
@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/).
|
|||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
|
||||
* Add ability to open log file and log directory in the help page ([#1556](https://github.com/lbryio/lbry-app/issues/1556))
|
||||
* Add ability to resend verification email ([#1492](https://github.com/lbryio/lbry-app/issues/1492))
|
||||
* Add Narrative about Feature Request on Help Page and Report Page ([#1551](https://github.com/lbryio/lbry-app/pull/1551))
|
||||
* Add keyboard shortcut to quit the app on Windows ([#1202](https://github.com/lbryio/lbry-app/pull/1202))
|
||||
* Build for both architectures (x86 and x64) for Windows ([#1262](https://github.com/lbryio/lbry-app/pull/1262))
|
||||
* Add referral FAQ to Invites screen([#1314](https://github.com/lbryio/lbry-app/pull/1314))
|
||||
|
@ -14,13 +18,17 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/).
|
|||
* Pre-fill publish URL after clicking "Put something here" link ([#1303](https://github.com/lbryio/lbry-app/pull/1303))
|
||||
* Add Danger JS to automate code reviews ([#1289](https://github.com/lbryio/lbry-app/pull/1289))
|
||||
* Autoplay downloaded and free media ([#584](https://github.com/lbryio/lbry-app/pull/1453))
|
||||
* Add 'Go to page' input on channel pagination ([#1166](https://github.com/lbryio/lbry-app/pull/1166))
|
||||
* Add "View on web" button on file/channel pages with spee.ch link ([#1222](https://github.com/lbryio/lbry-app/pull/1222))
|
||||
|
||||
### 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))
|
||||
* Move rewards logic to interal api ([#1509](https://github.com/lbryio/lbry-app/pull/1509))
|
||||
|
||||
### Fixed
|
||||
* Fixing content address extending outside of visible area. ([#741](https://github.com/lbryio/lbry-app/issues/741))
|
||||
* Fix content-type not shown correctly in file description ([#863](https://github.com/lbryio/lbry-app/pull/863))
|
||||
* Fix [Flow](https://flow.org/) ([#1197](https://github.com/lbryio/lbry-app/pull/1197))
|
||||
* Fix black screen on macOS after maximizing LBRY and then closing ([#1235](https://github.com/lbryio/lbry-app/pull/1235))
|
||||
|
@ -30,11 +38,15 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/).
|
|||
* Fix don't allow dark mode with automatic night mode enabled ([#1005](https://github.com/lbryio/lbry-app/issues/1005))
|
||||
* Fix description box on Publish (dark theme) ([#1356](https://github.com/lbryio/lbry-app/issues/#1356))
|
||||
* Fix price wrapping in price badge ([#1420](https://github.com/lbryio/lbry-app/pull/1420))
|
||||
* Fix spacing in search suggestions ([#1422])(https://github.com/lbryio/lbry-app/pull/1422))
|
||||
* Fix text/HTML files don't display correctly in-app anymore ([#1379])(https://github.com/lbryio/lbry-app/issues/1379)
|
||||
* Fix notification modals when reward is claimed ([#1436])(https://github.com/lbryio/lbry-app/issues/1436) and ([#1407])(https://github.com/lbryio/lbry-app/issues/1407)
|
||||
* Fix disabled cards(grayed out) ([#1466])(https://github.com/lbryio/lbry-app/issues/1466)
|
||||
* Fix spacing in search suggestions ([#1422](https://github.com/lbryio/lbry-app/pull/1422))
|
||||
* Fix text/HTML files don't display correctly in-app anymore ([#1379](https://github.com/lbryio/lbry-app/issues/1379))
|
||||
* Fix notification modals when reward is claimed ([#1436](https://github.com/lbryio/lbry-app/issues/1436)) and ([#1407](https://github.com/lbryio/lbry-app/issues/1407))
|
||||
* Fix disabled cards(grayed out) ([#1466](https://github.com/lbryio/lbry-app/issues/1466))
|
||||
* Fix markdown render ([#1179](https://github.com/lbryio/lbry-app/issues/1179))
|
||||
* Fix new lines not showing correctly after markdown changes ([#1504](https://github.com/lbryio/lbry-app/issues/1504))
|
||||
* Fix claim ID being null when reporting a claim that was not previously download ([issue#1512](https://github.com/lbryio/lbry-app/issues/1512)) ([PR#1530](https://github.com/lbryio/lbry-app/pull/1530))
|
||||
* Fix URI and outpoint not being passed properly to API ([#1494](https://github.com/lbryio/lbry-app/issues/1494))
|
||||
* Fix incorrect markdown preview on url with parentheses ([#1570](https://github.com/lbryio/lbry-app/issues/1570))
|
||||
|
||||
|
||||
## [0.21.3] - 2018-04-23
|
||||
|
@ -57,7 +69,6 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/).
|
|||
* App category for Linux ([#877](https://github.com/lbryio/lbry-app/pull/877))
|
||||
* Add YouTube Sync reward ([#1147](https://github.com/lbryio/lbry-app/pull/1147))
|
||||
* Retain previous screen sizing on startup ([#338](https://github.com/lbryio/lbry-app/issues/338))
|
||||
* Add 'Go to page' input on channel pagination ([#1166](https://github.com/lbryio/lbry-app/pull/1166))
|
||||
|
||||
|
||||
### Changed
|
||||
|
@ -372,7 +383,6 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/).
|
|||
* Removed placeholder values from price selection form fields, which was causing confusion that these were real values (#426)
|
||||
* Fixed showing "other currency" help tip in publish form, which was caused due to not "setting" state for price
|
||||
* Publish page now properly checks for all required fields are filled
|
||||
* Fixed pagination styling for pages > 5 (#416)
|
||||
* Fixed sizing on squat videos (#419)
|
||||
* Support claims no longer show up on Published page (#384)
|
||||
* Fixed rendering of small prices (#461)
|
||||
|
@ -410,7 +420,6 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/).
|
|||
### Added
|
||||
* Replaced horizontal scrollbars with scroll arrows
|
||||
* Featured weekly reward content shows with an orange star
|
||||
* Added pagination to channel pages
|
||||
|
||||
|
||||
### Fixed
|
||||
|
|
|
@ -146,6 +146,8 @@ There are a few tools integrated to the project that will ease the process of de
|
|||
manner and, therefore, not begin working on anything reserved (or updated) within the last 3 days.
|
||||
If someone has been officially assigned an issue via Github's assignment system, it is also not
|
||||
available. Contributors are encouraged to ask if they have any questions about issue availability.
|
||||
* The [changelog](https://github.com/lbryio/lbry-app/blob/master/CHANGELOG.md) should be updated to
|
||||
include a reference to the fix/change/addition. See previous entries for format.
|
||||
* Once the pull request is visible in the LBRY repo, a LBRY team member will review it and make sure
|
||||
it is up to our standards. At this point, the contributor may have to change his or her code based
|
||||
on our suggestions and comments.
|
||||
|
|
|
@ -50,7 +50,7 @@ distributable packages.
|
|||
|
||||
#### Resetting your Packages
|
||||
|
||||
If the app isn't building, or `yarn xxx` commands aren't working you may need to just reset your `node_modules`. To do so you can run: `rm -r node_modules && yarn` or `del node_modules && yarn` on Windows.
|
||||
If the app isn't building, or `yarn xxx` commands aren't working you may need to just reset your `node_modules`. To do so you can run: `rm -r node_modules && yarn` or `del /s /q node_modules && yarn` on Windows.
|
||||
|
||||
## Contributing
|
||||
|
||||
|
@ -66,4 +66,4 @@ We take security seriously. Please contact security@lbry.io regarding any securi
|
|||
|
||||
## Contact
|
||||
|
||||
The primary contact for this project is [@seanyesmunt](https://github.com/@seanyesmunt)
|
||||
The primary contact for this project is [@seanyesmunt](https://github.com/seanyesmunt)
|
||||
|
|
10
package.json
10
package.json
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "LBRY",
|
||||
"version": "0.21.3",
|
||||
"version": "0.22.0-rc.12",
|
||||
"description": "A browser for the LBRY network, a digital marketplace controlled by its users.",
|
||||
"keywords": [
|
||||
"lbry"
|
||||
|
@ -48,7 +48,7 @@
|
|||
"formik": "^0.10.4",
|
||||
"hast-util-sanitize": "^1.1.2",
|
||||
"keytar": "^4.2.1",
|
||||
"lbry-redux": "lbryio/lbry-redux#30c18725d8c6c141c30c57f0a324d0abb8963b99",
|
||||
"lbry-redux": "lbryio/lbry-redux#be7a07302aab0c5fc40f8c76cff524c7bce327a2",
|
||||
"localforage": "^1.7.1",
|
||||
"mixpanel-browser": "^2.17.1",
|
||||
"moment": "^2.22.0",
|
||||
|
@ -57,11 +57,11 @@
|
|||
"react": "^16.3.0",
|
||||
"react-dom": "^16.3.0",
|
||||
"react-feather": "^1.0.8",
|
||||
"react-markdown": "^2.5.0",
|
||||
"react-modal": "^3.1.7",
|
||||
"react-paginate": "^5.2.1",
|
||||
"react-redux": "^5.0.3",
|
||||
"react-simplemde-editor": "3.6.11",
|
||||
"react-simplemde-editor": "^3.6.15",
|
||||
"react-toggle": "^4.0.2",
|
||||
"react-transition-group": "1.x",
|
||||
"redux": "^3.6.0",
|
||||
"redux-logger": "^3.0.1",
|
||||
|
@ -127,7 +127,7 @@
|
|||
"yarn": "^1.3"
|
||||
},
|
||||
"lbrySettings": {
|
||||
"lbrynetDaemonVersion": "0.19.3",
|
||||
"lbrynetDaemonVersion": "0.20.0",
|
||||
"lbrynetDaemonUrlTemplate": "https://github.com/lbryio/lbry/releases/download/vDAEMONVER/lbrynet-daemon-vDAEMONVER-OSNAME.zip",
|
||||
"lbrynetDaemonDir": "static/daemon",
|
||||
"lbrynetDaemonFileName": "lbrynet-daemon"
|
||||
|
|
|
@ -3,7 +3,6 @@ import isDev from 'electron-is-dev';
|
|||
import windowStateKeeper from 'electron-window-state';
|
||||
|
||||
import setupBarMenu from './menu/setupBarMenu';
|
||||
import setupContextMenu from './menu/setupContextMenu';
|
||||
|
||||
export default appState => {
|
||||
// Get primary display dimensions from Electron.
|
||||
|
@ -65,15 +64,18 @@ export default appState => {
|
|||
// path, so we just strip it off.
|
||||
// - In a URI with a claim ID, like lbry://channel#claimid, Windows interprets the hash mark as
|
||||
// an anchor and converts it to lbry://channel/#claimid. We remove the slash here as well.
|
||||
// - ? also interpreted as an anchor, remove slash also.
|
||||
if (process.platform === 'win32') {
|
||||
deepLinkingURI = deepLinkingURI.replace(/\/$/, '').replace('/#', '#');
|
||||
deepLinkingURI = deepLinkingURI
|
||||
.replace(/\/$/, '')
|
||||
.replace('/#', '#')
|
||||
.replace('/?', '?');
|
||||
}
|
||||
} else {
|
||||
deepLinkingURI = appState.macDeepLinkingURI;
|
||||
}
|
||||
|
||||
setupBarMenu();
|
||||
setupContextMenu(window);
|
||||
|
||||
window.on('close', event => {
|
||||
if (!appState.isQuitting && !appState.autoUpdateAccepted) {
|
||||
|
|
|
@ -75,6 +75,9 @@ app.on('ready', async () => {
|
|||
await installExtensions();
|
||||
}
|
||||
rendererWindow = createWindow(appState);
|
||||
rendererWindow.webContents.on('devtools-opened', () => {
|
||||
rendererWindow.webContents.send('devtools-is-opened');
|
||||
});
|
||||
tray = createTray(rendererWindow);
|
||||
});
|
||||
|
||||
|
@ -176,11 +179,11 @@ ipcMain.on('version-info-requested', () => {
|
|||
},
|
||||
};
|
||||
let result = '';
|
||||
|
||||
const req = https.get(Object.assign(opts, url.parse(latestReleaseAPIURL)), res => {
|
||||
const onSuccess = res => {
|
||||
res.on('data', data => {
|
||||
result += data;
|
||||
});
|
||||
|
||||
res.on('end', () => {
|
||||
const tagName = JSON.parse(result).tag_name;
|
||||
const [, remoteVersion] = tagName.match(/^v([\d.]+(?:-?rc\d+)?)$/);
|
||||
|
@ -199,14 +202,27 @@ ipcMain.on('version-info-requested', () => {
|
|||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
req.on('error', err => {
|
||||
console.log('Failed to get current version from GitHub. Error:', err);
|
||||
if (rendererWindow) {
|
||||
rendererWindow.webContents.send('version-info-received', null);
|
||||
}
|
||||
});
|
||||
const requestLatestRelease = (apiUrl, alreadyRedirected = false) => {
|
||||
const req = https.get(Object.assign(opts, url.parse(apiUrl)), res => {
|
||||
if (res.statusCode === 301 || res.statusCode === 302) {
|
||||
requestLatestRelease(res.headers.location, true);
|
||||
} else {
|
||||
onSuccess(res);
|
||||
}
|
||||
});
|
||||
|
||||
if (alreadyRedirected) return;
|
||||
req.on('error', err => {
|
||||
console.log('Failed to get current version from GitHub. Error:', err);
|
||||
if (rendererWindow) {
|
||||
rendererWindow.webContents.send('version-info-received', null);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
requestLatestRelease(latestReleaseAPIURL);
|
||||
});
|
||||
|
||||
ipcMain.on('get-auth-token', event => {
|
||||
|
@ -242,8 +258,11 @@ const isSecondInstance = app.makeSingleInstance(argv => {
|
|||
// path, so we just strip it off.
|
||||
// - In a URI with a claim ID, like lbry://channel#claimid, Windows interprets the hash mark as
|
||||
// an anchor and converts it to lbry://channel/#claimid. We remove the slash here as well.
|
||||
// - ? also interpreted as an anchor, remove slash also.
|
||||
if (process.platform === 'win32') {
|
||||
URI = URI.replace(/\/$/, '').replace('/#', '#');
|
||||
URI = URI.replace(/\/$/, '')
|
||||
.replace('/#', '#')
|
||||
.replace('/?', '?');
|
||||
}
|
||||
|
||||
rendererWindow.webContents.send('open-uri-requested', URI);
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
// @flow
|
||||
import { Menu, BrowserWindow } from 'electron';
|
||||
import isDev from 'electron-is-dev';
|
||||
|
||||
export default (rendererWindow: BrowserWindow) => {
|
||||
rendererWindow.webContents.on('context-menu', (e, params) => {
|
||||
const { x, y } = params;
|
||||
|
||||
const template = [{ role: 'cut' }, { role: 'copy' }, { role: 'paste' }];
|
||||
|
||||
const developmentTemplateAddition = [
|
||||
{ type: 'separator' },
|
||||
{
|
||||
label: 'Inspect element',
|
||||
click: () => {
|
||||
rendererWindow.inspectElement(x, y);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
if (isDev) {
|
||||
template.push(...developmentTemplateAddition);
|
||||
}
|
||||
|
||||
Menu.buildFromTemplate(template).popup();
|
||||
});
|
||||
};
|
|
@ -7,6 +7,7 @@ import ReactModal from 'react-modal';
|
|||
import throttle from 'util/throttle';
|
||||
import SideBar from 'component/sideBar';
|
||||
import Header from 'component/header';
|
||||
import { openContextMenu } from '../../util/contextMenu';
|
||||
|
||||
type Props = {
|
||||
alertError: (string | {}) => void,
|
||||
|
@ -79,12 +80,12 @@ class App extends React.PureComponent<Props> {
|
|||
|
||||
render() {
|
||||
return (
|
||||
<div id="window">
|
||||
<div id="window" onContextMenu={e => openContextMenu(e)}>
|
||||
<Theme />
|
||||
<main className="page">
|
||||
<SideBar />
|
||||
<Header />
|
||||
<div className="content" id="content">
|
||||
<Header />
|
||||
<Router />
|
||||
<ModalRouter />
|
||||
</div>
|
||||
|
|
|
@ -22,6 +22,7 @@ type Props = {
|
|||
button: ?string, // primary, secondary, alt, link
|
||||
noPadding: ?boolean, // to remove padding and allow circular buttons
|
||||
uppercase: ?boolean,
|
||||
iconColor: ?string,
|
||||
};
|
||||
|
||||
class Button extends React.PureComponent<Props> {
|
||||
|
@ -48,6 +49,7 @@ class Button extends React.PureComponent<Props> {
|
|||
type,
|
||||
noPadding,
|
||||
uppercase,
|
||||
iconColor,
|
||||
...otherProps
|
||||
} = this.props;
|
||||
|
||||
|
@ -82,10 +84,10 @@ class Button extends React.PureComponent<Props> {
|
|||
|
||||
const content = (
|
||||
<span className="btn__content">
|
||||
{icon && <Icon icon={icon} />}
|
||||
{icon && <Icon icon={icon} iconColor={iconColor} />}
|
||||
{label && <span className="btn__label">{label}</span>}
|
||||
{children && children}
|
||||
{iconRight && <Icon icon={iconRight} />}
|
||||
{iconRight && <Icon icon={iconRight} iconColor={iconColor} />}
|
||||
</span>
|
||||
);
|
||||
|
||||
|
|
18
src/renderer/component/categoryList/index.js
Normal file
18
src/renderer/component/categoryList/index.js
Normal file
|
@ -0,0 +1,18 @@
|
|||
import { connect } from 'react-redux';
|
||||
import { doFetchClaimsByChannel } from 'redux/actions/content';
|
||||
import {
|
||||
makeSelectClaimsInChannelForCurrentPage,
|
||||
makeSelectFetchingChannelClaims,
|
||||
} from 'lbry-redux';
|
||||
import CategoryList from './view';
|
||||
|
||||
const select = (state, props) => ({
|
||||
channelClaims: makeSelectClaimsInChannelForCurrentPage(props.categoryLink)(state),
|
||||
fetching: makeSelectFetchingChannelClaims(props.categoryLink)(state),
|
||||
});
|
||||
|
||||
const perform = dispatch => ({
|
||||
fetchChannel: channel => dispatch(doFetchClaimsByChannel(channel)),
|
||||
});
|
||||
|
||||
export default connect(select, perform)(CategoryList);
|
|
@ -5,11 +5,15 @@ import ToolTip from 'component/common/tooltip';
|
|||
import FileCard from 'component/fileCard';
|
||||
import Button from 'component/button';
|
||||
import * as icons from 'constants/icons';
|
||||
import Claim from 'types/claim';
|
||||
|
||||
type Props = {
|
||||
category: string,
|
||||
names: Array<string>,
|
||||
categoryLink?: string,
|
||||
categoryLink: ?string,
|
||||
fetching: boolean,
|
||||
channelClaims: Array<Claim>,
|
||||
fetchChannel: string => void,
|
||||
};
|
||||
|
||||
type State = {
|
||||
|
@ -18,6 +22,11 @@ type State = {
|
|||
};
|
||||
|
||||
class CategoryList extends React.PureComponent<Props, State> {
|
||||
static defaultProps = {
|
||||
names: [],
|
||||
categoryLink: '',
|
||||
};
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
|
@ -32,6 +41,11 @@ class CategoryList extends React.PureComponent<Props, State> {
|
|||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { fetching, categoryLink, fetchChannel } = this.props;
|
||||
if (!fetching && categoryLink) {
|
||||
fetchChannel(categoryLink);
|
||||
}
|
||||
|
||||
const cardRow = this.rowItems;
|
||||
if (cardRow) {
|
||||
const cards = cardRow.getElementsByTagName('section');
|
||||
|
@ -109,6 +123,9 @@ class CategoryList extends React.PureComponent<Props, State> {
|
|||
|
||||
// check if a card is fully visible horizontally
|
||||
isCardVisible = (section: HTMLElement) => {
|
||||
if (!section) {
|
||||
return false;
|
||||
}
|
||||
const rect = section.getBoundingClientRect();
|
||||
const isVisible = rect.left >= 0 && rect.right <= window.innerWidth;
|
||||
return isVisible;
|
||||
|
@ -189,7 +206,7 @@ class CategoryList extends React.PureComponent<Props, State> {
|
|||
}
|
||||
|
||||
render() {
|
||||
const { category, names, categoryLink } = this.props;
|
||||
const { category, categoryLink, names, channelClaims } = this.props;
|
||||
const { canScrollNext, canScrollPrevious } = this.state;
|
||||
|
||||
// The lint was throwing an error saying we should use <button> instead of <a>
|
||||
|
@ -235,6 +252,12 @@ class CategoryList extends React.PureComponent<Props, State> {
|
|||
className="card-row__scrollhouse"
|
||||
>
|
||||
{names && names.map(name => <FileCard key={name} uri={normalizeURI(name)} />)}
|
||||
|
||||
{channelClaims && channelClaims.length
|
||||
? channelClaims.map(claim => (
|
||||
<FileCard key={claim.claim_id} uri={`lbry://${claim.name}#${claim.claim_id}`} />
|
||||
))
|
||||
: null}
|
||||
</div>
|
||||
</div>
|
||||
);
|
|
@ -9,6 +9,8 @@ type Props = {
|
|||
type: string,
|
||||
currentPath: ?string,
|
||||
onFileChosen: (string, string) => void,
|
||||
fileLabel: ?string,
|
||||
directoryLabel?: string,
|
||||
};
|
||||
|
||||
class FileSelector extends React.PureComponent<Props> {
|
||||
|
@ -47,15 +49,14 @@ class FileSelector extends React.PureComponent<Props> {
|
|||
input: ?HTMLInputElement;
|
||||
|
||||
render() {
|
||||
const { type, currentPath } = this.props;
|
||||
const { type, currentPath, fileLabel, directoryLabel } = this.props;
|
||||
|
||||
const label =
|
||||
type === 'file' ? fileLabel || __('Choose File') : directoryLabel || __('Choose Directory');
|
||||
|
||||
return (
|
||||
<FormRow verticallyCentered padded>
|
||||
<Button
|
||||
button="primary"
|
||||
onClick={() => this.handleButtonClick()}
|
||||
label={type === 'file' ? __('Choose File') : __('Choose Directory')}
|
||||
/>
|
||||
<Button button="primary" onClick={() => this.handleButtonClick()} label={label} />
|
||||
<input
|
||||
webkitdirectory="true"
|
||||
className="input-copyable"
|
||||
|
|
|
@ -62,7 +62,6 @@ export class FormFieldPrice extends React.PureComponent<Props> {
|
|||
name={`${name}_currency`}
|
||||
type="select"
|
||||
id={`${name}_currency`}
|
||||
className="form-field"
|
||||
disabled={disabled}
|
||||
onChange={this.handleCurrencyChange}
|
||||
value={price.currency}
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
// @flow
|
||||
import * as React from 'react';
|
||||
import ReactDOMServer from 'react-dom/server';
|
||||
import classnames from 'classnames';
|
||||
import MarkdownPreview from 'component/common/markdown-preview';
|
||||
import SimpleMDE from 'react-simplemde-editor';
|
||||
import style from 'react-simplemde-editor/dist/simplemde.min.css'; // eslint-disable-line no-unused-vars
|
||||
import 'simplemde/dist/simplemde.min.css';
|
||||
import Toggle from 'react-toggle';
|
||||
|
||||
type Props = {
|
||||
name: string,
|
||||
|
@ -18,6 +21,8 @@ type Props = {
|
|||
placeholder?: string | number,
|
||||
children?: React.Node,
|
||||
stretch?: boolean,
|
||||
affixClass?: string, // class applied to prefix/postfix label
|
||||
useToggle?: boolean,
|
||||
};
|
||||
|
||||
export class FormField extends React.PureComponent<Props> {
|
||||
|
@ -33,6 +38,8 @@ export class FormField extends React.PureComponent<Props> {
|
|||
type,
|
||||
children,
|
||||
stretch,
|
||||
affixClass,
|
||||
useToggle,
|
||||
...inputProps
|
||||
} = this.props;
|
||||
|
||||
|
@ -42,7 +49,7 @@ export class FormField extends React.PureComponent<Props> {
|
|||
if (type) {
|
||||
if (type === 'select') {
|
||||
input = (
|
||||
<select id={name} {...inputProps}>
|
||||
<select className="form-field__select" id={name} {...inputProps}>
|
||||
{children}
|
||||
</select>
|
||||
);
|
||||
|
@ -52,12 +59,20 @@ export class FormField extends React.PureComponent<Props> {
|
|||
<SimpleMDE
|
||||
{...inputProps}
|
||||
type="textarea"
|
||||
options={{ hideIcons: ['heading', 'image', 'fullscreen', 'side-by-side'] }}
|
||||
options={{
|
||||
hideIcons: ['heading', 'image', 'fullscreen', 'side-by-side'],
|
||||
previewRender(plainText) {
|
||||
const preview = <MarkdownPreview content={plainText} />;
|
||||
return ReactDOMServer.renderToString(preview);
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
} else if (type === 'textarea') {
|
||||
input = <textarea type={type} id={name} {...inputProps} />;
|
||||
} else if (type === 'checkbox' && useToggle) {
|
||||
input = <Toggle id={name} {...inputProps} />;
|
||||
} else {
|
||||
input = <input type={type} id={name} {...inputProps} />;
|
||||
}
|
||||
|
@ -84,22 +99,18 @@ export class FormField extends React.PureComponent<Props> {
|
|||
})}
|
||||
>
|
||||
{prefix && (
|
||||
<label htmlFor={name} className="form-field__prefix">
|
||||
<label htmlFor={name} className={classnames('form-field__prefix', affixClass)}>
|
||||
{prefix}
|
||||
</label>
|
||||
)}
|
||||
{input}
|
||||
{postfix && (
|
||||
<label htmlFor={name} className="form-field__postfix">
|
||||
<label htmlFor={name} className={classnames('form-field__postfix', affixClass)}>
|
||||
{postfix}
|
||||
</label>
|
||||
)}
|
||||
</div>
|
||||
{helper && (
|
||||
<label htmlFor={name} className="form-field__help">
|
||||
{helper}
|
||||
</label>
|
||||
)}
|
||||
{helper && <div className="form-field__help">{helper}</div>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@ import * as React from 'react';
|
|||
import classnames from 'classnames';
|
||||
|
||||
type Props = {
|
||||
centered?: boolean,
|
||||
children: React.Node,
|
||||
padded?: boolean,
|
||||
verticallyCentered?: boolean,
|
||||
|
@ -22,7 +21,6 @@ export class FormRow extends React.PureComponent<Props> {
|
|||
return (
|
||||
<div
|
||||
className={classnames('form-row', {
|
||||
'form-row--centered': centered,
|
||||
'form-row--padded': padded,
|
||||
'form-row--vertically-centered': verticallyCentered,
|
||||
'form-row--stretch': stretch,
|
||||
|
|
|
@ -1,26 +1,52 @@
|
|||
// @flow
|
||||
import React from 'react';
|
||||
// import * as icons from 'constants/icons';
|
||||
import * as FeatherIcons from 'react-feather';
|
||||
import * as icons from 'constants/icons';
|
||||
import Tooltip from 'component/common/tooltip';
|
||||
|
||||
const RED_COLOR = '#e2495e';
|
||||
const PURPLE_COLOR = '#8165b0';
|
||||
|
||||
type Props = {
|
||||
icon: string,
|
||||
tooltip?: string, // tooltip direction
|
||||
iconColor?: string,
|
||||
};
|
||||
|
||||
class IconComponent extends React.PureComponent<Props> {
|
||||
// TODO: Move all icons to constants and add titles for all
|
||||
// Add some some sort of hover flyout with the title?
|
||||
getTooltip = (icon: string) => {
|
||||
switch (icon) {
|
||||
case icons.FEATURED:
|
||||
return __('Featured content. Earn rewards for watching.');
|
||||
case icons.LOCAL:
|
||||
return __('This file is downloaded.');
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
getIconColor = (color: string) => {
|
||||
switch (color) {
|
||||
case 'red':
|
||||
return RED_COLOR;
|
||||
case 'purple':
|
||||
return PURPLE_COLOR;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const { icon } = this.props;
|
||||
const { icon, tooltip, iconColor } = this.props;
|
||||
const Icon = FeatherIcons[icon];
|
||||
|
||||
if (!Icon) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let color;
|
||||
if (icon === icons.HEART || icon === icons.FEATURED) {
|
||||
color = RED_COLOR;
|
||||
if (iconColor) {
|
||||
color = this.getIconColor(iconColor);
|
||||
}
|
||||
|
||||
let size = 14;
|
||||
|
@ -28,7 +54,19 @@ class IconComponent extends React.PureComponent<Props> {
|
|||
size = 20;
|
||||
}
|
||||
|
||||
return Icon ? <Icon size={size} className="icon" color={color} /> : null;
|
||||
let tooltipText;
|
||||
if (tooltip) {
|
||||
tooltipText = this.getTooltip(icon);
|
||||
}
|
||||
const inner = <Icon size={size} className="icon" color={color} />;
|
||||
|
||||
return tooltip ? (
|
||||
<Tooltip icon body={tooltipText} direction={tooltip}>
|
||||
{inner}
|
||||
</Tooltip>
|
||||
) : (
|
||||
inner
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,14 +11,19 @@ const schema = { ...defaultSchema };
|
|||
// Extend sanitation schema to support lbry protocol
|
||||
schema.protocols.href[3] = 'lbry';
|
||||
|
||||
type MarkdownProps = { content: string };
|
||||
type MarkdownProps = {
|
||||
content: string,
|
||||
promptLinks?: boolean,
|
||||
};
|
||||
|
||||
const SimpleLink = ({ href, title, children }) => (<a href={href} title={title}>{children}</a>);
|
||||
|
||||
const MarkdownPreview = (props: MarkdownProps) => {
|
||||
const { content } = props;
|
||||
const { content, externalLinks, promptLinks } = props;
|
||||
const remarkOptions = {
|
||||
sanitize: schema,
|
||||
remarkReactComponents: {
|
||||
a: ExternalLink,
|
||||
a: promptLinks ? ExternalLink : SimpleLink,
|
||||
},
|
||||
};
|
||||
return (
|
|
@ -6,19 +6,22 @@ import classnames from 'classnames';
|
|||
type Props = {
|
||||
value: string,
|
||||
paddingRight?: boolean,
|
||||
paddingTop?: boolean,
|
||||
};
|
||||
|
||||
class QRCode extends React.Component<Props> {
|
||||
static defaultProps = {
|
||||
paddingRight: false,
|
||||
paddingTop: false,
|
||||
};
|
||||
|
||||
render() {
|
||||
const { value, paddingRight } = this.props;
|
||||
const { value, paddingRight, paddingTop } = this.props;
|
||||
return (
|
||||
<div
|
||||
className={classnames('qr-code', {
|
||||
'qr-code--right-padding': paddingRight,
|
||||
'qr-code--top-padding': paddingTop,
|
||||
})}
|
||||
>
|
||||
<QRCodeElement value={value} />
|
||||
|
|
|
@ -1,55 +1,40 @@
|
|||
// @flow
|
||||
import React from 'react';
|
||||
import * as React from 'react';
|
||||
import classnames from 'classnames';
|
||||
import Icon from 'component/common/icon';
|
||||
import Button from 'component/button';
|
||||
import * as icons from 'constants/icons';
|
||||
|
||||
type Props = {
|
||||
body: string,
|
||||
label: string,
|
||||
label?: string,
|
||||
children: ?React.Node,
|
||||
icon: ?boolean,
|
||||
direction: string,
|
||||
onFormField?: boolean,
|
||||
};
|
||||
|
||||
type State = {
|
||||
showTooltip: boolean,
|
||||
};
|
||||
|
||||
class ToolTip extends React.PureComponent<Props, State> {
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
showTooltip: false,
|
||||
};
|
||||
|
||||
(this: any).handleClick = this.handleClick.bind(this);
|
||||
}
|
||||
|
||||
handleClick() {
|
||||
const { showTooltip } = this.state;
|
||||
|
||||
if (!showTooltip) {
|
||||
document.addEventListener('click', this.handleClick);
|
||||
} else {
|
||||
document.removeEventListener('click', this.handleClick);
|
||||
}
|
||||
|
||||
this.setState({
|
||||
showTooltip: !showTooltip,
|
||||
});
|
||||
}
|
||||
class ToolTip extends React.PureComponent<Props> {
|
||||
static defaultProps = {
|
||||
direction: 'bottom',
|
||||
};
|
||||
|
||||
render() {
|
||||
const { label, body } = this.props;
|
||||
const { showTooltip } = this.state;
|
||||
const { children, label, body, icon, direction, onFormField } = this.props;
|
||||
|
||||
const tooltipContent = children || label;
|
||||
|
||||
return (
|
||||
<span className="tooltip">
|
||||
<Button button="link" className="help tooltip__link" onClick={this.handleClick}>
|
||||
{label}
|
||||
{showTooltip && <Icon icon={icons.CLOSE} />}
|
||||
</Button>
|
||||
<div className={classnames('tooltip__body', { hidden: !showTooltip })}>{body}</div>
|
||||
<span
|
||||
className={classnames('tooltip', {
|
||||
'tooltip--label': label && !icon,
|
||||
'tooltip--icon': icon,
|
||||
'tooltip--top': direction === 'top',
|
||||
'tooltip--right': direction === 'right',
|
||||
'tooltip--bottom': direction === 'bottom',
|
||||
'tooltip--left': direction === 'left',
|
||||
'tooltip--on-formfield': onFormField,
|
||||
})}
|
||||
>
|
||||
{tooltipContent}
|
||||
<span className="tooltip__body">{body}</span>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@ class ExternalLink extends React.PureComponent<Props> {
|
|||
|
||||
createLink() {
|
||||
const { href, title, children, openModal, navigate } = this.props;
|
||||
console.info(href);
|
||||
|
||||
// Regex for url protocol
|
||||
const protocolRegex = new RegExp('^(https?|lbry)+:', 'i');
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
// @flow
|
||||
import React from 'react';
|
||||
import Button from 'component/button';
|
||||
import FileDownloadLink from 'component/fileDownloadLink';
|
||||
import { MODALS } from 'lbry-redux';
|
||||
import classnames from 'classnames';
|
||||
import * as icons from 'constants/icons';
|
||||
|
@ -12,6 +11,7 @@ type FileInfo = {
|
|||
|
||||
type Props = {
|
||||
uri: string,
|
||||
claimId: string,
|
||||
openModal: ({ id: string }, { uri: string }) => void,
|
||||
claimIsMine: boolean,
|
||||
fileInfo: FileInfo,
|
||||
|
@ -20,28 +20,26 @@ type Props = {
|
|||
|
||||
class FileActions extends React.PureComponent<Props> {
|
||||
render() {
|
||||
const { fileInfo, uri, openModal, claimIsMine, vertical } = this.props;
|
||||
|
||||
const claimId = fileInfo ? fileInfo.claim_id : '';
|
||||
const { fileInfo, uri, openModal, claimIsMine, vertical, claimId } = this.props;
|
||||
const showDelete = fileInfo && Object.keys(fileInfo).length > 0;
|
||||
|
||||
return (
|
||||
<section className={classnames('card__actions', { 'card__actions--vertical': vertical })}>
|
||||
<FileDownloadLink uri={uri} />
|
||||
{showDelete && (
|
||||
<Button
|
||||
className="btn--file-actions"
|
||||
button="alt"
|
||||
icon={icons.TRASH}
|
||||
description={__('Delete')}
|
||||
iconColor="red"
|
||||
label={__('Delete')}
|
||||
onClick={() => openModal({ id: MODALS.CONFIRM_FILE_REMOVE }, { uri })}
|
||||
/>
|
||||
)}
|
||||
{!claimIsMine && (
|
||||
<Button
|
||||
className="btn--file-actions"
|
||||
button="alt"
|
||||
icon={icons.REPORT}
|
||||
href={`https://lbry.io/dmca?claim_id=${claimId}`}
|
||||
description={__('Report content')}
|
||||
label={__('Report content')}
|
||||
/>
|
||||
)}
|
||||
</section>
|
||||
|
|
|
@ -5,6 +5,7 @@ import {
|
|||
makeSelectMetadataForUri,
|
||||
makeSelectFileInfoForUri,
|
||||
makeSelectIsUriResolving,
|
||||
makeSelectClaimIsMine,
|
||||
} from 'lbry-redux';
|
||||
import { doNavigate } from 'redux/actions/navigation';
|
||||
import { selectRewardContentClaimIds } from 'redux/selectors/content';
|
||||
|
@ -27,6 +28,7 @@ const select = (state, props) => {
|
|||
|
||||
return {
|
||||
obscureNsfw: !selectShowNsfw(state),
|
||||
claimIsMine: makeSelectClaimIsMine(props.uri)(state),
|
||||
rewardedContentClaimIds: selectRewardContentClaimIds(state, props),
|
||||
...fileCardInfo,
|
||||
pending: !!pendingPublish,
|
||||
|
@ -38,4 +40,7 @@ const perform = dispatch => ({
|
|||
resolveUri: uri => dispatch(doResolveUri(uri)),
|
||||
});
|
||||
|
||||
export default connect(select, perform)(FileCard);
|
||||
export default connect(
|
||||
select,
|
||||
perform
|
||||
)(FileCard);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// @flow
|
||||
import * as React from 'react';
|
||||
import { normalizeURI } from 'lbry-redux';
|
||||
import { normalizeURI, convertToShareLink } from 'lbry-redux';
|
||||
import Button from 'component/button';
|
||||
import CardMedia from 'component/cardMedia';
|
||||
import TruncatedText from 'component/common/truncated-text';
|
||||
|
@ -9,18 +9,24 @@ import FilePrice from 'component/filePrice';
|
|||
import UriIndicator from 'component/uriIndicator';
|
||||
import * as icons from 'constants/icons';
|
||||
import classnames from 'classnames';
|
||||
import { openCopyLinkMenu } from '../../util/contextMenu';
|
||||
|
||||
// TODO: iron these out
|
||||
type Props = {
|
||||
uri: string,
|
||||
claim: ?{ claim_id: string },
|
||||
fileInfo: ?{},
|
||||
metadata: ?{ nsfw: boolean, thumbnail: ?string },
|
||||
metadata: ?{ nsfw: boolean, title: string, thumbnail: ?string },
|
||||
navigate: (string, ?{}) => void,
|
||||
rewardedContentClaimIds: Array<string>,
|
||||
obscureNsfw: boolean,
|
||||
claimIsMine: boolean,
|
||||
showPrice: boolean,
|
||||
pending?: boolean,
|
||||
/* eslint-disable react/no-unused-prop-types */
|
||||
resolveUri: string => void,
|
||||
isResolvingUri: boolean,
|
||||
/* eslint-enable react/no-unused-prop-types */
|
||||
};
|
||||
|
||||
class FileCard extends React.PureComponent<Props> {
|
||||
|
@ -52,14 +58,20 @@ class FileCard extends React.PureComponent<Props> {
|
|||
navigate,
|
||||
rewardedContentClaimIds,
|
||||
obscureNsfw,
|
||||
claimIsMine,
|
||||
showPrice,
|
||||
pending,
|
||||
} = this.props;
|
||||
const uri = !pending ? normalizeURI(this.props.uri) : this.props.uri;
|
||||
const title = metadata && metadata.title ? metadata.title : uri;
|
||||
const thumbnail = metadata && metadata.thumbnail ? metadata.thumbnail : null;
|
||||
const shouldObscureNsfw = obscureNsfw && metadata && metadata.nsfw;
|
||||
const shouldObscureNsfw = obscureNsfw && metadata && metadata.nsfw && !claimIsMine;
|
||||
const isRewardContent = claim && rewardedContentClaimIds.includes(claim.claim_id);
|
||||
const handleContextMenu = event => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
openCopyLinkMenu(convertToShareLink(uri), event);
|
||||
};
|
||||
|
||||
// We should be able to tab through cards
|
||||
/* eslint-disable jsx-a11y/click-events-have-key-events */
|
||||
|
@ -72,6 +84,7 @@ class FileCard extends React.PureComponent<Props> {
|
|||
'card--link': !pending,
|
||||
'card--pending': pending,
|
||||
})}
|
||||
onContextMenu={handleContextMenu}
|
||||
>
|
||||
<CardMedia nsfw={shouldObscureNsfw} thumbnail={thumbnail} />
|
||||
<div className="card-media__internal-links">{showPrice && <FilePrice uri={uri} />}</div>
|
||||
|
@ -98,14 +111,16 @@ class FileCard extends React.PureComponent<Props> {
|
|||
<div className="card__title--small">
|
||||
<TruncatedText lines={3}>{title}</TruncatedText>
|
||||
</div>
|
||||
<div className="card__subtitle card__subtitle--file-info">
|
||||
<div className="card__subtitle">
|
||||
{pending ? (
|
||||
<div>Pending...</div>
|
||||
) : (
|
||||
<React.Fragment>
|
||||
<UriIndicator uri={uri} link />
|
||||
{isRewardContent && <Icon icon={icons.FEATURED} />}
|
||||
{fileInfo && <Icon icon={icons.LOCAL} />}
|
||||
<div>
|
||||
{isRewardContent && <Icon iconColor="red" icon={icons.FEATURED} />}
|
||||
{fileInfo && <Icon icon={icons.LOCAL} />}
|
||||
</div>
|
||||
</React.Fragment>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// @flow
|
||||
import * as React from 'react';
|
||||
import MarkdownPreview from 'component/markdownPreview';
|
||||
import MarkdownPreview from 'component/common/markdown-preview';
|
||||
import Button from 'component/button';
|
||||
import path from 'path';
|
||||
import type { Claim } from 'types/claim';
|
||||
|
@ -41,7 +41,7 @@ const FileDetails = (props: Props) => {
|
|||
<React.Fragment>
|
||||
<div className="card__subtext-title">About</div>
|
||||
<div className="card__subtext">
|
||||
<MarkdownPreview content={description} />
|
||||
<MarkdownPreview content={description} promptLinks={true} />
|
||||
</div>
|
||||
</React.Fragment>
|
||||
)}
|
||||
|
|
|
@ -5,7 +5,6 @@ import {
|
|||
makeSelectLoadingForUri,
|
||||
makeSelectCostInfoForUri,
|
||||
} from 'lbry-redux';
|
||||
import { doFetchAvailability } from 'redux/actions/availability';
|
||||
import { doOpenFileInShell } from 'redux/actions/file';
|
||||
import { doPurchaseUri, doStartDownload } from 'redux/actions/content';
|
||||
import { doPause } from 'redux/actions/media';
|
||||
|
@ -20,7 +19,6 @@ const select = (state, props) => ({
|
|||
});
|
||||
|
||||
const perform = dispatch => ({
|
||||
checkAvailability: uri => dispatch(doFetchAvailability(uri)),
|
||||
openInShell: path => dispatch(doOpenFileInShell(path)),
|
||||
purchaseUri: uri => dispatch(doPurchaseUri(uri)),
|
||||
restartDownload: (uri, outpoint) => dispatch(doStartDownload(uri, outpoint)),
|
||||
|
|
|
@ -1,21 +1,29 @@
|
|||
// @flow
|
||||
import React from 'react';
|
||||
import Button from 'component/button';
|
||||
import classnames from 'classnames';
|
||||
import * as icons from 'constants/icons';
|
||||
|
||||
class FileDownloadLink extends React.PureComponent {
|
||||
componentWillMount() {
|
||||
this.checkAvailability(this.props.uri);
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
this.checkAvailability(nextProps.uri);
|
||||
this.restartDownload(nextProps);
|
||||
}
|
||||
|
||||
restartDownload(props) {
|
||||
const { downloading, fileInfo, uri, restartDownload } = props;
|
||||
type Props = {
|
||||
uri: string,
|
||||
downloading: boolean,
|
||||
fileInfo: ?{
|
||||
written_bytes: number,
|
||||
total_bytes: number,
|
||||
outpoint: number,
|
||||
download_path: string,
|
||||
completed: boolean,
|
||||
},
|
||||
loading: boolean,
|
||||
costInfo: ?{},
|
||||
restartDownload: (string, number) => void,
|
||||
openInShell: string => void,
|
||||
purchaseUri: string => void,
|
||||
doPause: () => void,
|
||||
};
|
||||
|
||||
class FileDownloadLink extends React.PureComponent<Props> {
|
||||
componentWillUpdate() {
|
||||
const { downloading, fileInfo, uri, restartDownload } = this.props;
|
||||
if (
|
||||
!downloading &&
|
||||
fileInfo &&
|
||||
|
@ -27,12 +35,7 @@ class FileDownloadLink extends React.PureComponent {
|
|||
}
|
||||
}
|
||||
|
||||
checkAvailability(uri) {
|
||||
if (!this._uri || uri !== this._uri) {
|
||||
this._uri = uri;
|
||||
this.props.checkAvailability(uri);
|
||||
}
|
||||
}
|
||||
uri: ?string;
|
||||
|
||||
render() {
|
||||
const {
|
||||
|
@ -47,8 +50,10 @@ class FileDownloadLink extends React.PureComponent {
|
|||
} = this.props;
|
||||
|
||||
const openFile = () => {
|
||||
openInShell(fileInfo.download_path);
|
||||
doPause();
|
||||
if (fileInfo) {
|
||||
openInShell(fileInfo.download_path);
|
||||
doPause();
|
||||
}
|
||||
};
|
||||
|
||||
if (loading || downloading) {
|
||||
|
@ -56,21 +61,11 @@ class FileDownloadLink extends React.PureComponent {
|
|||
fileInfo && fileInfo.written_bytes
|
||||
? fileInfo.written_bytes / fileInfo.total_bytes * 100
|
||||
: 0;
|
||||
const label = fileInfo ? progress.toFixed(0) + __('% complete') : __('Connecting...');
|
||||
const label = fileInfo
|
||||
? __('Downloading: ') + progress.toFixed(0) + __('% complete')
|
||||
: __('Connecting...');
|
||||
|
||||
return (
|
||||
<div className="file-download btn__content">
|
||||
<div
|
||||
className={classnames('file-download__overlay', {
|
||||
btn__content: !!progress,
|
||||
})}
|
||||
style={{ width: `${progress}%` }}
|
||||
>
|
||||
{label}
|
||||
</div>
|
||||
{label}
|
||||
</div>
|
||||
);
|
||||
return <span className="file-download">{label}</span>;
|
||||
} else if (fileInfo === null && !downloading) {
|
||||
if (!costInfo) {
|
||||
return null;
|
||||
|
@ -78,9 +73,10 @@ class FileDownloadLink extends React.PureComponent {
|
|||
|
||||
return (
|
||||
<Button
|
||||
className="btn--file-actions"
|
||||
description={__('Download')}
|
||||
button="alt"
|
||||
label={__('Download')}
|
||||
icon={icons.DOWNLOAD}
|
||||
iconColor="purple"
|
||||
onClick={() => {
|
||||
purchaseUri(uri);
|
||||
}}
|
||||
|
@ -89,8 +85,9 @@ class FileDownloadLink extends React.PureComponent {
|
|||
} else if (fileInfo && fileInfo.download_path) {
|
||||
return (
|
||||
<Button
|
||||
className="btn--file-actions"
|
||||
description={__('Open')}
|
||||
button="alt"
|
||||
iconColor="purple"
|
||||
label={__('Open File')}
|
||||
icon={icons.OPEN}
|
||||
onClick={() => openFile()}
|
||||
/>
|
||||
|
|
|
@ -8,6 +8,7 @@ type FileInfo = {
|
|||
name: string,
|
||||
channelName: ?string,
|
||||
pending?: boolean,
|
||||
channel_claim_id: string,
|
||||
value?: {
|
||||
publisherSignature: {
|
||||
certificateId: string,
|
||||
|
@ -139,6 +140,8 @@ class FileList extends React.PureComponent<Props, State> {
|
|||
});
|
||||
}
|
||||
|
||||
sortFunctions: {};
|
||||
|
||||
render() {
|
||||
const { fileInfos, hideFilter, checkPending } = this.props;
|
||||
const { sortBy } = this.state;
|
||||
|
@ -149,27 +152,14 @@ class FileList extends React.PureComponent<Props, State> {
|
|||
}
|
||||
|
||||
this.sortFunctions[sortBy](fileInfos).forEach(fileInfo => {
|
||||
const {
|
||||
channel_name: channelName,
|
||||
name: claimName,
|
||||
claim_name: claimNameDownloaded,
|
||||
claim_id: claimId,
|
||||
} = fileInfo;
|
||||
const { name: claimName, claim_name: claimNameDownloaded, claim_id: claimId } = fileInfo;
|
||||
const uriParams = {};
|
||||
|
||||
// This is unfortunate
|
||||
// https://github.com/lbryio/lbry/issues/1159
|
||||
const name = claimName || claimNameDownloaded;
|
||||
|
||||
if (channelName) {
|
||||
uriParams.channelName = channelName;
|
||||
uriParams.contentName = name;
|
||||
uriParams.claimId = this.getChannelSignature(fileInfo);
|
||||
} else {
|
||||
uriParams.claimId = claimId;
|
||||
uriParams.claimName = name;
|
||||
}
|
||||
|
||||
uriParams.contentName = name;
|
||||
uriParams.claimId = claimId;
|
||||
const uri = buildURI(uriParams);
|
||||
|
||||
content.push(<FileCard key={uri} uri={uri} checkPending={checkPending} />);
|
||||
|
@ -181,6 +171,7 @@ class FileList extends React.PureComponent<Props, State> {
|
|||
{!hideFilter && (
|
||||
<FormField
|
||||
prefix={__('Sort by')}
|
||||
affixClass="form-field--align-center"
|
||||
type="select"
|
||||
value={sortBy}
|
||||
onChange={this.handleSortChanged}
|
||||
|
|
|
@ -58,7 +58,7 @@ class FileListSearch extends React.PureComponent<Props> {
|
|||
return (
|
||||
query && (
|
||||
<div className="search__results">
|
||||
<div className="search-result__column">
|
||||
<div className="search-result__row">
|
||||
<div className="file-list__header">{__('Content')}</div>
|
||||
{!isSearching &&
|
||||
(fileResults.length ? (
|
||||
|
@ -68,7 +68,7 @@ class FileListSearch extends React.PureComponent<Props> {
|
|||
))}
|
||||
</div>
|
||||
|
||||
<div className="search-result__column">
|
||||
<div className="search-result__row">
|
||||
<div className="file-list__header">{__('Channels')}</div>
|
||||
{!isSearching &&
|
||||
(channelResults.length ? (
|
||||
|
@ -78,7 +78,7 @@ class FileListSearch extends React.PureComponent<Props> {
|
|||
))}
|
||||
</div>
|
||||
|
||||
<div className="search-result__column">
|
||||
<div className="search-result__row">
|
||||
<div className="file-list__header">{__('Your downloads')}</div>
|
||||
{downloadUris && downloadUris.length ? (
|
||||
downloadUris.map(uri => <FileTile hideNoResult key={uri} uri={uri} />)
|
||||
|
|
|
@ -35,20 +35,14 @@ class FilePrice extends React.PureComponent<Props> {
|
|||
render() {
|
||||
const { costInfo, showFullPrice } = this.props;
|
||||
|
||||
const isEstimate = costInfo ? !costInfo.includesData : false;
|
||||
|
||||
if (!costInfo) {
|
||||
return <span className="credit-amount">PRICE</span>;
|
||||
}
|
||||
|
||||
return (
|
||||
return costInfo ? (
|
||||
<CreditAmount
|
||||
amount={costInfo.cost}
|
||||
isEstimate={isEstimate}
|
||||
isEstimate={!costInfo.includesData}
|
||||
showFree
|
||||
showFullPrice={showFullPrice}
|
||||
/>
|
||||
);
|
||||
) : null;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,9 @@ import {
|
|||
makeSelectMetadataForUri,
|
||||
makeSelectFileInfoForUri,
|
||||
makeSelectIsUriResolving,
|
||||
makeSelectClaimIsMine,
|
||||
} from 'lbry-redux';
|
||||
import { selectShowNsfw } from 'redux/selectors/settings';
|
||||
import { doNavigate } from 'redux/actions/navigation';
|
||||
import { doClearPublish, doUpdatePublishForm } from 'redux/actions/publish';
|
||||
import { selectRewardContentClaimIds } from 'redux/selectors/content';
|
||||
|
@ -17,6 +19,8 @@ const select = (state, props) => ({
|
|||
metadata: makeSelectMetadataForUri(props.uri)(state),
|
||||
isResolvingUri: makeSelectIsUriResolving(props.uri)(state),
|
||||
rewardedContentClaimIds: selectRewardContentClaimIds(state, props),
|
||||
obscureNsfw: !selectShowNsfw(state),
|
||||
claimIsMine: makeSelectClaimIsMine(props.uri)(state),
|
||||
});
|
||||
|
||||
const perform = dispatch => ({
|
||||
|
|
|
@ -13,6 +13,8 @@ type Props = {
|
|||
fullWidth: boolean, // removes the max-width css
|
||||
showUri: boolean,
|
||||
showLocal: boolean,
|
||||
obscureNsfw: boolean,
|
||||
claimIsMine: boolean,
|
||||
isDownloaded: boolean,
|
||||
uri: string,
|
||||
isResolvingUri: boolean,
|
||||
|
@ -58,6 +60,8 @@ class FileTile extends React.PureComponent<Props> {
|
|||
navigate,
|
||||
rewardedContentClaimIds,
|
||||
showUri,
|
||||
obscureNsfw,
|
||||
claimIsMine,
|
||||
fullWidth,
|
||||
showLocal,
|
||||
isDownloaded,
|
||||
|
@ -68,10 +72,12 @@ class FileTile extends React.PureComponent<Props> {
|
|||
|
||||
const uri = normalizeURI(this.props.uri);
|
||||
const isClaimed = !!claim;
|
||||
const description = isClaimed && metadata && metadata.description ? metadata.description : '';
|
||||
const title =
|
||||
isClaimed && metadata && metadata.title ? metadata.title : parseURI(uri).contentName;
|
||||
const thumbnail = metadata && metadata.thumbnail ? metadata.thumbnail : null;
|
||||
const isRewardContent = claim && rewardedContentClaimIds.includes(claim.claim_id);
|
||||
const shouldObscureNsfw = obscureNsfw && metadata && metadata.nsfw && !claimIsMine;
|
||||
|
||||
const onClick = () => navigate('/show', { uri });
|
||||
|
||||
|
@ -92,7 +98,7 @@ class FileTile extends React.PureComponent<Props> {
|
|||
role="button"
|
||||
tabIndex="0"
|
||||
>
|
||||
<CardMedia title={title || name} thumbnail={thumbnail} />
|
||||
<CardMedia title={title || name} thumbnail={thumbnail} nsfw={shouldObscureNsfw} />
|
||||
<div className="file-tile__info">
|
||||
{isResolvingUri && <div className="card__title--small">{__('Loading...')}</div>}
|
||||
{!isResolvingUri && (
|
||||
|
@ -104,9 +110,12 @@ class FileTile extends React.PureComponent<Props> {
|
|||
{showUri ? uri : channel || __('Anonymous')}
|
||||
{isRewardContent && <Icon icon={icons.FEATURED} />}
|
||||
{showLocal && isDownloaded && <Icon icon={icons.LOCAL} />}
|
||||
<div className="card__subtitle-price">
|
||||
<FilePrice uri={uri} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="card__subtext card__subtext--small">
|
||||
<TruncatedText lines={3}>{description}</TruncatedText>
|
||||
</div>
|
||||
<div className="card__subtitle-price">
|
||||
<FilePrice uri={uri} />
|
||||
</div>
|
||||
{!name && (
|
||||
<React.Fragment>
|
||||
|
|
|
@ -1,26 +1,17 @@
|
|||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import InviteNew from './view';
|
||||
import {
|
||||
selectUserInvitesRemaining,
|
||||
selectUserInviteNewIsPending,
|
||||
selectUserInviteNewErrorMessage,
|
||||
} from 'redux/selectors/user';
|
||||
import rewards from 'rewards';
|
||||
import { makeSelectRewardAmountByType } from 'redux/selectors/rewards';
|
||||
|
||||
import { doUserInviteNew } from 'redux/actions/user';
|
||||
import InviteNew from './view';
|
||||
|
||||
const select = state => {
|
||||
const selectReward = makeSelectRewardAmountByType();
|
||||
|
||||
return {
|
||||
errorMessage: selectUserInviteNewErrorMessage(state),
|
||||
invitesRemaining: selectUserInvitesRemaining(state),
|
||||
isPending: selectUserInviteNewIsPending(state),
|
||||
rewardAmount: selectReward(state, { reward_type: rewards.TYPE_REFERRAL }),
|
||||
};
|
||||
};
|
||||
const select = state => ({
|
||||
errorMessage: selectUserInviteNewErrorMessage(state),
|
||||
invitesRemaining: selectUserInvitesRemaining(state),
|
||||
isPending: selectUserInviteNewIsPending(state),
|
||||
});
|
||||
|
||||
const perform = dispatch => ({
|
||||
inviteNew: email => dispatch(doUserInviteNew(email)),
|
||||
|
|
|
@ -29,8 +29,7 @@ class FormInviteNew extends React.PureComponent {
|
|||
}
|
||||
|
||||
render() {
|
||||
const { errorMessage, isPending, rewardAmount } = this.props;
|
||||
const label = `${__('Get')} ${rewardAmount} LBC`;
|
||||
const { errorMessage, isPending } = this.props;
|
||||
|
||||
return (
|
||||
<Form onSubmit={this.handleSubmit}>
|
||||
|
@ -49,7 +48,7 @@ class FormInviteNew extends React.PureComponent {
|
|||
/>
|
||||
</FormRow>
|
||||
<div className="card__actions">
|
||||
<Submit label={label} disabled={isPending} />
|
||||
<Submit label="Invite" disabled={isPending} />
|
||||
</div>
|
||||
</Form>
|
||||
);
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import MarkdownPreview from './view';
|
||||
|
||||
const select = () => ({});
|
||||
const perform = () => ({});
|
||||
|
||||
export default connect(select, perform)(MarkdownPreview);
|
|
@ -1,32 +1,34 @@
|
|||
// @flow
|
||||
import * as React from 'react';
|
||||
import Button from 'component/button';
|
||||
import { buildURI } from 'lbry-redux';
|
||||
import type { Claim } from 'types/claim';
|
||||
|
||||
type Props = {
|
||||
uri: ?string,
|
||||
editingURI: ?string,
|
||||
isResolvingUri: boolean,
|
||||
winningBidForClaimUri: ?number,
|
||||
myClaimForUri: ?{},
|
||||
onEditMyClaim: any => void,
|
||||
myClaimForUri: ?Claim,
|
||||
isStillEditing: boolean,
|
||||
onEditMyClaim: (any, string) => void,
|
||||
};
|
||||
|
||||
class BidHelpText extends React.PureComponent<Props> {
|
||||
render() {
|
||||
const {
|
||||
uri,
|
||||
editingURI,
|
||||
isResolvingUri,
|
||||
winningBidForClaimUri,
|
||||
myClaimForUri,
|
||||
onEditMyClaim,
|
||||
isStillEditing,
|
||||
} = this.props;
|
||||
|
||||
if (!uri) {
|
||||
return __('Create a URL for this content');
|
||||
}
|
||||
|
||||
if (uri === editingURI) {
|
||||
if (isStillEditing) {
|
||||
return __('You are currently editing this claim');
|
||||
}
|
||||
|
||||
|
@ -35,11 +37,20 @@ class BidHelpText extends React.PureComponent<Props> {
|
|||
}
|
||||
|
||||
if (myClaimForUri) {
|
||||
const editUri = buildURI({
|
||||
contentName: myClaimForUri.name,
|
||||
claimId: myClaimForUri.claim_id,
|
||||
});
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
{__('You already have a claim at')}
|
||||
{` ${uri} `}
|
||||
<Button button="link" label="Edit it" onClick={() => onEditMyClaim(myClaimForUri, uri)} />
|
||||
<Button
|
||||
button="link"
|
||||
label="Edit it"
|
||||
onClick={() => onEditMyClaim(myClaimForUri, editUri)}
|
||||
/>
|
||||
<br />
|
||||
{__('Publishing will update your existing claim.')}
|
||||
</React.Fragment>
|
||||
|
|
|
@ -1,15 +1,17 @@
|
|||
// @flow
|
||||
import * as React from 'react';
|
||||
import { isNameValid, buildURI, regexInvalidURI } from 'lbry-redux';
|
||||
import { isNameValid, buildURI, regexInvalidURI, THUMBNAIL_STATUSES } from 'lbry-redux';
|
||||
import { Form, FormField, FormRow, FormFieldPrice, Submit } from 'component/common/form';
|
||||
import Button from 'component/button';
|
||||
import ChannelSection from 'component/selectChannel';
|
||||
import classnames from 'classnames';
|
||||
import type { PublishParams, UpdatePublishFormData } from 'redux/reducers/publish';
|
||||
import FileSelector from 'component/common/file-selector';
|
||||
import SelectThumbnail from 'component/selectThumbnail';
|
||||
import { COPYRIGHT, OTHER } from 'constants/licenses';
|
||||
import { CHANNEL_NEW, CHANNEL_ANONYMOUS, MINIMUM_PUBLISH_BID } from 'constants/claim';
|
||||
import * as icons from 'constants/icons';
|
||||
import type { Claim } from 'types/claim';
|
||||
import BidHelpText from './internal/bid-help-text';
|
||||
import LicenseType from './internal/license-type';
|
||||
|
||||
|
@ -20,6 +22,8 @@ type Props = {
|
|||
editingURI: ?string,
|
||||
title: ?string,
|
||||
thumbnail: ?string,
|
||||
uploadThumbnailStatus: ?string,
|
||||
thumbnailPath: ?string,
|
||||
description: ?string,
|
||||
language: string,
|
||||
nsfw: boolean,
|
||||
|
@ -36,14 +40,7 @@ type Props = {
|
|||
nameError: ?string,
|
||||
isResolvingUri: boolean,
|
||||
winningBidForClaimUri: number,
|
||||
myClaimForUri: ?{
|
||||
amount: number,
|
||||
value: {
|
||||
stream: {
|
||||
source: { source: string },
|
||||
},
|
||||
},
|
||||
},
|
||||
myClaimForUri: ?Claim,
|
||||
licenseType: string,
|
||||
otherLicenseDescription: ?string,
|
||||
licenseUrl: ?string,
|
||||
|
@ -52,10 +49,12 @@ type Props = {
|
|||
bidError: ?string,
|
||||
publishing: boolean,
|
||||
balance: number,
|
||||
isStillEditing: boolean,
|
||||
clearPublish: () => void,
|
||||
resolveUri: string => void,
|
||||
scrollToTop: () => void,
|
||||
prepareEdit: ({}, uri) => void,
|
||||
prepareEdit: ({}) => void,
|
||||
resetThumbnailStatus: () => void,
|
||||
};
|
||||
|
||||
class PublishForm extends React.PureComponent<Props> {
|
||||
|
@ -73,7 +72,13 @@ class PublishForm extends React.PureComponent<Props> {
|
|||
(this: any).getNewUri = this.getNewUri.bind(this);
|
||||
}
|
||||
|
||||
// Returns a new uri to be used in the form and begins to resolve that uri for bid help text
|
||||
componentWillMount() {
|
||||
const { isStillEditing, thumbnail } = this.props;
|
||||
if (!isStillEditing || !thumbnail) {
|
||||
this.props.resetThumbnailStatus();
|
||||
}
|
||||
}
|
||||
|
||||
getNewUri(name: string, channel: string) {
|
||||
const { resolveUri } = this.props;
|
||||
// If they are midway through a channel creation, treat it as anonymous until it completes
|
||||
|
@ -138,22 +143,26 @@ class PublishForm extends React.PureComponent<Props> {
|
|||
|
||||
handleChannelChange(channelName: string) {
|
||||
const { name, updatePublishForm } = this.props;
|
||||
const form = { channel: channelName };
|
||||
|
||||
if (name) {
|
||||
const uri = this.getNewUri(name, channelName);
|
||||
updatePublishForm({ channel: channelName, uri });
|
||||
} else {
|
||||
updatePublishForm({ channel: channelName });
|
||||
form.uri = this.getNewUri(name, channelName);
|
||||
}
|
||||
updatePublishForm(form);
|
||||
}
|
||||
|
||||
handleBidChange(bid: number) {
|
||||
const { balance, updatePublishForm } = this.props;
|
||||
|
||||
let bidError;
|
||||
if (balance <= bid) {
|
||||
bidError = __('Not enough credits');
|
||||
if (bid === 0) {
|
||||
bidError = __('Deposit cannot be 0');
|
||||
} else if (balance === bid) {
|
||||
bidError = __('Please decrease your deposit to account for transaction fees');
|
||||
} else if (balance < bid) {
|
||||
bidError = __('Deposit cannot be higher than your balance');
|
||||
} else if (bid <= MINIMUM_PUBLISH_BID) {
|
||||
bidError = __('Your bid must be higher');
|
||||
bidError = __('Your deposit must be higher');
|
||||
}
|
||||
|
||||
updatePublishForm({ bid, bidError });
|
||||
|
@ -175,24 +184,13 @@ class PublishForm extends React.PureComponent<Props> {
|
|||
|
||||
handlePublish() {
|
||||
const {
|
||||
publish,
|
||||
filePath,
|
||||
bid,
|
||||
title,
|
||||
thumbnail,
|
||||
description,
|
||||
language,
|
||||
nsfw,
|
||||
channel,
|
||||
copyrightNotice,
|
||||
licenseType,
|
||||
licenseUrl,
|
||||
otherLicenseDescription,
|
||||
copyrightNotice,
|
||||
name,
|
||||
contentIsFree,
|
||||
price,
|
||||
uri,
|
||||
myClaimForUri,
|
||||
publish,
|
||||
} = this.props;
|
||||
|
||||
let publishingLicense;
|
||||
|
@ -211,21 +209,22 @@ class PublishForm extends React.PureComponent<Props> {
|
|||
|
||||
const publishParams = {
|
||||
filePath,
|
||||
bid,
|
||||
title,
|
||||
thumbnail,
|
||||
description,
|
||||
language,
|
||||
nsfw,
|
||||
channel,
|
||||
bid: this.props.bid,
|
||||
title: this.props.title,
|
||||
thumbnail: this.props.thumbnail,
|
||||
description: this.props.description,
|
||||
language: this.props.language,
|
||||
nsfw: this.props.nsfw,
|
||||
license: publishingLicense,
|
||||
licenseUrl: publishingLicenseUrl,
|
||||
otherLicenseDescription,
|
||||
copyrightNotice,
|
||||
name,
|
||||
contentIsFree,
|
||||
price,
|
||||
uri,
|
||||
name: this.props.name,
|
||||
contentIsFree: this.props.contentIsFree,
|
||||
price: this.props.price,
|
||||
uri: this.props.uri,
|
||||
channel: this.props.channel,
|
||||
isStillEditing: this.props.isStillEditing,
|
||||
};
|
||||
|
||||
// Editing a claim
|
||||
|
@ -273,6 +272,7 @@ class PublishForm extends React.PureComponent<Props> {
|
|||
editingURI,
|
||||
title,
|
||||
thumbnail,
|
||||
uploadThumbnailStatus,
|
||||
description,
|
||||
language,
|
||||
nsfw,
|
||||
|
@ -295,13 +295,14 @@ class PublishForm extends React.PureComponent<Props> {
|
|||
bidError,
|
||||
publishing,
|
||||
clearPublish,
|
||||
thumbnailPath,
|
||||
resetThumbnailStatus,
|
||||
isStillEditing,
|
||||
} = this.props;
|
||||
|
||||
const formDisabled = (!filePath && !editingURI) || publishing;
|
||||
const formValid = this.checkIsFormValid();
|
||||
|
||||
const simpleUri = uri && uri.split('#')[0];
|
||||
const isStillEditing = editingURI === simpleUri;
|
||||
let submitLabel;
|
||||
if (isStillEditing) {
|
||||
submitLabel = !publishing ? __('Edit') : __('Editing...');
|
||||
|
@ -349,18 +350,6 @@ class PublishForm extends React.PureComponent<Props> {
|
|||
onChange={e => updatePublishForm({ title: e.target.value })}
|
||||
/>
|
||||
</FormRow>
|
||||
<FormRow padded>
|
||||
<FormField
|
||||
stretch
|
||||
type="text"
|
||||
name="content_thumbnail"
|
||||
label={__('Thumbnail')}
|
||||
placeholder="http://spee.ch/mylogo"
|
||||
value={thumbnail}
|
||||
disabled={formDisabled}
|
||||
onChange={e => updatePublishForm({ thumbnail: e.target.value })}
|
||||
/>
|
||||
</FormRow>
|
||||
<FormRow padded>
|
||||
<FormField
|
||||
stretch
|
||||
|
@ -375,6 +364,30 @@ class PublishForm extends React.PureComponent<Props> {
|
|||
</FormRow>
|
||||
</section>
|
||||
|
||||
<section className="card card--section">
|
||||
<div className="card__title">{__('Thumbnail')}</div>
|
||||
<div className="card__subtitle">
|
||||
{uploadThumbnailStatus === THUMBNAIL_STATUSES.API_DOWN ? (
|
||||
__('Enter a url for your thumbnail.')
|
||||
) : (
|
||||
<React.Fragment>
|
||||
{__(
|
||||
'Upload your thumbnail to spee.ch, or enter the url manually. Learn more about spee.ch '
|
||||
)}
|
||||
<Button button="link" label={__('here')} href="https://spee.ch/about" />.
|
||||
</React.Fragment>
|
||||
)}
|
||||
</div>
|
||||
<SelectThumbnail
|
||||
thumbnailPath={thumbnailPath}
|
||||
thumbnail={thumbnail}
|
||||
uploadThumbnailStatus={uploadThumbnailStatus}
|
||||
updatePublishForm={updatePublishForm}
|
||||
formDisabled={formDisabled}
|
||||
resetThumbnailStatus={resetThumbnailStatus}
|
||||
/>
|
||||
</section>
|
||||
|
||||
<section className="card card--section">
|
||||
<div className="card__title">{__('Price')}</div>
|
||||
<div className="card__subtitle">{__('How much will this content cost?')}</div>
|
||||
|
@ -447,7 +460,8 @@ class PublishForm extends React.PureComponent<Props> {
|
|||
error={nameError}
|
||||
helper={
|
||||
<BidHelpText
|
||||
uri={simpleUri}
|
||||
isStillEditing={isStillEditing}
|
||||
uri={uri}
|
||||
editingURI={editingURI}
|
||||
isResolvingUri={isResolvingUri}
|
||||
winningBidForClaimUri={winningBidForClaimUri}
|
||||
|
@ -554,7 +568,14 @@ class PublishForm extends React.PureComponent<Props> {
|
|||
</section>
|
||||
|
||||
<div className="card__actions">
|
||||
<Submit label={submitLabel} disabled={formDisabled || !formValid || publishing} />
|
||||
<Submit
|
||||
label={submitLabel}
|
||||
disabled={
|
||||
formDisabled ||
|
||||
!formValid ||
|
||||
uploadThumbnailStatus === THUMBNAIL_STATUSES.IN_PROGRESS
|
||||
}
|
||||
/>
|
||||
<Button button="alt" onClick={this.handleCancelPublish} label={__('Cancel')} />
|
||||
</div>
|
||||
{!formDisabled && !formValid && this.renderFormErrors()}
|
||||
|
|
|
@ -16,7 +16,7 @@ const makeSelect = () => {
|
|||
const select = (state, props) => ({
|
||||
errorMessage: selectError(state, props),
|
||||
isPending: selectIsPending(state, props),
|
||||
reward: selectReward(state, props),
|
||||
reward: selectReward(state, props.reward_type),
|
||||
});
|
||||
|
||||
return select;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { connect } from 'react-redux';
|
||||
import { selectCurrentPage, selectCurrentParams } from 'lbry-redux';
|
||||
import { selectCurrentPage, selectCurrentParams, doNotify } from 'lbry-redux';
|
||||
import Router from './view';
|
||||
|
||||
const select = state => ({
|
||||
|
@ -7,4 +7,4 @@ const select = state => ({
|
|||
currentPage: selectCurrentPage(state),
|
||||
});
|
||||
|
||||
export default connect(select, null)(Router);
|
||||
export default connect(select, { doNotify })(Router);
|
||||
|
|
|
@ -17,17 +17,23 @@ import AuthPage from 'page/auth';
|
|||
import InvitePage from 'page/invite';
|
||||
import BackupPage from 'page/backup';
|
||||
import SubscriptionsPage from 'page/subscriptions';
|
||||
import SearchPage from 'page/search';
|
||||
|
||||
const route = (page, routesMap) => {
|
||||
const route = (props, page, routesMap) => {
|
||||
const component = routesMap[page];
|
||||
|
||||
return component || DiscoverPage;
|
||||
if (!component) {
|
||||
props.doNotify({
|
||||
message: __('Invalid page requested'),
|
||||
displayType: ['snackbar'],
|
||||
});
|
||||
}
|
||||
return component || routesMap.discover;
|
||||
};
|
||||
|
||||
const Router = props => {
|
||||
const { currentPage, params } = props;
|
||||
|
||||
return route(currentPage, {
|
||||
return route(props, currentPage, {
|
||||
auth: <AuthPage params={params} />,
|
||||
backup: <BackupPage params={params} />,
|
||||
channel: <ChannelPage params={params} />,
|
||||
|
@ -46,6 +52,7 @@ const Router = props => {
|
|||
show: <ShowPage {...params} />,
|
||||
wallet: <WalletPage params={params} />,
|
||||
subscriptions: <SubscriptionsPage params={params} />,
|
||||
search: <SearchPage {...params} />,
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
@ -55,11 +55,13 @@ class ChannelSection extends React.PureComponent<Props, State> {
|
|||
|
||||
handleChannelChange(event: SyntheticInputEvent<*>) {
|
||||
const { onChannelChange } = this.props;
|
||||
const { newChannelBid } = this.state;
|
||||
const channel = event.target.value;
|
||||
|
||||
if (channel === CHANNEL_NEW) {
|
||||
this.setState({ addingChannel: true });
|
||||
onChannelChange(channel);
|
||||
this.handleNewChannelBidChange(newChannelBid);
|
||||
} else {
|
||||
this.setState({ addingChannel: false });
|
||||
onChannelChange(channel);
|
||||
|
@ -84,14 +86,15 @@ class ChannelSection extends React.PureComponent<Props, State> {
|
|||
});
|
||||
}
|
||||
|
||||
handleNewChannelBidChange(event: SyntheticInputEvent<*>) {
|
||||
handleNewChannelBidChange(newChannelBid: number) {
|
||||
const { balance } = this.props;
|
||||
const newChannelBid = parseFloat(event.target.value);
|
||||
let newChannelBidError;
|
||||
if (newChannelBid === balance) {
|
||||
newChannelBidError = __('Please decrease your bid to account for transaction fees');
|
||||
if (newChannelBid === 0) {
|
||||
newChannelBidError = __('Your deposit cannot be 0');
|
||||
} else if (newChannelBid === balance) {
|
||||
newChannelBidError = __('Please decrease your deposit to account for transaction fees');
|
||||
} else if (newChannelBid > balance) {
|
||||
newChannelBidError = __('Not enough credits');
|
||||
newChannelBidError = __('Deposit cannot be higher than your balance');
|
||||
}
|
||||
|
||||
this.setState({
|
||||
|
@ -176,6 +179,7 @@ class ChannelSection extends React.PureComponent<Props, State> {
|
|||
label={__('Name')}
|
||||
type="text"
|
||||
prefix="@"
|
||||
placeholder={__('myChannelName')}
|
||||
error={newChannelNameError}
|
||||
value={newChannelName}
|
||||
onChange={this.handleNewChannelNameChange}
|
||||
|
@ -183,6 +187,7 @@ class ChannelSection extends React.PureComponent<Props, State> {
|
|||
</FormRow>
|
||||
<FormRow padded>
|
||||
<FormField
|
||||
className="input--price-amount"
|
||||
label={__('Deposit')}
|
||||
postfix="LBC"
|
||||
step="any"
|
||||
|
@ -193,7 +198,7 @@ class ChannelSection extends React.PureComponent<Props, State> {
|
|||
)}
|
||||
error={newChannelBidError}
|
||||
value={newChannelBid}
|
||||
onChange={this.handleNewChannelBidChange}
|
||||
onChange={event => this.handleNewChannelBidChange(parseFloat(event.target.value))}
|
||||
/>
|
||||
</FormRow>
|
||||
<div className="card__actions">
|
||||
|
|
12
src/renderer/component/selectThumbnail/index.js
Normal file
12
src/renderer/component/selectThumbnail/index.js
Normal file
|
@ -0,0 +1,12 @@
|
|||
import { connect } from 'react-redux';
|
||||
import { doNotify } from 'lbry-redux';
|
||||
import SelectThumbnail from './view';
|
||||
|
||||
const perform = dispatch => ({
|
||||
openModal: (modal, props) => dispatch(doNotify(modal, props)),
|
||||
});
|
||||
|
||||
export default connect(
|
||||
null,
|
||||
perform
|
||||
)(SelectThumbnail);
|
90
src/renderer/component/selectThumbnail/view.jsx
Normal file
90
src/renderer/component/selectThumbnail/view.jsx
Normal file
|
@ -0,0 +1,90 @@
|
|||
// @flow
|
||||
import { THUMBNAIL_STATUSES, MODALS } from 'lbry-redux';
|
||||
import React from 'react';
|
||||
import { FormField, FormRow } from 'component/common/form';
|
||||
import FileSelector from 'component/common/file-selector';
|
||||
import Button from 'component/button';
|
||||
|
||||
type Props = {
|
||||
thumbnail: ?string,
|
||||
formDisabled: boolean,
|
||||
uploadThumbnailStatus: string,
|
||||
thumbnailPath: ?string,
|
||||
openModal: ({ id: string }, {}) => void,
|
||||
updatePublishForm: ({}) => void,
|
||||
resetThumbnailStatus: () => void,
|
||||
};
|
||||
|
||||
class SelectThumbnail extends React.PureComponent<Props> {
|
||||
render() {
|
||||
const {
|
||||
thumbnail,
|
||||
formDisabled,
|
||||
uploadThumbnailStatus: status,
|
||||
openModal,
|
||||
updatePublishForm,
|
||||
thumbnailPath,
|
||||
resetThumbnailStatus,
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<div>
|
||||
{status === THUMBNAIL_STATUSES.API_DOWN || status === THUMBNAIL_STATUSES.MANUAL ? (
|
||||
<FormRow padded>
|
||||
<FormField
|
||||
stretch
|
||||
type="text"
|
||||
name="content_thumbnail"
|
||||
label={__('Url')}
|
||||
placeholder="http://spee.ch/mylogo"
|
||||
value={thumbnail}
|
||||
disabled={formDisabled}
|
||||
onChange={e => updatePublishForm({ thumbnail: e.target.value })}
|
||||
/>
|
||||
</FormRow>
|
||||
) : (
|
||||
<div className="form-row--padded">
|
||||
{(status === THUMBNAIL_STATUSES.READY || status === THUMBNAIL_STATUSES.COMPLETE) && (
|
||||
<FileSelector
|
||||
currentPath={thumbnailPath}
|
||||
fileLabel={__('Choose Thumbnail')}
|
||||
onFileChosen={path => openModal({ id: MODALS.CONFIRM_THUMBNAIL_UPLOAD }, { path })}
|
||||
/>
|
||||
)}
|
||||
{status === THUMBNAIL_STATUSES.COMPLETE && (
|
||||
<div>
|
||||
<p>
|
||||
Upload complete. View it{' '}
|
||||
<Button button="link" href={thumbnail} label={__('here')} />.
|
||||
</p>
|
||||
<Button button="link" label={__('New thumbnail')} onClick={resetThumbnailStatus} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<div className="card__actions">
|
||||
{status === THUMBNAIL_STATUSES.READY && (
|
||||
<Button
|
||||
button="link"
|
||||
label={__('Or enter a URL manually')}
|
||||
onClick={() =>
|
||||
updatePublishForm({ uploadThumbnailStatus: THUMBNAIL_STATUSES.MANUAL })
|
||||
}
|
||||
/>
|
||||
)}
|
||||
{status === THUMBNAIL_STATUSES.MANUAL && (
|
||||
<Button
|
||||
button="link"
|
||||
label={__('Use thumbnail upload tool')}
|
||||
onClick={() => updatePublishForm({ uploadThumbnailStatus: THUMBNAIL_STATUSES.READY })}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{status === THUMBNAIL_STATUSES.IN_PROGRESS && <p>{__('Uploading thumbnail')}...</p>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default SelectThumbnail;
|
|
@ -19,7 +19,10 @@ class LoadScreen extends React.PureComponent<Props> {
|
|||
|
||||
return (
|
||||
<div className="load-screen">
|
||||
<h1 className="load-screen__title">{__('LBRY')}</h1>
|
||||
<div className="load-screen__header">
|
||||
<h1 className="load-screen__title">{__('LBRY')}</h1>
|
||||
<sup className="load-screen__beta">beta</sup>
|
||||
</div>
|
||||
{isWarning ? (
|
||||
<span className="load-screen__message">
|
||||
<Icon size={20} icon={icons.ALERT} />
|
||||
|
|
|
@ -37,8 +37,9 @@ export default (props: Props) => {
|
|||
|
||||
return channelName && uri ? (
|
||||
<Button
|
||||
iconColor="red"
|
||||
icon={isSubscribed ? undefined : icons.HEART}
|
||||
button={isSubscribed ? 'danger' : 'alt'}
|
||||
button="alt"
|
||||
label={subscriptionLabel}
|
||||
onClick={() => {
|
||||
if (!subscriptions.length) {
|
||||
|
|
|
@ -96,6 +96,7 @@ class TransactionList extends React.PureComponent<Props, State> {
|
|||
type="select"
|
||||
value={filter}
|
||||
onChange={this.handleFilterChanged}
|
||||
affixClass="form-field--align-center"
|
||||
prefix={__('Show')}
|
||||
postfix={
|
||||
<Button
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { doUserEmailVerify, doUserEmailVerifyFailure } from 'redux/actions/user';
|
||||
import {
|
||||
doUserEmailVerify,
|
||||
doUserEmailVerifyFailure,
|
||||
doUserResendVerificationEmail,
|
||||
} from 'redux/actions/user';
|
||||
import {
|
||||
selectEmailVerifyIsPending,
|
||||
selectEmailToVerify,
|
||||
|
@ -17,6 +20,7 @@ const select = state => ({
|
|||
const perform = dispatch => ({
|
||||
verifyUserEmail: (code, recaptcha) => dispatch(doUserEmailVerify(code, recaptcha)),
|
||||
verifyUserEmailFailure: error => dispatch(doUserEmailVerifyFailure(error)),
|
||||
resendVerificationEmail: email => dispatch(doUserResendVerificationEmail(email)),
|
||||
});
|
||||
|
||||
export default connect(select, perform)(UserEmailVerify);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// @flow
|
||||
import React from 'react';
|
||||
import * as React from 'react';
|
||||
import Button from 'component/button';
|
||||
import { Form, FormField, FormRow, Submit } from 'component/common/form';
|
||||
|
||||
|
@ -10,6 +10,7 @@ type Props = {
|
|||
isPending: boolean,
|
||||
verifyUserEmail: (string, string) => void,
|
||||
verifyUserEmailFailure: string => void,
|
||||
resendVerificationEmail: string => void,
|
||||
};
|
||||
|
||||
type State = {
|
||||
|
@ -25,6 +26,7 @@ class UserEmailVerify extends React.PureComponent<Props, State> {
|
|||
};
|
||||
|
||||
(this: any).handleSubmit = this.handleSubmit.bind(this);
|
||||
(this: any).handleResendVerificationEmail = this.handleResendVerificationEmail.bind(this);
|
||||
}
|
||||
|
||||
handleCodeChanged(event: SyntheticInputEvent<*>) {
|
||||
|
@ -43,6 +45,10 @@ class UserEmailVerify extends React.PureComponent<Props, State> {
|
|||
}
|
||||
}
|
||||
|
||||
handleResendVerificationEmail() {
|
||||
this.props.resendVerificationEmail(this.props.email);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { cancelButton, errorMessage, email, isPending } = this.props;
|
||||
|
||||
|
@ -71,6 +77,11 @@ class UserEmailVerify extends React.PureComponent<Props, State> {
|
|||
<div className="card__actions">
|
||||
<Submit label={__('Verify')} disabled={isPending} />
|
||||
{cancelButton}
|
||||
<Button
|
||||
button="link"
|
||||
label={__('Resend verification email')}
|
||||
onClick={this.handleResendVerificationEmail}
|
||||
/>
|
||||
</div>
|
||||
</Form>
|
||||
);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { connect } from 'react-redux';
|
||||
import { doNotify, MODALS } from 'lbry-redux';
|
||||
import { doNavigate } from 'redux/actions/navigation';
|
||||
import { doUserIdentityVerify } from 'redux/actions/user';
|
||||
import rewards from 'rewards';
|
||||
|
@ -8,15 +9,14 @@ import {
|
|||
selectIdentityVerifyErrorMessage,
|
||||
} from 'redux/selectors/user';
|
||||
import UserVerify from './view';
|
||||
import { doNotify, MODALS } from 'lbry-redux';
|
||||
|
||||
const select = (state, props) => {
|
||||
const select = state => {
|
||||
const selectReward = makeSelectRewardByType();
|
||||
|
||||
return {
|
||||
isPending: selectIdentityVerifyIsPending(state),
|
||||
errorMessage: selectIdentityVerifyErrorMessage(state),
|
||||
reward: selectReward(state, { reward_type: rewards.TYPE_NEW_USER }),
|
||||
reward: selectReward(state, rewards.TYPE_NEW_USER),
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -46,6 +46,7 @@ const select = (state, props) => ({
|
|||
const perform = dispatch => ({
|
||||
play: uri => dispatch(doPlayUri(uri)),
|
||||
load: uri => dispatch(doLoadVideo(uri)),
|
||||
cancelPlay: () => dispatch(doSetPlayingUri(null)),
|
||||
changeVolume: volume => dispatch(doChangeVolume(volume)),
|
||||
doPlay: () => dispatch(doPlay()),
|
||||
doPause: () => dispatch(doPause()),
|
||||
|
|
|
@ -17,9 +17,7 @@ class VideoPlayButton extends React.PureComponent<Props> {
|
|||
const icon = doesPlayback ? 'Play' : 'Folder';
|
||||
const label = doesPlayback ? 'Play' : 'View';
|
||||
|
||||
return (
|
||||
<Button button="secondary" disabled={disabled} label={label} icon={icon} onClick={play} />
|
||||
);
|
||||
return <Button button="primary" disabled={disabled} label={label} icon={icon} onClick={play} />;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -132,22 +132,11 @@ class Video extends React.PureComponent<Props> {
|
|||
}
|
||||
|
||||
handleAutoplay = (props: Props) => {
|
||||
const {
|
||||
autoplay,
|
||||
playingUri,
|
||||
fileInfo,
|
||||
costInfo,
|
||||
isDownloading,
|
||||
uri,
|
||||
load,
|
||||
play,
|
||||
metadata,
|
||||
} = props;
|
||||
const { autoplay, playingUri, fileInfo, costInfo, isDownloading, uri, play, metadata } = props;
|
||||
|
||||
const playable = autoplay && playingUri !== uri && metadata && !metadata.nsfw;
|
||||
|
||||
if (playable && costInfo && costInfo.cost === 0 && !fileInfo && !isDownloading) {
|
||||
load(uri);
|
||||
play(uri);
|
||||
} else if (playable && fileInfo && fileInfo.blobs_completed > 0) {
|
||||
play(uri);
|
||||
|
@ -263,7 +252,10 @@ class Video extends React.PureComponent<Props> {
|
|||
style={layoverStyle}
|
||||
>
|
||||
<VideoPlayButton
|
||||
play={this.playContent}
|
||||
play={e => {
|
||||
e.stopPropagation();
|
||||
this.playContent();
|
||||
}}
|
||||
fileInfo={fileInfo}
|
||||
uri={uri}
|
||||
isLoading={isLoading}
|
||||
|
|
3
src/renderer/component/viewOnWebButton/index.js
Normal file
3
src/renderer/component/viewOnWebButton/index.js
Normal file
|
@ -0,0 +1,3 @@
|
|||
import ViewOnWebButton from './view';
|
||||
|
||||
export default ViewOnWebButton;
|
25
src/renderer/component/viewOnWebButton/view.jsx
Normal file
25
src/renderer/component/viewOnWebButton/view.jsx
Normal file
|
@ -0,0 +1,25 @@
|
|||
// @flow
|
||||
import React from 'react';
|
||||
import * as icons from 'constants/icons';
|
||||
import Button from 'component/button';
|
||||
|
||||
type Props = {
|
||||
claimId: ?string,
|
||||
claimName: ?string,
|
||||
};
|
||||
|
||||
export default (props: Props) => {
|
||||
const { claimId, claimName } = props;
|
||||
const speechURL = claimName.startsWith('@')
|
||||
? `${claimName}:${claimId}`
|
||||
: `${claimId}/${claimName}`;
|
||||
|
||||
return claimId && claimName ? (
|
||||
<Button
|
||||
icon={icons.GLOBE}
|
||||
button="alt"
|
||||
label={__('View on Web')}
|
||||
href={`http://spee.ch/${speechURL}`}
|
||||
/>
|
||||
) : null;
|
||||
};
|
|
@ -2,6 +2,7 @@
|
|||
import React from 'react';
|
||||
import Button from 'component/button';
|
||||
import Address from 'component/address';
|
||||
import QRCode from 'component/common/qr-code';
|
||||
import * as icons from 'constants/icons';
|
||||
|
||||
type Props = {
|
||||
|
@ -12,6 +13,20 @@ type Props = {
|
|||
};
|
||||
|
||||
class WalletAddress extends React.PureComponent<Props> {
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
showQR: false,
|
||||
};
|
||||
}
|
||||
|
||||
toggleQR() {
|
||||
this.setState({
|
||||
showQR: !this.state.showQR,
|
||||
});
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
const { checkAddressIsMine, receiveAddress, getNewAddress } = this.props;
|
||||
if (!receiveAddress) {
|
||||
|
@ -23,6 +38,7 @@ class WalletAddress extends React.PureComponent<Props> {
|
|||
|
||||
render() {
|
||||
const { receiveAddress, getNewAddress, gettingNewAddress } = this.props;
|
||||
const { showQR } = this.state;
|
||||
|
||||
return (
|
||||
<section className="card card--section">
|
||||
|
@ -43,7 +59,17 @@ class WalletAddress extends React.PureComponent<Props> {
|
|||
onClick={getNewAddress}
|
||||
disabled={gettingNewAddress}
|
||||
/>
|
||||
<Button
|
||||
button="link"
|
||||
label={showQR ? __('Hide QR code') : __('Show QR code')}
|
||||
onClick={this.toggleQR.bind(this)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="card__content">
|
||||
{showQR && <QRCode value={receiveAddress} paddingTop />}
|
||||
</div>
|
||||
|
||||
<div className="card__content">
|
||||
<div className="help">
|
||||
<p>
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import { connect } from 'react-redux';
|
||||
import { doSendDraftTransaction, selectBalance } from 'lbry-redux';
|
||||
import { selectBalance, doNotify } from 'lbry-redux';
|
||||
import WalletSend from './view';
|
||||
|
||||
const perform = dispatch => ({
|
||||
sendToAddress: (address, amount) => dispatch(doSendDraftTransaction(address, amount)),
|
||||
openModal: (modal, props) => dispatch(doNotify(modal, props)),
|
||||
});
|
||||
|
||||
const select = state => ({
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// @flow
|
||||
import React from 'react';
|
||||
import { MODALS } from 'lbry-redux';
|
||||
import Button from 'component/button';
|
||||
import { Form, FormRow, FormField } from 'component/common/form';
|
||||
import { Formik } from 'formik';
|
||||
|
@ -11,7 +12,7 @@ type DraftTransaction = {
|
|||
};
|
||||
|
||||
type Props = {
|
||||
sendToAddress: (string, number) => void,
|
||||
openModal: ({ id: string }, { address: string, amount: number }) => void,
|
||||
balance: number,
|
||||
};
|
||||
|
||||
|
@ -23,10 +24,12 @@ class WalletSend extends React.PureComponent<Props> {
|
|||
}
|
||||
|
||||
handleSubmit(values: DraftTransaction) {
|
||||
const { sendToAddress } = this.props;
|
||||
const { openModal } = this.props;
|
||||
const { address, amount } = values;
|
||||
if (amount && address) {
|
||||
sendToAddress(address, amount);
|
||||
const notificationId = { id: MODALS.CONFIRM_TRANSACTION };
|
||||
const modalProps = { address, amount };
|
||||
openModal(notificationId, modalProps);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -53,17 +56,22 @@ class WalletSend extends React.PureComponent<Props> {
|
|||
label={__('Amount')}
|
||||
postfix={__('LBC')}
|
||||
className="input--price-amount"
|
||||
affixClass="form-field--fix-no-height"
|
||||
min="0"
|
||||
step="any"
|
||||
placeholder="12.34"
|
||||
onChange={handleChange}
|
||||
onBlur={handleBlur}
|
||||
value={values.amount}
|
||||
error={
|
||||
(!!values.amount && touched.amount && errors.amount) ||
|
||||
(values.amount > balance && __('Not enough'))
|
||||
(values.amount === balance &&
|
||||
__('Decrease amount to account for transaction fee')) ||
|
||||
(values.amount > balance && __('Not enough credits'))
|
||||
}
|
||||
/>
|
||||
|
||||
</FormRow>
|
||||
<FormRow padded>
|
||||
<FormField
|
||||
type="text"
|
||||
name="address"
|
||||
|
@ -84,7 +92,8 @@ class WalletSend extends React.PureComponent<Props> {
|
|||
disabled={
|
||||
!values.address ||
|
||||
!!Object.keys(errors).length ||
|
||||
!(parseFloat(values.amount) > 0.0)
|
||||
!(parseFloat(values.amount) > 0.0) ||
|
||||
parseFloat(values.amount) === balance
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
@ -9,7 +9,6 @@ type Props = {
|
|||
uri: string,
|
||||
title: string,
|
||||
claim: Claim,
|
||||
errorMessage: string,
|
||||
isPending: boolean,
|
||||
sendSupport: (number, string, string) => void,
|
||||
onCancel: () => void,
|
||||
|
@ -18,7 +17,8 @@ type Props = {
|
|||
};
|
||||
|
||||
type State = {
|
||||
amount: number,
|
||||
tipAmount: number,
|
||||
newTipError: string,
|
||||
};
|
||||
|
||||
class WalletSendTip extends React.PureComponent<Props, State> {
|
||||
|
@ -26,7 +26,8 @@ class WalletSendTip extends React.PureComponent<Props, State> {
|
|||
super(props);
|
||||
|
||||
this.state = {
|
||||
amount: 0,
|
||||
tipAmount: 0,
|
||||
newTipError: '',
|
||||
};
|
||||
|
||||
(this: any).handleSendButtonClicked = this.handleSendButtonClicked.bind(this);
|
||||
|
@ -35,9 +36,9 @@ class WalletSendTip extends React.PureComponent<Props, State> {
|
|||
handleSendButtonClicked() {
|
||||
const { claim, uri, sendSupport, sendTipCallback } = this.props;
|
||||
const { claim_id: claimId } = claim;
|
||||
const { amount } = this.state;
|
||||
const { tipAmount } = this.state;
|
||||
|
||||
sendSupport(amount, claimId, uri);
|
||||
sendSupport(tipAmount, claimId, uri);
|
||||
|
||||
// ex: close modal
|
||||
if (sendTipCallback) {
|
||||
|
@ -46,14 +47,24 @@ class WalletSendTip extends React.PureComponent<Props, State> {
|
|||
}
|
||||
|
||||
handleSupportPriceChange(event: SyntheticInputEvent<*>) {
|
||||
const { balance } = this.props;
|
||||
const tipAmount = parseFloat(event.target.value);
|
||||
let newTipError;
|
||||
if (tipAmount === balance) {
|
||||
newTipError = __('Please decrease your tip to account for transaction fees');
|
||||
} else if (tipAmount > balance) {
|
||||
newTipError = __('Not enough credits');
|
||||
}
|
||||
|
||||
this.setState({
|
||||
amount: Number(event.target.value),
|
||||
tipAmount,
|
||||
newTipError,
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const { title, errorMessage, isPending, uri, onCancel, balance } = this.props;
|
||||
const { amount } = this.state;
|
||||
const { title, isPending, uri, onCancel, balance } = this.props;
|
||||
const { tipAmount, newTipError } = this.state;
|
||||
|
||||
return (
|
||||
<div>
|
||||
|
@ -67,7 +78,8 @@ class WalletSendTip extends React.PureComponent<Props, State> {
|
|||
label={__('Amount')}
|
||||
postfix={__('LBC')}
|
||||
className="input--price-amount"
|
||||
error={errorMessage}
|
||||
error={newTipError}
|
||||
value={tipAmount}
|
||||
min="0"
|
||||
step="any"
|
||||
type="number"
|
||||
|
@ -84,10 +96,15 @@ class WalletSendTip extends React.PureComponent<Props, State> {
|
|||
<Button
|
||||
button="primary"
|
||||
label={__('Send')}
|
||||
disabled={isPending || amount <= 0 || amount > balance}
|
||||
disabled={isPending || tipAmount <= 0 || tipAmount > balance || tipAmount === balance}
|
||||
onClick={this.handleSendButtonClicked}
|
||||
/>
|
||||
<Button button="alt" label={__('Cancel')} onClick={onCancel} navigateParams={{ uri }} />
|
||||
<Button
|
||||
button="link"
|
||||
label={__('Cancel')}
|
||||
onClick={onCancel}
|
||||
navigateParams={{ uri }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -7,6 +7,7 @@ import {
|
|||
MODALS,
|
||||
doFocusSearchInput,
|
||||
doBlurSearchInput,
|
||||
doSearch,
|
||||
} from 'lbry-redux';
|
||||
import { doNavigate } from 'redux/actions/navigation';
|
||||
import Wunderbar from './view';
|
||||
|
@ -27,8 +28,8 @@ const select = state => {
|
|||
|
||||
const perform = dispatch => ({
|
||||
onSearch: query => {
|
||||
dispatch(doUpdateSearchQuery(query));
|
||||
dispatch(doNotify({ id: MODALS.SEARCH }));
|
||||
dispatch(doSearch(query));
|
||||
dispatch(doNavigate(`/search`, { query }));
|
||||
},
|
||||
onSubmit: (uri, extraParams) => dispatch(doNavigate('/show', { uri, ...extraParams })),
|
||||
updateSearchQuery: query => dispatch(doUpdateSearchQuery(query)),
|
||||
|
|
|
@ -106,7 +106,7 @@ class WunderBar extends React.PureComponent<Props> {
|
|||
<input
|
||||
{...props}
|
||||
className="wunderbar__input"
|
||||
placeholder="Search for videos, music, games and more"
|
||||
placeholder="Enter LBRY URL here or search for videos, music, games and more"
|
||||
/>
|
||||
)}
|
||||
renderItem={({ value, type, shorthand }, isHighlighted) => (
|
||||
|
|
|
@ -117,6 +117,7 @@ export const USER_EMAIL_NEW_FAILURE = 'USER_EMAIL_NEW_FAILURE';
|
|||
export const USER_EMAIL_VERIFY_STARTED = 'USER_EMAIL_VERIFY_STARTED';
|
||||
export const USER_EMAIL_VERIFY_SUCCESS = 'USER_EMAIL_VERIFY_SUCCESS';
|
||||
export const USER_EMAIL_VERIFY_FAILURE = 'USER_EMAIL_VERIFY_FAILURE';
|
||||
export const USER_EMAIL_VERIFY_RETRY = 'USER_EMAIL_VERIFY_RETRY';
|
||||
export const USER_PHONE_RESET = 'USER_PHONE_RESET';
|
||||
export const USER_PHONE_NEW_STARTED = 'USER_PHONE_NEW_STARTED';
|
||||
export const USER_PHONE_NEW_SUCCESS = 'USER_PHONE_NEW_SUCCESS';
|
||||
|
|
|
@ -28,3 +28,4 @@ export const CHECK_SIMPLE = 'Check';
|
|||
export const PLAY = 'Play';
|
||||
export const MAXIMIZE = 'Maximize2';
|
||||
export const PAUSE = 'Pause';
|
||||
export const GLOBE = 'Globe';
|
||||
|
|
5
src/renderer/constants/thumbnail_upload_statuses.js
Normal file
5
src/renderer/constants/thumbnail_upload_statuses.js
Normal file
|
@ -0,0 +1,5 @@
|
|||
export const API_DOWN = 'apiDown';
|
||||
export const READY = 'ready';
|
||||
export const IN_PROGRESS = 'inProgress';
|
||||
export const COMPLETE = 'complete';
|
||||
export const MANUAL = 'manual';
|
|
@ -8,7 +8,7 @@ import React from 'react';
|
|||
import ReactDOM from 'react-dom';
|
||||
import { Provider } from 'react-redux';
|
||||
import { doConditionalAuthNavigate, doDaemonReady, doAutoUpdate } from 'redux/actions/app';
|
||||
import { doNotify, doBlackListedOutpointsSubscribe } from 'lbry-redux';
|
||||
import { doNotify, doBlackListedOutpointsSubscribe, isURIValid } from 'lbry-redux';
|
||||
import { doNavigate } from 'redux/actions/navigation';
|
||||
import { doDownloadLanguages, doUpdateIsNightAsync } from 'redux/actions/settings';
|
||||
import { doUserEmailVerify } from 'redux/actions/user';
|
||||
|
@ -17,8 +17,10 @@ import store from 'store';
|
|||
import app from './app';
|
||||
import analytics from './analytics';
|
||||
import VideoOverlay from './component/videoOverlay/';
|
||||
import doLogWarningConsoleMessage from './logWarningConsoleMessage';
|
||||
|
||||
const { autoUpdater } = remote.require('electron-updater');
|
||||
const APPPAGEURL = 'lbry://?';
|
||||
|
||||
autoUpdater.logger = remote.require('electron-log');
|
||||
|
||||
|
@ -42,8 +44,18 @@ ipcRenderer.on('open-uri-requested', (event, uri, newSession) => {
|
|||
})
|
||||
);
|
||||
}
|
||||
} else {
|
||||
} else if (uri.startsWith(APPPAGEURL)) {
|
||||
const navpage = uri.replace(APPPAGEURL, '').toLowerCase();
|
||||
app.store.dispatch(doNavigate(`/${navpage}`));
|
||||
} else if (isURIValid(uri)) {
|
||||
app.store.dispatch(doNavigate('/show', { uri }));
|
||||
} else {
|
||||
app.store.dispatch(
|
||||
doNotify({
|
||||
message: __('Invalid LBRY URL requested'),
|
||||
displayType: ['snackbar'],
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -62,6 +74,11 @@ ipcRenderer.on('window-is-focused', () => {
|
|||
dock.setBadge('');
|
||||
});
|
||||
|
||||
ipcRenderer.on('devtools-is-opened', () => {
|
||||
const logOnDevelopment = false;
|
||||
doLogWarningConsoleMessage(logOnDevelopment);
|
||||
});
|
||||
|
||||
document.addEventListener('dragover', event => {
|
||||
event.preventDefault();
|
||||
});
|
||||
|
|
34
src/renderer/logWarningConsoleMessage.js
Normal file
34
src/renderer/logWarningConsoleMessage.js
Normal file
|
@ -0,0 +1,34 @@
|
|||
import isDev from 'electron-is-dev';
|
||||
|
||||
export default function doLogWarningConsoleMessage(activeOnDev = false) {
|
||||
if (isDev && !activeOnDev) return;
|
||||
const style = {
|
||||
redTitle:
|
||||
'color: red; font-size: 50px; text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black;, font-weight: bold;',
|
||||
normalText: 'font-size: 24px;',
|
||||
redText:
|
||||
'color: red; text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black; font-size: 24px;',
|
||||
};
|
||||
console.clear();
|
||||
console.log('%cScam alert!', style.redTitle);
|
||||
|
||||
console.log(
|
||||
'%cIf someone told you to copy / paste something here you have a chance of being scammed.',
|
||||
style.normalText
|
||||
);
|
||||
|
||||
console.log(
|
||||
'%cPasting anything in here could give attackers access to your LBC credits or wallet.',
|
||||
style.normalText
|
||||
);
|
||||
|
||||
console.log(
|
||||
"%cIf you don't understand what you are doing here, please close this window and keep your LBC credits/wallet safe.",
|
||||
style.redText
|
||||
);
|
||||
|
||||
console.log(
|
||||
'%cIf you do understand exactly what you are doing, you should come work with us https://lbry.io/join-us',
|
||||
style.normalText
|
||||
);
|
||||
}
|
|
@ -56,7 +56,7 @@ export class Modal extends React.PureComponent<ModalProps> {
|
|||
return (
|
||||
<ReactModal
|
||||
{...modalProps}
|
||||
onCloseRequested={onAborted || onConfirmed}
|
||||
onRequestClose={onAborted || onConfirmed}
|
||||
className={classnames(className, {
|
||||
modal: !fullScreen,
|
||||
'modal--fullscreen': fullScreen,
|
||||
|
|
|
@ -3,6 +3,12 @@ import FilePrice from 'component/filePrice';
|
|||
import { Modal } from 'modal/modal';
|
||||
|
||||
class ModalAffirmPurchase extends React.PureComponent {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.onAffirmPurchase = this.onAffirmPurchase.bind(this);
|
||||
}
|
||||
|
||||
onAffirmPurchase() {
|
||||
this.props.closeModal();
|
||||
this.props.loadVideo(this.props.uri);
|
||||
|
@ -20,7 +26,7 @@ class ModalAffirmPurchase extends React.PureComponent {
|
|||
type="confirm"
|
||||
isOpen
|
||||
contentLabel={__('Confirm Purchase')}
|
||||
onConfirmed={this.onAffirmPurchase.bind(this)}
|
||||
onConfirmed={this.onAffirmPurchase}
|
||||
onAborted={cancelPurchase}
|
||||
>
|
||||
{__('This will purchase')} <strong>{title}</strong> {__('for')}{' '}
|
||||
|
|
21
src/renderer/modal/modalConfirmThumbnailUpload/index.js
Normal file
21
src/renderer/modal/modalConfirmThumbnailUpload/index.js
Normal file
|
@ -0,0 +1,21 @@
|
|||
import { connect } from 'react-redux';
|
||||
import { doHideNotification } from 'lbry-redux';
|
||||
import { doUploadThumbnail, doUpdatePublishForm } from 'redux/actions/publish';
|
||||
import { selectPublishFormValues } from 'redux/selectors/publish';
|
||||
import ModalConfirmThumbnailUpload from './view';
|
||||
|
||||
const select = state => {
|
||||
const publishState = selectPublishFormValues(state);
|
||||
return { nsfw: publishState.nsfw };
|
||||
};
|
||||
|
||||
const perform = dispatch => ({
|
||||
closeModal: () => dispatch(doHideNotification()),
|
||||
upload: (path, nsfw = false) => dispatch(doUploadThumbnail(path, nsfw)),
|
||||
updatePublishForm: value => dispatch(doUpdatePublishForm(value)),
|
||||
});
|
||||
|
||||
export default connect(
|
||||
select,
|
||||
perform
|
||||
)(ModalConfirmThumbnailUpload);
|
48
src/renderer/modal/modalConfirmThumbnailUpload/view.jsx
Normal file
48
src/renderer/modal/modalConfirmThumbnailUpload/view.jsx
Normal file
|
@ -0,0 +1,48 @@
|
|||
// @flow
|
||||
import React from 'react';
|
||||
import { Modal } from 'modal/modal';
|
||||
import { FormField } from 'component/common/form';
|
||||
|
||||
type Props = {
|
||||
upload: (string, boolean) => void,
|
||||
path: string,
|
||||
nsfw: boolean,
|
||||
closeModal: () => void,
|
||||
updatePublishForm: ({}) => void,
|
||||
};
|
||||
|
||||
class ModalConfirmThumbnailUpload extends React.PureComponent<Props> {
|
||||
upload() {
|
||||
const { upload, updatePublishForm, closeModal, path, nsfw } = this.props;
|
||||
upload(path, nsfw);
|
||||
updatePublishForm({ thumbnailPath: path });
|
||||
closeModal();
|
||||
}
|
||||
|
||||
render() {
|
||||
const { closeModal, path, updatePublishForm, nsfw } = this.props;
|
||||
|
||||
return (
|
||||
<Modal
|
||||
isOpen
|
||||
contentLabel={__('Confirm Thumbnail Upload')}
|
||||
type="confirm"
|
||||
confirmButtonLabel={__('Upload')}
|
||||
onConfirmed={() => this.upload()}
|
||||
onAborted={closeModal}
|
||||
>
|
||||
<p>{__('Are you sure you want to upload this thumbnail to spee.ch')}?</p>
|
||||
<blockquote>{path}</blockquote>
|
||||
<FormField
|
||||
type="checkbox"
|
||||
name="content_is_mature"
|
||||
postfix={__('Mature audiences only')}
|
||||
checked={nsfw}
|
||||
onChange={event => updatePublishForm({ nsfw: event.target.checked })}
|
||||
/>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default ModalConfirmThumbnailUpload;
|
10
src/renderer/modal/modalConfirmTransaction/index.js
Normal file
10
src/renderer/modal/modalConfirmTransaction/index.js
Normal file
|
@ -0,0 +1,10 @@
|
|||
import { connect } from 'react-redux';
|
||||
import { doHideNotification, doSendDraftTransaction } from 'lbry-redux';
|
||||
import ModalConfirmTransaction from './view';
|
||||
|
||||
const perform = dispatch => ({
|
||||
closeModal: () => dispatch(doHideNotification()),
|
||||
sendToAddress: (address, amount) => dispatch(doSendDraftTransaction(address, amount)),
|
||||
});
|
||||
|
||||
export default connect(null, perform)(ModalConfirmTransaction);
|
44
src/renderer/modal/modalConfirmTransaction/view.jsx
Normal file
44
src/renderer/modal/modalConfirmTransaction/view.jsx
Normal file
|
@ -0,0 +1,44 @@
|
|||
// @flow
|
||||
import React from 'react';
|
||||
import { Modal } from 'modal/modal';
|
||||
|
||||
type Props = {
|
||||
address: string,
|
||||
amount: number,
|
||||
closeModal: () => void,
|
||||
sendToAddress: (string, number) => void,
|
||||
};
|
||||
|
||||
class ModalConfirmTransaction extends React.PureComponent<Props> {
|
||||
onConfirmed() {
|
||||
const { closeModal, sendToAddress, amount, address } = this.props;
|
||||
sendToAddress(address, amount);
|
||||
closeModal();
|
||||
}
|
||||
|
||||
render() {
|
||||
const { amount, address, closeModal } = this.props;
|
||||
return (
|
||||
<Modal
|
||||
isOpen
|
||||
contentLabel={__('Confirm Transaction')}
|
||||
type="confirm"
|
||||
confirmButtonLabel={__('Continue')}
|
||||
onConfirmed={() => this.onConfirmed()}
|
||||
onAborted={closeModal}
|
||||
>
|
||||
<p>{__('Are you sure you want to ')}</p>
|
||||
<h1>
|
||||
{__('send ')} {amount} LBC
|
||||
</h1>
|
||||
<p>{__('Sending: ')}</p>
|
||||
<blockquote>{amount} LBC</blockquote>
|
||||
<p>{__('To address: ')}</p>
|
||||
<blockquote>{address}</blockquote>
|
||||
<p>{__('Once the transaction is sent, it cannot be reversed.')}</p>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default ModalConfirmTransaction;
|
|
@ -1,14 +1,20 @@
|
|||
// I'll come back to this
|
||||
/* esline-disable */
|
||||
// @flow
|
||||
import React from 'react';
|
||||
import { Modal } from 'modal/modal';
|
||||
import CurrencySymbol from 'component/common/lbc-symbol';
|
||||
import CreditAmount from 'component/common/credit-amount';
|
||||
import Button from 'component/button';
|
||||
|
||||
const ModalCreditIntro = props => {
|
||||
type Props = {
|
||||
totalRewardValue: number,
|
||||
currentBalance: number,
|
||||
closeModal: () => void,
|
||||
addBalance: () => void,
|
||||
};
|
||||
|
||||
const ModalCreditIntro = (props: Props) => {
|
||||
const { closeModal, totalRewardValue, currentBalance, addBalance } = props;
|
||||
const totalRewardRounded = Math.round(totalRewardValue / 10) * 10;
|
||||
const totalRewardRounded = Math.floor(totalRewardValue / 10) * 10;
|
||||
|
||||
return (
|
||||
<Modal type="custom" isOpen contentLabel="Welcome to LBRY">
|
||||
|
@ -25,16 +31,13 @@ const ModalCreditIntro = props => {
|
|||
can take are limited.
|
||||
</p>
|
||||
)}
|
||||
<p>
|
||||
There are a variety of ways to get credits, including more than{' '}
|
||||
{totalRewardValue ? (
|
||||
<CreditAmount noStyle amount={totalRewardRounded} />
|
||||
) : (
|
||||
<span className="credit-amount">{__('?? credits')}</span>
|
||||
)}{' '}
|
||||
{__(' in free rewards for participating in the LBRY beta.')}
|
||||
</p>
|
||||
|
||||
{Boolean(totalRewardValue) && (
|
||||
<p>
|
||||
There are a variety of ways to get credits, including more than{' '}
|
||||
<CreditAmount noStyle amount={totalRewardRounded} />{' '}
|
||||
{__('in free rewards for participating in the LBRY beta.')}
|
||||
</p>
|
||||
)}
|
||||
<div className="card__actions card__actions--center">
|
||||
<Button button="primary" onClick={addBalance} label={__('Get Credits')} />
|
||||
<Button
|
||||
|
@ -49,4 +52,3 @@ const ModalCreditIntro = props => {
|
|||
};
|
||||
|
||||
export default ModalCreditIntro;
|
||||
/* esline-enable */
|
||||
|
|
|
@ -34,7 +34,7 @@ class ModalDownloading extends React.PureComponent {
|
|||
/>
|
||||
) : null}
|
||||
<Button
|
||||
button="alt"
|
||||
button="link"
|
||||
label={__('Cancel')}
|
||||
className="modal__button"
|
||||
onClick={cancelUpgrade}
|
||||
|
|
|
@ -8,7 +8,7 @@ const select = state => {
|
|||
const selectReward = makeSelectRewardByType();
|
||||
|
||||
return {
|
||||
reward: selectReward(state, { reward_type: rewards.TYPE_NEW_USER }),
|
||||
reward: selectReward(state, rewards.TYPE_NEW_USER),
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ import CreditAmount from 'component/common/credit-amount';
|
|||
|
||||
class ModalFirstReward extends React.PureComponent {
|
||||
render() {
|
||||
const { closeModal, reward } = this.props;
|
||||
const { closeModal } = this.props;
|
||||
|
||||
return (
|
||||
<Modal
|
||||
|
@ -18,10 +18,7 @@ class ModalFirstReward extends React.PureComponent {
|
|||
>
|
||||
<section>
|
||||
<h3 className="modal__header">{__('Your First Reward')}</h3>
|
||||
<p>
|
||||
{__('You just earned your first reward of')}{' '}
|
||||
<CreditAmount amount={reward.reward_amount} />.
|
||||
</p>
|
||||
<p>{__('You just earned your first reward!')}</p>
|
||||
<p>
|
||||
{__(
|
||||
"This reward will show in your Wallet in the top right momentarily (if it hasn't already)."
|
||||
|
|
|
@ -18,12 +18,17 @@ import ModalRevokeClaim from 'modal/modalRevokeClaim';
|
|||
import ModalEmailCollection from 'modal/modalEmailCollection';
|
||||
import ModalPhoneCollection from 'modal/modalPhoneCollection';
|
||||
import ModalFirstSubscription from 'modal/modalFirstSubscription';
|
||||
import ModalConfirmTransaction from 'modal/modalConfirmTransaction';
|
||||
import ModalSendTip from '../modalSendTip';
|
||||
import ModalPublish from '../modalPublish';
|
||||
import ModalSearch from '../modalSearch';
|
||||
import ModalOpenExternalLink from '../modalOpenExternalLink';
|
||||
import ModalConfirmThumbnailUpload from 'modal/modalConfirmThumbnailUpload';
|
||||
|
||||
class ModalRouter extends React.PureComponent {
|
||||
type Props = {
|
||||
modal: string,
|
||||
};
|
||||
|
||||
class ModalRouter extends React.PureComponent<Props> {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
|
@ -56,7 +61,7 @@ class ModalRouter extends React.PureComponent {
|
|||
|
||||
if (
|
||||
transitionModal &&
|
||||
(transitionModal != this.state.lastTransitionModal || page != this.state.lastTransitionPage)
|
||||
(transitionModal !== this.state.lastTransitionModal || page !== this.state.lastTransitionPage)
|
||||
) {
|
||||
openModal({ id: transitionModal });
|
||||
this.setState({
|
||||
|
@ -89,7 +94,7 @@ class ModalRouter extends React.PureComponent {
|
|||
const { balance, page, isCreditIntroAcknowledged } = props;
|
||||
|
||||
if (
|
||||
balance <= 0 &&
|
||||
balance === 0 &&
|
||||
!isCreditIntroAcknowledged &&
|
||||
(['send', 'publish'].includes(page) || this.isPaidShowPage(props))
|
||||
) {
|
||||
|
@ -154,10 +159,12 @@ class ModalRouter extends React.PureComponent {
|
|||
return <ModalSendTip {...notificationProps} />;
|
||||
case MODALS.PUBLISH:
|
||||
return <ModalPublish {...notificationProps} />;
|
||||
case MODALS.SEARCH:
|
||||
return <ModalSearch {...notificationProps} />;
|
||||
case MODALS.CONFIRM_EXTERNAL_LINK:
|
||||
return <ModalOpenExternalLink {...notificationProps} />;
|
||||
case MODALS.CONFIRM_TRANSACTION:
|
||||
return <ModalConfirmTransaction {...notificationProps} />;
|
||||
case MODALS.CONFIRM_THUMBNAIL_UPLOAD:
|
||||
return <ModalConfirmThumbnailUpload {...notificationProps} />;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
import { connect } from 'react-redux';
|
||||
import { doHideNotification } from 'lbry-redux';
|
||||
import ModalSearch from './view';
|
||||
import { doClearPublish } from 'redux/actions/publish';
|
||||
import { doNavigate } from 'redux/actions/navigation';
|
||||
|
||||
const perform = dispatch => ({
|
||||
closeModal: () => dispatch(doHideNotification()),
|
||||
clearPublish: () => dispatch(doClearPublish()),
|
||||
navigate: (path, params) => dispatch(doNavigate(path, params)),
|
||||
});
|
||||
|
||||
export default connect(null, perform)(ModalSearch);
|
|
@ -1,25 +0,0 @@
|
|||
// @flow
|
||||
import React from 'react';
|
||||
import { Modal } from 'modal/modal';
|
||||
import SearchPage from 'page/search';
|
||||
import Button from 'component/button';
|
||||
import * as icons from 'constants/icons';
|
||||
|
||||
type Props = {
|
||||
closeModal: () => void,
|
||||
query: string,
|
||||
};
|
||||
|
||||
class ModalSearch extends React.PureComponent<Props> {
|
||||
render() {
|
||||
const { closeModal, query } = this.props;
|
||||
return (
|
||||
<Modal isOpen type="custom" fullScreen>
|
||||
<Button noPadding button="alt" icon={icons.CLOSE} onClick={closeModal} />
|
||||
<SearchPage />
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default ModalSearch;
|
|
@ -1,13 +1,19 @@
|
|||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { doHideNotification } from 'lbry-redux';
|
||||
import { doDownloadUpgrade, doSkipUpgrade } from 'redux/actions/app';
|
||||
import ModalUpgrade from './view';
|
||||
|
||||
const select = state => ({});
|
||||
const select = () => ({});
|
||||
|
||||
const perform = dispatch => ({
|
||||
downloadUpgrade: () => dispatch(doDownloadUpgrade()),
|
||||
skipUpgrade: () => dispatch(doSkipUpgrade()),
|
||||
skipUpgrade: () => {
|
||||
dispatch(doHideNotification());
|
||||
dispatch(doSkipUpgrade());
|
||||
},
|
||||
});
|
||||
|
||||
export default connect(select, perform)(ModalUpgrade);
|
||||
export default connect(
|
||||
select,
|
||||
perform
|
||||
)(ModalUpgrade);
|
||||
|
|
|
@ -24,7 +24,11 @@ class ModalUpgrade extends React.PureComponent {
|
|||
</p>
|
||||
<p className="meta text-center">
|
||||
{__('Want to know what has changed?')} See the{' '}
|
||||
<Button label={__('release notes')} href="https://github.com/lbryio/lbry-app/releases" />.
|
||||
<Button
|
||||
button="link"
|
||||
label={__('release notes')}
|
||||
href="https://github.com/lbryio/lbry-app/releases"
|
||||
/>.
|
||||
</p>
|
||||
</Modal>
|
||||
);
|
||||
|
|
|
@ -6,7 +6,6 @@ import {
|
|||
makeSelectFetchingChannelClaims,
|
||||
makeSelectCurrentParam,
|
||||
selectCurrentParams,
|
||||
doNotify,
|
||||
} from 'lbry-redux';
|
||||
import { doNavigate } from 'redux/actions/navigation';
|
||||
import { makeSelectTotalPagesForChannel } from 'redux/selectors/content';
|
||||
|
@ -25,7 +24,6 @@ const perform = dispatch => ({
|
|||
fetchClaims: (uri, page) => dispatch(doFetchClaimsByChannel(uri, page)),
|
||||
fetchClaimCount: uri => dispatch(doFetchClaimCountByChannel(uri)),
|
||||
navigate: (path, params) => dispatch(doNavigate(path, params)),
|
||||
openModal: (modal, props) => dispatch(doNotify(modal, props)),
|
||||
});
|
||||
|
||||
export default connect(select, perform)(ChannelPage);
|
||||
|
|
|
@ -4,6 +4,7 @@ import BusyIndicator from 'component/common/busy-indicator';
|
|||
import { FormField, FormRow } from 'component/common/form';
|
||||
import ReactPaginate from 'react-paginate';
|
||||
import SubscribeButton from 'component/subscribeButton';
|
||||
import ViewOnWebButton from 'component/viewOnWebButton';
|
||||
import Page from 'component/page';
|
||||
import FileList from 'component/fileList';
|
||||
import type { Claim } from 'types/claim';
|
||||
|
@ -47,17 +48,24 @@ class ChannelPage extends React.PureComponent<Props> {
|
|||
this.props.navigate('/show', newParams);
|
||||
}
|
||||
|
||||
paginate(e, totalPages) {
|
||||
paginate(e, totalPages: number) {
|
||||
// Change page if enter was pressed, and the given page is between
|
||||
// the first and the last.
|
||||
if (e.keyCode === 13 && e.target.value > 0 && e.target.value <= totalPages) {
|
||||
this.changePage(e.target.value);
|
||||
const pageFromInput = Number(e.target.value);
|
||||
|
||||
if (
|
||||
e.keyCode === 13 &&
|
||||
!Number.isNaN(pageFromInput) &&
|
||||
pageFromInput > 0 &&
|
||||
pageFromInput <= totalPages
|
||||
) {
|
||||
this.changePage(pageFromInput);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { fetching, claimsInChannel, claim, page, totalPages } = this.props;
|
||||
const { name, permanent_url: permanentUrl } = claim;
|
||||
const { name, permanent_url: permanentUrl, claim_id: claimId } = claim;
|
||||
|
||||
let contentList;
|
||||
if (fetching) {
|
||||
|
@ -77,6 +85,7 @@ class ChannelPage extends React.PureComponent<Props> {
|
|||
<h1>{name}</h1>
|
||||
<div className="card__actions card__actions--no-margin">
|
||||
<SubscribeButton uri={permanentUrl} channelName={name} />
|
||||
<ViewOnWebButton claimId={claimId} claimName={name} />
|
||||
</div>
|
||||
</section>
|
||||
<section>{contentList}</section>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// @flow
|
||||
import React from 'react';
|
||||
import Page from 'component/page';
|
||||
import CategoryList from 'component/common/category-list';
|
||||
import CategoryList from 'component/categoryList';
|
||||
|
||||
type Props = {
|
||||
fetchFeaturedUris: () => void,
|
||||
|
@ -27,7 +27,11 @@ class DiscoverPage extends React.PureComponent<Props> {
|
|||
featuredUris[category].length ? (
|
||||
<CategoryList key={category} category={category} names={featuredUris[category]} />
|
||||
) : (
|
||||
''
|
||||
<CategoryList
|
||||
key={category}
|
||||
category={category.split('#')[0]}
|
||||
categoryLink={category}
|
||||
/>
|
||||
)
|
||||
)}
|
||||
{failedToLoad && <div className="empty">{__('Failed to load landing content.')}</div>}
|
||||
|
|
|
@ -7,16 +7,21 @@ import FilePrice from 'component/filePrice';
|
|||
import FileDetails from 'component/fileDetails';
|
||||
import FileActions from 'component/fileActions';
|
||||
import UriIndicator from 'component/uriIndicator';
|
||||
import { FormField, FormRow } from 'component/common/form';
|
||||
import Icon from 'component/common/icon';
|
||||
import DateTime from 'component/dateTime';
|
||||
import * as icons from 'constants/icons';
|
||||
import Button from 'component/button';
|
||||
import SubscribeButton from 'component/subscribeButton';
|
||||
import ViewOnWebButton from 'component/viewOnWebButton';
|
||||
import Page from 'component/page';
|
||||
import player from 'render-media';
|
||||
import * as settings from 'constants/settings';
|
||||
import type { Claim } from 'types/claim';
|
||||
import type { Subscription } from 'types/subscription';
|
||||
import FileDownloadLink from 'component/fileDownloadLink';
|
||||
import classnames from 'classnames';
|
||||
import { FormField, FormRow } from 'component/common/form';
|
||||
import ToolTip from 'component/common/tooltip';
|
||||
|
||||
type Props = {
|
||||
claim: Claim,
|
||||
|
@ -30,8 +35,6 @@ type Props = {
|
|||
uri: string,
|
||||
rewardedContentClaimIds: Array<string>,
|
||||
obscureNsfw: boolean,
|
||||
playingUri: ?string,
|
||||
isPaused: boolean,
|
||||
claimIsMine: boolean,
|
||||
autoplay: boolean,
|
||||
costInfo: ?{},
|
||||
|
@ -39,11 +42,11 @@ type Props = {
|
|||
openModal: ({ id: string }, { uri: string }) => void,
|
||||
fetchFileInfo: string => void,
|
||||
fetchCostInfo: string => void,
|
||||
prepareEdit: ({}) => void,
|
||||
prepareEdit: ({}, string) => void,
|
||||
setClientSetting: (string, boolean | string) => void,
|
||||
checkSubscription: ({ channelName: string, uri: string }) => void,
|
||||
subscriptions: Array<{}>,
|
||||
fromOverlay: boolean,
|
||||
subscriptions: Array<Subscription>,
|
||||
};
|
||||
|
||||
class FilePage extends React.Component<Props> {
|
||||
|
@ -54,15 +57,14 @@ class FilePage extends React.Component<Props> {
|
|||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { uri, fileInfo, fetchFileInfo, costInfo, fetchCostInfo } = this.props;
|
||||
const { uri, fileInfo, fetchFileInfo, fetchCostInfo } = this.props;
|
||||
|
||||
if (fileInfo === undefined) {
|
||||
fetchFileInfo(uri);
|
||||
}
|
||||
|
||||
if (costInfo === undefined) {
|
||||
fetchCostInfo(uri);
|
||||
}
|
||||
// See https://github.com/lbryio/lbry-app/pull/1563 for discussion
|
||||
fetchCostInfo(uri);
|
||||
|
||||
this.checkSubscription(this.props);
|
||||
}
|
||||
|
@ -79,12 +81,7 @@ class FilePage extends React.Component<Props> {
|
|||
}
|
||||
|
||||
checkSubscription = (props: Props) => {
|
||||
if (
|
||||
props.claim.value.publisherSignature &&
|
||||
props.subscriptions
|
||||
.map(subscription => subscription.channelName)
|
||||
.indexOf(props.claim.channel_name) !== -1
|
||||
) {
|
||||
if (props.subscriptions.find(sub => sub.channelName === props.claim.channel_name)) {
|
||||
props.checkSubscription({
|
||||
channelName: props.claim.channel_name,
|
||||
uri: buildURI(
|
||||
|
@ -106,14 +103,13 @@ class FilePage extends React.Component<Props> {
|
|||
uri,
|
||||
rewardedContentClaimIds,
|
||||
obscureNsfw,
|
||||
playingUri,
|
||||
isPaused,
|
||||
openModal,
|
||||
claimIsMine,
|
||||
prepareEdit,
|
||||
navigate,
|
||||
autoplay,
|
||||
fromOverlay,
|
||||
costInfo,
|
||||
} = this.props;
|
||||
|
||||
// File info
|
||||
|
@ -122,16 +118,32 @@ class FilePage extends React.Component<Props> {
|
|||
const shouldObscureThumbnail = obscureNsfw && metadata.nsfw;
|
||||
const { height, channel_name: channelName, value } = claim;
|
||||
const mediaType = Lbry.getMediaType(contentType);
|
||||
const isPlayable =
|
||||
Object.values(player.mime).indexOf(contentType) !== -1 || mediaType === 'audio';
|
||||
const isPlayable = Object.values(player.mime).includes(contentType) || mediaType === 'audio';
|
||||
const channelClaimId =
|
||||
value && value.publisherSignature && value.publisherSignature.certificateId;
|
||||
let subscriptionUri;
|
||||
if (channelName && channelClaimId) {
|
||||
subscriptionUri = buildURI({ channelName, claimId: channelClaimId }, false);
|
||||
}
|
||||
const speechSharable =
|
||||
costInfo &&
|
||||
costInfo.cost === 0 &&
|
||||
contentType &&
|
||||
['video', 'image'].includes(contentType.split('/')[0]);
|
||||
|
||||
// We want to use the short form uri for editing
|
||||
// This is what the user is used to seeing, they don't care about the claim id
|
||||
// We will select the claim id before they publish
|
||||
let editUri;
|
||||
if (claimIsMine) {
|
||||
const uriObject = { contentName: claim.name, claimId: claim.claim_id };
|
||||
if (channelName) {
|
||||
uriObject.channelName = channelName;
|
||||
}
|
||||
|
||||
editUri = buildURI(uriObject);
|
||||
}
|
||||
|
||||
const isPlaying = playingUri === uri && !isPaused;
|
||||
return (
|
||||
<Page extraPadding>
|
||||
{!claim || !metadata ? (
|
||||
|
@ -140,22 +152,27 @@ class FilePage extends React.Component<Props> {
|
|||
</section>
|
||||
) : (
|
||||
<section className="card">
|
||||
{isPlayable ? (
|
||||
<Video className="content__embedded" uri={uri} fromOverlay={fromOverlay} />
|
||||
) : (
|
||||
<Thumbnail shouldObscure={shouldObscureThumbnail} src={thumbnail} />
|
||||
)}
|
||||
{!isPlaying && (
|
||||
<div className="card-media__internal-links">
|
||||
<FileActions uri={uri} vertical />
|
||||
</div>
|
||||
)}
|
||||
{isPlayable && <Video className="content__embedded" uri={uri} fromOverlay={fromOverlay} />}
|
||||
{!isPlayable &&
|
||||
(thumbnail ? (
|
||||
<Thumbnail shouldObscure={shouldObscureThumbnail} src={thumbnail} />
|
||||
) : (
|
||||
<div
|
||||
className={classnames('content__empty', {
|
||||
'content__empty--nsfw': shouldObscureThumbnail,
|
||||
})}
|
||||
>
|
||||
<div className="card__media-text">{__('This content is not playable.')}</div>
|
||||
</div>
|
||||
))}
|
||||
<div className="card__content">
|
||||
<div className="card__title-identity--file">
|
||||
<h1 className="card__title card__title--file">{title}</h1>
|
||||
<div className="card__title-identity-icons">
|
||||
<FilePrice uri={normalizeURI(uri)} />
|
||||
{isRewardContent && <Icon icon={icons.FEATURED} />}
|
||||
{isRewardContent && (
|
||||
<Icon iconColor="red" tooltip="bottom" icon={icons.FEATURED} />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<span className="card__subtitle card__subtitle--file">
|
||||
|
@ -172,35 +189,54 @@ class FilePage extends React.Component<Props> {
|
|||
icon={icons.EDIT}
|
||||
label={__('Edit')}
|
||||
onClick={() => {
|
||||
prepareEdit(claim, uri);
|
||||
prepareEdit(claim, editUri);
|
||||
navigate('/publish');
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<React.Fragment>
|
||||
<Button
|
||||
button="alt"
|
||||
iconRight="Send"
|
||||
label={__('Enjoy this? Send a tip')}
|
||||
onClick={() => openModal({ id: MODALS.SEND_TIP }, { uri })}
|
||||
/>
|
||||
<SubscribeButton uri={subscriptionUri} channelName={channelName} />
|
||||
</React.Fragment>
|
||||
<SubscribeButton uri={subscriptionUri} channelName={channelName} />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<FormRow alignRight>
|
||||
{(!claimIsMine || speechSharable) && (
|
||||
<div className="card__actions card__actions--end">
|
||||
{!claimIsMine && (
|
||||
<Button
|
||||
button="alt"
|
||||
icon="Send"
|
||||
label={__('Enjoy this? Send a tip')}
|
||||
onClick={() => openModal({ id: MODALS.SEND_TIP }, { uri })}
|
||||
/>
|
||||
)}
|
||||
{speechSharable && (
|
||||
<ViewOnWebButton claimId={claim.claim_id} claimName={claim.name} />
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<FormRow alignRight padded>
|
||||
<FormField
|
||||
type="checkbox"
|
||||
useToggle
|
||||
name="autoplay"
|
||||
onChange={this.onAutoplayChange}
|
||||
type="checkbox"
|
||||
checked={autoplay}
|
||||
postfix={__('Autoplay')}
|
||||
onChange={this.onAutoplayChange}
|
||||
postfix={
|
||||
<ToolTip
|
||||
onFormField
|
||||
label={__('Autoplay')}
|
||||
body={__('Automatically download and play free content.')}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</FormRow>
|
||||
</div>
|
||||
|
||||
<div className="card__content">
|
||||
<FileDownloadLink uri={uri} />
|
||||
<FileActions uri={uri} claimId={claim.claim_id} />
|
||||
</div>
|
||||
|
||||
<div className="card__content--extra-padding">
|
||||
<FileDetails uri={uri} />
|
||||
</div>
|
||||
</section>
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
import { connect } from 'react-redux';
|
||||
import { selectMyClaimsWithoutChannels } from 'lbry-redux';
|
||||
import { selectPendingPublishes } from 'redux/selectors/publish';
|
||||
import { selectPendingPublishes, selectClaimsWithPendingPublishes } from 'redux/selectors/publish';
|
||||
import { doNavigate } from 'redux/actions/navigation';
|
||||
import { doCheckPendingPublishes } from 'redux/actions/publish';
|
||||
import FileListPublished from './view';
|
||||
|
||||
const select = state => ({
|
||||
claims: selectMyClaimsWithoutChannels(state),
|
||||
claims: selectClaimsWithPendingPublishes(state),
|
||||
pendingPublishes: selectPendingPublishes(state),
|
||||
});
|
||||
|
||||
|
@ -15,4 +14,7 @@ const perform = dispatch => ({
|
|||
checkIfPublishesConfirmed: publishes => dispatch(doCheckPendingPublishes(publishes)),
|
||||
});
|
||||
|
||||
export default connect(select, perform)(FileListPublished);
|
||||
export default connect(
|
||||
select,
|
||||
perform
|
||||
)(FileListPublished);
|
||||
|
|
|
@ -20,13 +20,12 @@ class FileListPublished extends React.PureComponent<Props> {
|
|||
}
|
||||
|
||||
render() {
|
||||
const { claims, pendingPublishes, navigate } = this.props;
|
||||
const fileInfos = [...pendingPublishes, ...claims];
|
||||
const { claims, navigate } = this.props;
|
||||
|
||||
return (
|
||||
<Page notContained>
|
||||
{fileInfos.length ? (
|
||||
<FileList checkPending fileInfos={fileInfos} sortByHeight />
|
||||
{claims.length ? (
|
||||
<FileList checkPending fileInfos={claims} sortByHeight />
|
||||
) : (
|
||||
<div className="page__empty">
|
||||
{__("It looks like you haven't published anything to LBRY yet.")}
|
||||
|
|
|
@ -3,18 +3,11 @@ import Button from 'component/button';
|
|||
import RewardSummary from 'component/rewardSummary';
|
||||
import ShapeShift from 'component/shapeShift';
|
||||
import Page from 'component/page';
|
||||
import * as icons from 'constants/icons';
|
||||
|
||||
const GetCreditsPage = props => (
|
||||
const GetCreditsPage = () => (
|
||||
<Page>
|
||||
<RewardSummary />
|
||||
<ShapeShift />
|
||||
<section className="card card--section">
|
||||
<div className="card__title">{__('From External Wallet')}</div>
|
||||
<div className="card__actions">
|
||||
<Button button="primary" icon={icons.SEND} navigate="/send" label={__('Send / Receive')} />
|
||||
</div>
|
||||
</section>
|
||||
<section className="card card--section">
|
||||
<div className="card__title">{__('More ways to get LBRY Credits')}</div>
|
||||
<div className="card__content">
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
import { connect } from 'react-redux';
|
||||
import { doAuthNavigate } from 'redux/actions/navigation';
|
||||
import { doFetchAccessToken } from 'redux/actions/user';
|
||||
import { selectDaemonSettings } from 'redux/selectors/settings';
|
||||
import { selectAccessToken, selectUser } from 'redux/selectors/user';
|
||||
import HelpPage from './view';
|
||||
|
||||
const select = state => ({
|
||||
user: selectUser(state),
|
||||
accessToken: selectAccessToken(state),
|
||||
deamonSettings: selectDaemonSettings(state),
|
||||
});
|
||||
|
||||
const perform = dispatch => ({
|
||||
|
@ -14,4 +16,7 @@ const perform = dispatch => ({
|
|||
fetchAccessToken: () => dispatch(doFetchAccessToken()),
|
||||
});
|
||||
|
||||
export default connect(select, perform)(HelpPage);
|
||||
export default connect(
|
||||
select,
|
||||
perform
|
||||
)(HelpPage);
|
||||
|
|
|
@ -1,15 +1,44 @@
|
|||
// @TODO: Customize advice based on OS
|
||||
import React from 'react';
|
||||
// @flow
|
||||
import * as React from 'react';
|
||||
import { shell } from 'electron';
|
||||
import { Lbry } from 'lbry-redux';
|
||||
import Native from 'native';
|
||||
import Button from 'component/button';
|
||||
import BusyIndicator from 'component/common/busy-indicator';
|
||||
import Icon from 'component/common/icon';
|
||||
import Page from 'component/page';
|
||||
import * as icons from 'constants/icons';
|
||||
|
||||
class HelpPage extends React.PureComponent {
|
||||
constructor(props) {
|
||||
type DeamonSettings = {
|
||||
data_dir: string | any,
|
||||
};
|
||||
|
||||
type Props = {
|
||||
deamonSettings: DeamonSettings,
|
||||
accessToken: string,
|
||||
fetchAccessToken: () => void,
|
||||
doAuth: () => void,
|
||||
user: any,
|
||||
};
|
||||
|
||||
type VersionInfo = {
|
||||
os_system: string,
|
||||
os_release: string,
|
||||
platform: string,
|
||||
lbrynet_version: string,
|
||||
lbryum_version: string,
|
||||
};
|
||||
|
||||
type State = {
|
||||
versionInfo: VersionInfo | any,
|
||||
lbryId: String | any,
|
||||
uiVersion: ?string,
|
||||
upgradeAvailable: ?boolean,
|
||||
accessTokenHidden: ?boolean,
|
||||
};
|
||||
|
||||
class HelpPage extends React.PureComponent<Props, State> {
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
|
@ -20,11 +49,12 @@ class HelpPage extends React.PureComponent {
|
|||
accessTokenHidden: true,
|
||||
};
|
||||
|
||||
this.showAccessToken = this.showAccessToken.bind(this);
|
||||
(this: any).showAccessToken = this.showAccessToken.bind(this);
|
||||
(this: any).openLogFile = this.openLogFile.bind(this);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
Native.getAppVersionInfo().then(({ remoteVersion, localVersion, upgradeAvailable }) => {
|
||||
Native.getAppVersionInfo().then(({ localVersion, upgradeAvailable }) => {
|
||||
this.setState({
|
||||
uiVersion: localVersion,
|
||||
upgradeAvailable,
|
||||
|
@ -50,13 +80,24 @@ class HelpPage extends React.PureComponent {
|
|||
});
|
||||
}
|
||||
|
||||
openLogFile(userHomeDirectory: string) {
|
||||
const logFileName = 'lbrynet.log';
|
||||
const os = this.state.versionInfo.os_system;
|
||||
if (os === 'Darwin' || os === 'Linux') {
|
||||
shell.openItem(`${userHomeDirectory}/${logFileName}`);
|
||||
} else {
|
||||
shell.openItem(`${userHomeDirectory}\\${logFileName}`);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
let ver;
|
||||
let osName;
|
||||
let platform;
|
||||
let newVerLink;
|
||||
|
||||
const { accessToken, doAuth, user } = this.props;
|
||||
const { accessToken, doAuth, user, deamonSettings } = this.props;
|
||||
const { data_dir: dataDirectory } = deamonSettings;
|
||||
|
||||
if (this.state.versionInfo) {
|
||||
ver = this.state.versionInfo;
|
||||
|
@ -109,13 +150,36 @@ class HelpPage extends React.PureComponent {
|
|||
</section>
|
||||
|
||||
<section className="card card--section">
|
||||
<div className="card__title">{__('Report a Bug')}</div>
|
||||
<p className="card__subtitle">{__('Did you find something wrong?')}</p>
|
||||
<div className="card__title">{__('View your Log')}</div>
|
||||
<p className="card__subtitle">
|
||||
{__('Did something go wrong? Have a look in your log file, or send it to')}{' '}
|
||||
<Button button="link" label={__('support')} href="https://lbry.io/faq/support" />.
|
||||
</p>
|
||||
<div className="card__actions">
|
||||
<Button
|
||||
button="primary"
|
||||
label={__('Open Log')}
|
||||
icon={icons.REPORT}
|
||||
onClick={() => this.openLogFile(dataDirectory)}
|
||||
/>
|
||||
<Button
|
||||
button="primary"
|
||||
label={__('Open Log Folder')}
|
||||
icon={icons.REPORT}
|
||||
onClick={() => shell.showItemInFolder(dataDirectory)}
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="card card--section">
|
||||
<div className="card__title">{__('Report a Bug or Suggest a New Feature')}</div>
|
||||
<p className="card__subtitle">
|
||||
{__('Did you find something wrong? Think LBRY could add something useful and cool?')}
|
||||
</p>
|
||||
<div className="card__actions">
|
||||
<Button
|
||||
navigate="/report"
|
||||
label={__('Submit a Bug Report')}
|
||||
label={__('Submit a Bug Report/Feature Request')}
|
||||
icon={icons.REPORT}
|
||||
button="primary"
|
||||
/>
|
||||
|
|
|
@ -1,31 +1,25 @@
|
|||
import { connect } from 'react-redux';
|
||||
import { doClaimRewardType } from 'redux/actions/rewards';
|
||||
import {
|
||||
doHistoryBack,
|
||||
doResolveUri,
|
||||
makeSelectCostInfoForUri,
|
||||
selectMyClaims,
|
||||
selectFetchingMyChannels,
|
||||
selectMyChannelClaims,
|
||||
selectClaimsByUri,
|
||||
selectResolvingUris,
|
||||
selectBalance,
|
||||
} from 'lbry-redux';
|
||||
import {
|
||||
doFetchClaimListMine,
|
||||
doFetchChannelListMine,
|
||||
doCreateChannel,
|
||||
} from 'redux/actions/content';
|
||||
import { doResolveUri, selectClaimsByUri, selectResolvingUris, selectBalance } from 'lbry-redux';
|
||||
import { doNavigate } from 'redux/actions/navigation';
|
||||
import rewards from 'rewards';
|
||||
import { selectPublishFormValues } from 'redux/selectors/publish';
|
||||
import { doClearPublish, doUpdatePublishForm, doPublish } from 'redux/actions/publish';
|
||||
import { doPrepareEdit } from 'redux/actions/publish';
|
||||
import {
|
||||
selectPublishFormValues,
|
||||
selectIsStillEditing,
|
||||
selectMyClaimForUri,
|
||||
} from 'redux/selectors/publish';
|
||||
import {
|
||||
doResetThumbnailStatus,
|
||||
doClearPublish,
|
||||
doUpdatePublishForm,
|
||||
doPublish,
|
||||
doPrepareEdit,
|
||||
} from 'redux/actions/publish';
|
||||
import PublishPage from './view';
|
||||
|
||||
const select = (state, props) => {
|
||||
const select = state => {
|
||||
const isStillEditing = selectIsStillEditing(state);
|
||||
const myClaimForUri = selectMyClaimForUri(state);
|
||||
const publishState = selectPublishFormValues(state);
|
||||
const { uri, name } = publishState;
|
||||
const { uri } = publishState;
|
||||
|
||||
const resolvingUris = selectResolvingUris(state);
|
||||
let isResolvingUri = false;
|
||||
|
@ -33,24 +27,28 @@ const select = (state, props) => {
|
|||
isResolvingUri = resolvingUris.includes(uri);
|
||||
}
|
||||
|
||||
const claimsByUri = selectClaimsByUri(state);
|
||||
const myClaims = selectMyClaims(state);
|
||||
|
||||
const claimForUri = claimsByUri[uri];
|
||||
let claimForUri;
|
||||
let winningBidForClaimUri;
|
||||
let myClaimForUri;
|
||||
if (claimForUri) {
|
||||
winningBidForClaimUri = claimForUri.effective_amount;
|
||||
myClaimForUri = myClaims.find(claim => claim.name === name);
|
||||
if (!myClaimForUri) {
|
||||
// if the uri isn't from a users claim, find the winning bid needed for the vanity url
|
||||
// in the future we may want to display this on users claims
|
||||
// ex: "you own this, for 5 more lbc you will win this claim"
|
||||
const claimsByUri = selectClaimsByUri(state);
|
||||
claimForUri = claimsByUri[uri];
|
||||
winningBidForClaimUri = claimForUri ? claimForUri.effective_amount : null;
|
||||
}
|
||||
|
||||
return {
|
||||
...publishState,
|
||||
isResolvingUri,
|
||||
// The winning claim for a short lbry uri
|
||||
claimForUri,
|
||||
winningBidForClaimUri,
|
||||
// My previously published claims under this short lbry uri
|
||||
myClaimForUri,
|
||||
costInfo: makeSelectCostInfoForUri(props.uri)(state),
|
||||
// If I clicked the "edit" button, have I changed the uri?
|
||||
// Need this to make it easier to find the source on previously published content
|
||||
isStillEditing,
|
||||
balance: selectBalance(state),
|
||||
};
|
||||
};
|
||||
|
@ -62,6 +60,10 @@ const perform = dispatch => ({
|
|||
publish: params => dispatch(doPublish(params)),
|
||||
navigate: path => dispatch(doNavigate(path)),
|
||||
prepareEdit: (claim, uri) => dispatch(doPrepareEdit(claim, uri)),
|
||||
resetThumbnailStatus: () => dispatch(doResetThumbnailStatus()),
|
||||
});
|
||||
|
||||
export default connect(select, perform)(PublishPage);
|
||||
export default connect(
|
||||
select,
|
||||
perform
|
||||
)(PublishPage);
|
||||
|
|
|
@ -49,10 +49,10 @@ class ReportPage extends React.Component {
|
|||
<Page>
|
||||
<section className="card card--section">
|
||||
<div className="card__content">
|
||||
<div className="card__title">{__('Report an Issue')}</div>
|
||||
<div className="card__title">{__('Report an Issue/Request a Feature')}</div>
|
||||
<p>
|
||||
{__(
|
||||
'Please describe the problem you experienced and any information you think might be useful to us. Links to screenshots are great!'
|
||||
'Please describe the problem you experienced or the feature you want to see and any information you think might be useful to us. Links to screenshots are great!'
|
||||
)}
|
||||
</p>
|
||||
<FormRow>
|
||||
|
@ -65,7 +65,7 @@ class ReportPage extends React.Component {
|
|||
onChange={event => {
|
||||
this.onMessageChange(event);
|
||||
}}
|
||||
placeholder={__('Description of your issue')}
|
||||
placeholder={__('Description of your issue or feature request')}
|
||||
/>
|
||||
</FormRow>
|
||||
<div className="card__actions">
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue