Compare commits

...

614 commits

Author SHA1 Message Date
jessopb
fdd759b241
Merge pull request #1236 from ktprograms/readme-google-services
Add google-services.json instructions to README
2022-11-29 13:07:52 -05:00
jessopb
57cd649c02
Update README.md 2022-11-29 13:07:30 -05:00
jessopb
7250435d7f
Create deploy.yml 2022-11-25 14:03:02 -05:00
jessopb
b81abf74a1
Merge pull request #1244 from Coolguy3289/patch-1
Update LBRY_TV_CONNECTION_STRING to new Odysee Backend
2022-11-23 13:59:38 -05:00
Ralph
208e2c2d42
Update LBRY_TV_CONNECTION_STRING to new Odysee Backend 2022-11-23 11:29:52 -05:00
kt programs
a5bdd1c042 Add google-services.json instructions to README 2022-04-18 12:14:25 +08:00
Alex Grin
1e3a74cae1
Update README.md 2021-09-28 10:19:37 -04:00
Akinwale Ariwodola
ca08f71a72 sdk 0.102.0 2021-08-20 15:32:14 +01:00
Akinwale Ariwodola
b60ca39df1 fix crash bug when trying to play content 2021-08-19 12:27:18 +01:00
soup-jingle
696bc86b7c
Added QR scanner to wallet send card (#1194)
* Added QR scanner to wallet send card

* * app/src/main/java/io/lbry/browser/ui/wallet/WalletFragment.java:

Changed orientation of QR scanner, along with some style corrections

* Revert "* app/src/main/java/io/lbry/browser/ui/wallet/WalletFragment.java:"

This reverts commit 519c45ae0d.

* Fixed orientation of QR scanner activity, plus style corrections
2021-08-13 09:01:53 +01:00
Akinwale Ariwodola
4c163c6244
Merge pull request #1216 from lbryio/new_cdn_url
Use the new CDN url scheme for thumbnails
2021-08-13 09:01:09 +01:00
Akinwale Ariwodola
2ad49ca281
Merge pull request #1208 from lbryio/claimid-modifier-char
Accept colon or octoshape as claimID modifier character
2021-08-11 10:20:58 +01:00
Javi Rueda
56caeef72b Use the new CDN url scheme for thumbnails 2021-08-10 18:28:20 +02:00
Javi Rueda
84bb014557 Accept colon or octoshape as claimID modifier character and add unit tests 2021-07-29 00:55:45 +02:00
Akinwale Ariwodola
9278e74e85 remove reference to bintray 2021-06-25 19:34:58 +01:00
Akinwale Ariwodola
cf6f09c60d fix gitlab CI script 2021-06-25 19:25:29 +01:00
Akinwale Ariwodola
f2cbed48d9 fix git-secret install source 2021-06-25 19:23:30 +01:00
Akinwale Ariwodola
f1ead0c247 bumpversion 0.17.0 --> 0.17.1 2021-06-25 19:08:30 +01:00
Akinwale Ariwodola
5f2c72ec4d sdk 0.100.0 / switch to maven central for lbrysdk Gradle dependency 2021-06-25 19:07:47 +01:00
Javi Rueda
a6869eb2e6
Fix crash for anonymous content or without tags (#1190) 2021-05-10 17:14:22 +02:00
Javi Rueda
cbae6c476a
Claim has source (#1188)
* Pass has_source parameter to claim_search to ignore livestreamings

* Update to SDK 0.94.1 and allow user to view livestream content on Odysee
2021-05-10 17:13:28 +02:00
Javi Rueda
48d257ceaf
Show total wallet balance in USD instead of spendable balance conversion (#1186) 2021-04-19 19:55:49 +02:00
Javi Rueda
5355456498
Don't show link to Bittrex (#1181) 2021-04-12 18:53:59 +02:00
Javi Rueda
1436895ace
Copy file to public Downloads directory (#1180) 2021-04-12 18:53:13 +02:00
Javi Rueda
6e32f7724f
Notification improvements (#1175)
* Stop showing notification list when going from notification's content to related content

* Add is_app_readable parameter to notification_list call

* Return current fragment on main activity
2021-03-29 17:39:27 +02:00
Javi Rueda
3f5104d60a
Hide floating wallet on the Channel fragment (#1177)
* Hide floating wallet on the Channel fragment

* Unregister OnPageChangeCallback when exiting channel fragment
2021-03-29 17:38:51 +02:00
Javi Rueda
d8fdb3b818
Decode and encode urls with non-authorized characters (#1174)
* Decode URL encoded links and unit test it

* Encode UTF8 characters on LBRY.TV links and unit test it
2021-03-19 11:00:24 +01:00
Akinwale Ariwodola
5c187e7a8d Merge branch 'master' of https://github.com/lbryio/lbry-android 2021-03-16 09:24:53 +01:00
Akinwale Ariwodola
24862550a1 bumpversion 0.16.14 --> 0.17.0 2021-03-16 09:24:33 +01:00
Akinwale Ariwodola
146fced44e
Merge pull request #1162 from kekkyojin/wallet-total
Use total wallet balance instead of spendable
2021-03-16 09:22:57 +01:00
Akinwale Ariwodola
d535ed8c98
Merge pull request #1168 from lbryio/enable-phone-verification
Enable phone verification
2021-03-16 09:22:35 +01:00
Akinwale Ariwodola
b675dbad9b Merge branch 'master' of https://github.com/lbryio/lbry-android 2021-03-16 08:59:42 +01:00
Javi Rueda
dabe9fe691
Disable Javascript (#1171) 2021-03-15 20:08:18 +01:00
Javi Rueda
9ac216504d
Use ':' as separator for LBRY.TV sharing links (#1169) 2021-03-15 16:22:18 +01:00
Javi Rueda
911ca998e7 Use total wallet balance instead of spendable 2021-03-15 12:48:51 +01:00
Javi Rueda
36c105d3a7 Enable phone verification
Show the Close button after phone number has been verified
2021-03-11 17:46:17 +01:00
Akinwale Ariwodola
a655d0112b
PR cleanup (#1164)
* simplify code for readability
* code-cleanup. Make non-changing variables final
* Bump buildToolsVersion 29.0.1 -> 29.0.2 for FDroid build compability
* Set gradle version to static 3.6.4 instead of dynamic 3.+
* Use StandardCharsets.UTF_8 instead of string UTF8
* Remove unused imports
* Add missing null check

Co-authored-by: Patric Karlström <patric@pkcab.eu>
2021-03-08 20:15:23 +01:00
Akinwale Ariwodola
493c771e94 sdk 0.91.0 2021-03-08 19:52:15 +01:00
Akinwale Ariwodola
e9d70dbf87
Merge pull request #1163 from lbryio/iap-check
allow users to initiate a purchase flow check
2021-03-08 19:40:19 +01:00
Akinwale Ariwodola
0849ce2b66 allow users to initiate a purchase flow check 2021-03-08 19:38:00 +01:00
Javi Rueda
d0a8b3b218
Fix mass tips unlocking (#1157) 2021-03-06 00:32:12 +01:00
Javi Rueda
a8cdc4a771
Move the wallet floating button away when scroll gets to the bottom at FileViewFragment (#1155) 2021-03-04 19:11:19 +01:00
Javi Rueda
67b883660f
Hide support button and comments consistently with claim tags (#1152)
* Hide support button and comments consistently with claim tags

* Set visibility to GONE instead of INVISIBLE for the tipping button
2021-02-26 19:31:11 +01:00
Javi Rueda
f328efb831
Allow media to be played automatically (#1153)
* Allow media to be played automatically

* Fix for media been always autoplayed when opened from miniplayer
2021-02-26 19:24:17 +01:00
Javi Rueda
b2f56364d6
Use commentron instead of Comment SDK calls (#1149)
* Use commentron instead of Comment SDK calls

* Use current timestamp as 'id' for comment server request
2021-02-24 16:23:33 +01:00
Akinwale Ariwodola
2761857fe8
Merge pull request #1135 from kekkyojin/totvstring-unittest
Add unit test for LbryUri.toTvString
2021-02-22 20:07:55 +01:00
Akinwale Ariwodola
d439260d69
Merge pull request #1132 from kekkyojin/ignore_helpertest
Change HelperTest to JUnit4 and remove example test class
2021-02-16 17:02:48 +01:00
Akinwale Ariwodola
f0f0a5028b
Merge pull request #1123 from kekkyojin/style-code-tag
Styling <code> tag for Markdown content
2021-02-16 16:59:36 +01:00
Javi Rueda
13e170cb61 Add unit test for LbryUri.toTvString 2021-02-16 16:42:05 +01:00
Javi Rueda
127d8052ca Change HelperTest to JUnit4 and remove example test class 2021-02-12 01:28:22 +01:00
Javi Rueda
1b3086572f Styling <code> tag for Markdown content 2021-02-02 19:00:17 +01:00
Akinwale Ariwodola
6fa308ef96 bumpversion 0.16.13 --> 0.16.14 2021-01-25 18:54:00 +01:00
Akinwale Ariwodola
f3e513fc2d Update translations and content filters 2021-01-25 18:52:21 +01:00
Akinwale Ariwodola
d72a8faec4 sdk 0.88.0 2021-01-23 19:23:11 +01:00
Akinwale Ariwodola
fdb4578349
Merge pull request #1119 from kekkyojin/remove-sha256
Remove Helper.SHA256() method
2021-01-18 20:24:22 +01:00
Javi Rueda
c08237d399 Remove Helper.SHA256() method 2021-01-14 13:04:43 +01:00
Akinwale Ariwodola
bdf8a58818 bumpversion 0.16.12 --> 0.16.13 2021-01-12 09:11:26 +01:00
Akinwale Ariwodola
e1d51c881a Fix crash bug for anonymous repost claim results. Better handle channel repost navigation. 2021-01-12 09:07:33 +01:00
Akinwale Ariwodola
28212808f8
Merge pull request #1115 from pakar/master
Upgrade ExoPlayer from 2.11.4 to 2.12.2
2021-01-12 08:35:04 +01:00
Akinwale Ariwodola
74f08f8f98
Merge pull request #1102 from kekkyojin/fix-markdown-rendering
Use Base64 to encode html when rendering Markdown files
2021-01-12 08:33:40 +01:00
Akinwale Ariwodola
cb5c29fbce
Merge pull request #1117 from kekkyojin/fix-nosuchmethod-commons
Fix NoSuchMethod exception for HelperSHA256 on API Level prior to P
2021-01-12 08:32:08 +01:00
Javi Rueda
4d775d3a17 Fix NoSuchMethod exception for HelperSHA256 on API Level prior to P 2021-01-11 20:44:03 +01:00
Patric Karlström
fd94ef9fa7 Upgrade ExoPlayer from 2.11.4 to 2.12.2 2021-01-11 01:10:23 +01:00
Javi Rueda
2e0331305a Use Base64 to encode html when rendering Markdown files 2020-12-29 11:30:05 +01:00
Akinwale Ariwodola
fb560f8f01 fix last resource build error 2020-12-29 07:20:46 +01:00
Akinwale Ariwodola
ef80c9f7fd fix resource build error 2020-12-29 07:13:57 +01:00
Akinwale Ariwodola
99a4a0a22f Remove comment post confirmation. Fix resources build error. 2020-12-29 07:07:53 +01:00
Akinwale Ariwodola
136853853a bumpversion 0.16.11 --> 0.16.12 2020-12-29 07:02:13 +01:00
Akinwale Ariwodola
ebf3299c30 add scrollbars attribute to listview 2020-12-29 07:00:45 +01:00
Akinwale Ariwodola
036b49a871
Merge pull request #1097 from kekkyojin/remove_stages_scrollbar
Avoid showing vertical scroll bar on stage error listview
2020-12-29 07:00:02 +01:00
Akinwale Ariwodola
67d5f88d34
Merge pull request #1100 from clay53/master
Changed wallet send notification to accept 4 digit decimal
2020-12-29 06:52:16 +01:00
Akinwale Ariwodola
b1e0b9af33 sdk 0.87.0. Show confirmation for unfollow. 2020-12-29 06:47:10 +01:00
Clayton Hickey
c30b012787 Changed wallet send notification to accept 4 digit decimal 2020-12-27 03:54:36 -05:00
Javi Rueda
c8c6305757 Avoid showing vertical scroll bar on stage error listview 2020-12-22 02:26:37 +01:00
Akinwale Ariwodola
ee1d090e62
Merge pull request #1068 from kekkyojin/fix-lintproblems
Some fixes for lint
2020-12-21 19:43:08 +01:00
Javi Rueda
9e56a86492 Some fixes for lint 2020-12-18 14:30:48 +01:00
Akinwale Ariwodola
e6b83877f1
Merge pull request #1063 from clay53/1042
Removed comment tips
2020-12-18 13:01:49 +01:00
Akinwale Ariwodola
b567e39aef
Merge pull request #1069 from kekkyojin/add-twitter-instructions
Provide instructions to add dummy Twitter API credentials
2020-12-18 12:22:03 +01:00
Akinwale Ariwodola
ae62dba0a6
Merge pull request #1071 from kekkyojin/sha256-unittest
Add unit test for Helper.SHA256(String)
2020-12-18 12:21:39 +01:00
Akinwale Ariwodola
df1e8abf50
Merge pull request #1067 from kekkyojin/use-apache-hex
Replace Hex class from GMS with the one from Apache
2020-12-18 12:20:42 +01:00
Javi Rueda
31cfb26c3b Add unit test for Helper.SHA256(String) 2020-12-15 13:45:32 +01:00
Javi Rueda
e5f34dc464 Provide instructions to add dummy Twitter API credentials 2020-12-14 20:38:57 +01:00
Javi Rueda
601031e55d Replace Hex class from GMS with the one from Apache 2020-12-14 18:17:13 +01:00
Akinwale Ariwodola
a9aadbe6a8 bumpversion 0.16.10 --> 0.16.11 2020-12-13 18:08:10 +01:00
Akinwale Ariwodola
f9a4b71037 fix crash error when following doesn't exist in shared user state 2020-12-13 18:07:19 +01:00
Clayton Hickey
0f10e9dc1f Removed comment tips 2020-12-12 20:11:00 -05:00
Akinwale Ariwodola
0647deb06c
Merge pull request #1061 from kekkyojin/startupstage-listview
Use ListView to show startup stage errors
2020-12-12 23:16:17 +01:00
Akinwale Ariwodola
b2f5fec293 make the channel filter name alphabet uppercase 2020-12-10 09:57:27 +01:00
Javi Rueda
daf4e5aca2 Use ListView to show startup stage errors 2020-12-09 21:05:21 +01:00
Akinwale Ariwodola
c1324efb41 bumpversion 0.16.9 --> 0.16.10 2020-12-09 11:47:58 +01:00
Akinwale Ariwodola
6221de2d3c sync notificationsDisabled states for followed channels 2020-12-09 11:31:13 +01:00
Akinwale Ariwodola
983bc68af2 Merge branch 'master' of https://github.com/lbryio/lbry-android 2020-12-09 11:00:25 +01:00
Akinwale Ariwodola
f1b167693d SDK 0.86.1. is_seen vs is_read swap. Fix error condition where wallet sync starts if the wallet is not ready. 2020-12-09 10:59:25 +01:00
Akinwale Ariwodola
68ac64b534
Merge pull request #1057 from kekkyojin/sort-commentreplies
Sort replies from oldest to newest
2020-12-05 04:32:41 +01:00
Javi Rueda
6819ae46f9 Sort replies from oldest to newest 2020-12-01 04:58:48 +01:00
Akinwale Ariwodola
6c406c5a85 share_usage_data setting 2020-11-29 05:07:54 +01:00
Akinwale Ariwodola
c179243d22 update dependencies 2020-11-26 00:04:37 +01:00
Akinwale Ariwodola
d0f5504c80 LbryUri parsing improvements. Remove duplicate code. 2020-11-15 09:11:50 +01:00
Akinwale Ariwodola
896c566a02
Merge pull request #1045 from kekkyojin/open-file-external
Offer opening unsupported filetypes with external app
2020-11-13 15:42:59 +01:00
Javi Rueda
da9352cc68 Offer opening unsupported filetypes with external app 2020-10-27 14:28:15 +01:00
Akinwale Ariwodola
b8d2375e20
Merge pull request #1044 from ycohen-dev/fix_issue_1043
Fix floating wallet/rewards bar for RTL layout
2020-10-23 13:25:07 +01:00
Akinwale Ariwodola
dd52ff9d07
Merge pull request #1033 from kekkyojin/md-text-rendering
Fix for text not rendering after # in markdown
2020-10-23 13:23:15 +01:00
yuval
d9891f8a8a Floating wallet balance/rewards now visible in RTL layout
(Fix issue #1043)
2020-10-22 22:22:44 +03:00
Akinwale Ariwodola
ea5fe6842d
Merge pull request #1041 from ycohen-dev/fix_issue_1040
fix issue 1040
2020-10-21 00:15:36 +01:00
Akinwale Ariwodola
fc649187df
Merge pull request #1039 from ycohen-dev/fix_issue_1038
fix issue 1038
2020-10-21 00:14:15 +01:00
yuval
b0f7c41885 fix issue 1040
Transaction amount text Direction changed to LTR.
Transaction amount pinned to end of view
2020-10-17 22:18:14 +03:00
yuval
45935717c8 fix issue 1038
Replaced gravity pinning to "end" instead of "right"
Pinned claim id which could be in rtl and ltr scripts to the start of the layout
2020-10-16 23:40:28 +03:00
Akinwale Ariwodola
ac5e666369 bumpversion 0.16.8 --> 0.16.9 2020-10-16 06:58:57 +01:00
Akinwale Ariwodola
ffeb72a383 Publish mature tags. String resource updates. 2020-10-16 06:53:08 +01:00
Akinwale Ariwodola
0ec09d751c
Merge pull request #1036 from ycohen-dev/fix_issue_1034
Fix issue #1034
2020-10-16 06:39:45 +01:00
Akinwale Ariwodola
b8e4fcff92
Merge pull request #1037 from lbryio/follow-text
add follow text beside follow icon
2020-10-16 06:37:50 +01:00
Akinwale Ariwodola
b79f0f4820 add follow text beside follow icon 2020-10-16 06:36:36 +01:00
yuval
a1cd58a214 Fix issue #1034
Hide notifications when entering PiP mode
2020-10-16 00:11:08 +03:00
Javi Rueda
cfca8facbe Use '%23' instead of '#' when rendering #hashtag style text from markdown 2020-10-15 01:49:53 +02:00
Akinwale Ariwodola
066a0a099c
Merge pull request #1032 from lbryio/wallet-balance-page
use credits icon on wallet balance page
2020-10-14 15:33:25 +01:00
Akinwale Ariwodola
afeee2e5df use credits icon on wallet balance page 2020-10-14 15:30:59 +01:00
Akinwale Ariwodola
76036acfc7 Merge branch 'master' of https://github.com/lbryio/lbry-android 2020-10-14 15:17:35 +01:00
Akinwale Ariwodola
897bfdaffd fix build error 2020-10-14 15:16:45 +01:00
Akinwale Ariwodola
7475ae323c
Merge pull request #1031 from ycohen-dev/fix_issue_1030
Fix issue #1030
2020-10-14 15:12:34 +01:00
Akinwale Ariwodola
faf7f3ccbf make credits translatable 2020-10-14 15:11:36 +01:00
Akinwale Ariwodola
4940d1ca33 Merge branch 'master' of https://github.com/lbryio/lbry-android 2020-10-14 15:10:25 +01:00
Akinwale Ariwodola
3d48fa5741 also check pending when checking if item is a placeholder 2020-10-14 15:09:59 +01:00
yuval
f9887cffae Fix issue #1030
Dismiss all active dialog fragment when entering PiP mode
So that PiP window contain the video only
2020-10-13 23:17:58 +03:00
Akinwale Ariwodola
6644907665
Merge pull request #1027 from ycohen-dev/fix_issue_1025
Fix issue #1025
2020-10-12 19:25:48 +01:00
Akinwale Ariwodola
5f850685d6 bumpversion 0.16.7 --> 0.16.8 2020-10-12 11:48:24 +01:00
Akinwale Ariwodola
5f9674e49c do not open lbry.*/$/verify links in the app 2020-10-12 11:47:45 +01:00
yuval
0d185c6db3 Fix issue #1025
Increased size of currency selection spinner in publish form fragment
Now spinner is in proper size to display "LBRY Credits" default value
2020-10-10 16:58:29 +03:00
Akinwale Ariwodola
53d22dd22d remove debug logs 2020-10-09 07:43:38 +01:00
Akinwale Ariwodola
ff8ffda3c6 bumpversion 0.16.6 --> 0.16.7 2020-10-09 07:39:46 +01:00
Akinwale Ariwodola
64bd540322
In-app notification options (#1023)
* pull-down to refresh in-app notifications
* support deleting notifications
2020-10-09 07:38:47 +01:00
Akinwale Ariwodola
919f9a48f3
Merge pull request #1022 from lbryio/bell-icon
per-channel subscribe notification toggle
2020-10-09 06:58:08 +01:00
Akinwale Ariwodola
746d442051 per-channel subscribe notification toggle 2020-10-09 06:56:13 +01:00
Akinwale Ariwodola
1877b75188 fix strings.xml 2020-10-06 07:14:42 +01:00
Akinwale Ariwodola
6e8c38cace update module versions 2020-10-05 16:56:17 +01:00
Akinwale Ariwodola
eab7bab267
Credits icon (#1021)
* new credits icon
* remove references to LBC
2020-10-05 16:50:39 +01:00
Akinwale Ariwodola
aab648c3cf
Fix errors with deep link handling (#1019) 2020-10-02 12:39:37 +01:00
Javi Rueda
f79ff509bd
Support some lbry hosts to deep links. Add unit tests (#1008)
* Support lbry.tv and other supported hosts for deep links. Add unit tests for LbryUri parse() method
* add unit test for lbry protocol schema
* Add unit test for lbry.tv deep-link with only channel
2020-10-02 12:34:38 +01:00
Akinwale Ariwodola
1197e990ca cleanup debug logging 2020-10-02 12:09:33 +01:00
Akinwale Ariwodola
dce1c0715e move Unpublish button 2020-10-02 12:08:33 +01:00
Akinwale Ariwodola
6a0263c5bc
Merge pull request #1013 from clay53/987
Add ability to download & delete your own videos and move unpublish button to description
2020-10-02 11:05:44 +01:00
Akinwale Ariwodola
ca64db0499 sdk 0.82.0 2020-10-01 12:42:48 +01:00
Akinwale Ariwodola
a5d4eda4d1 bumpversion 0.16.5 --> 0.16.6 2020-09-25 14:45:48 +01:00
Akinwale Ariwodola
5d210961c1 apply mature filter to Editor's Choice 2020-09-25 14:41:40 +01:00
Akinwale Ariwodola
1b88f565af bumpversion 0.16.4 --> 0.16.5 2020-09-23 16:37:41 +01:00
Akinwale Ariwodola
991a98b571 fix shuffle mode player getting stuck 2020-09-23 16:35:59 +01:00
Akinwale Ariwodola
0073277d6e
Merge pull request #1017 from lbryio/shuffle-random
keep track of watched content for subsequent shuffle sessions
2020-09-23 16:23:57 +01:00
Akinwale Ariwodola
eeca602f7a keep track of watched content for subsequent shuffle sessions 2020-09-23 15:31:34 +01:00
Akinwale Ariwodola
6c171560fd remove Finnish strings 2020-09-18 14:56:35 +01:00
Akinwale Ariwodola
66c4c00215 bumpversion 0.16.3 --> 0.16.4 2020-09-18 14:54:59 +01:00
Akinwale Ariwodola
9b9ef9ab74
Surf mode experiment (#1003)
* surf mode implementation
* occupy entire vertical area
* fix onResume logic
* shuffle mode with selected channel ids
2020-09-18 14:53:19 +01:00
Clayton Hickey
39a289e7f1
Add ability to download & delete your own videos and move unpublish button to description 2020-09-16 14:31:03 -04:00
Akinwale Ariwodola
722c829502 fix paid content stream source 2020-09-14 18:21:31 +01:00
Akinwale Ariwodola
7ecb80d136
Merge pull request #1009 from lbryio/mini-player-margin
add setting for mini-player bottom spacing
2020-09-14 18:05:09 +01:00
Akinwale Ariwodola
ea19af04d4 add setting for mini-player bottom spacing 2020-09-14 18:01:38 +01:00
Akinwale Ariwodola
8196b69211 bumpversion 0.16.2 --> 0.16.3 2020-09-14 11:20:47 +01:00
Akinwale Ariwodola
dc861caf6c fix websocket for Android < 7.0 2020-09-14 11:19:50 +01:00
Akinwale Ariwodola
adb5ffa8d0 exclude x86_64 lib from build 2020-09-14 11:06:39 +01:00
Akinwale Ariwodola
d918cb28bd sdk 0.81.0 2020-09-11 13:50:16 +01:00
Akinwale Ariwodola
7ce7314ab9 bumpversion 0.16.1 --> 0.16.2 2020-09-11 13:41:30 +01:00
Javi Rueda
13e5caa0ef
Use Start/End instead of Left/Right to support RTL (#1005)
* Use Start/End instead of Left/Right to support RTL
* Change it also for relative layout properties
2020-09-11 13:28:37 +01:00
Akinwale Ariwodola
ff59a7a89f
Merge pull request #1007 from lbryio/first-run-install-id
generate install_id natively
2020-09-11 13:22:42 +01:00
Akinwale Ariwodola
c3efa4d004 generate install_id natively 2020-09-10 12:20:49 +01:00
Akinwale Ariwodola
ed50e1300a
real time notifications over websocket (#1000)
* real time notifications over websocket
* automatically re-establish websocket connections
2020-09-09 14:16:22 +01:00
Akinwale Ariwodola
86dbfd54d1
Merge pull request #1006 from lbryio/notification-back
proper back navigation to the notifications screen
2020-09-09 14:05:29 +01:00
Akinwale Ariwodola
535120eebd proper back navigation to the notifications screen 2020-09-09 14:03:36 +01:00
Akinwale Ariwodola
c1106d7186 display correct playback speed for media 2020-09-04 12:50:22 +01:00
Akinwale Ariwodola
45be7f2c9b
Merge pull request #1004 from lbryio/player-resume-black-screen
display player view correctly after dismissing PIP view
2020-09-04 12:33:53 +01:00
Akinwale Ariwodola
d6baf3d1c8 display player view correctly after dismissing PIP view 2020-09-04 12:32:53 +01:00
Akinwale Ariwodola
08c38c1723 bumpversion 0.16.0 --> 0.16.1 2020-08-28 10:07:20 +01:00
Javi Rueda
af4fa454d3
Add setting to enable sending buffering events (#993)
* Add setting to enable sending buffering events
* Use true as default value
2020-08-28 10:06:41 +01:00
Akinwale Ariwodola
0620582a4e fix in-app notification read background in dark mode 2020-08-28 10:04:10 +01:00
Akinwale Ariwodola
b11c07e3d1 fix comment redirect from device notifications 2020-08-28 10:00:57 +01:00
Akinwale Ariwodola
593b34079c load notifications after app startup 2020-08-20 20:47:14 +01:00
Akinwale Ariwodola
becb533624 fix notification relative time display 2020-08-20 20:32:22 +01:00
Akinwale Ariwodola
8efc0522f2 load unread count after fetching remote notifications 2020-08-20 20:03:30 +01:00
Akinwale Ariwodola
cead924ca5 Notification timestamp timezone fix. Tweak loading unread notification count. 2020-08-20 19:56:35 +01:00
Akinwale Ariwodola
f83a043664 fix notification sorting 2020-08-20 19:00:21 +01:00
Akinwale Ariwodola
e8a0bca5ea tweak equality check for LbryNotification 2020-08-20 18:45:02 +01:00
Akinwale Ariwodola
1198c2298a add and update translations 2020-08-20 18:28:32 +01:00
Akinwale Ariwodola
7205acb9d6 Sort newly added notifications. Add remote loading TTL. 2020-08-20 18:06:35 +01:00
Akinwale Ariwodola
d21cfd55ab Handle special URLs from notifications. Disable auto load/play for comment notifications. 2020-08-20 16:39:45 +01:00
Akinwale Ariwodola
47cbc3624c
Merge pull request #980 from lbryio/channel-comment-hash
properly handle channel comment notifications
2020-08-20 16:26:08 +01:00
Akinwale Ariwodola
1f9a0886a0 properly handle channel comment notifications 2020-08-20 16:20:46 +01:00
Akinwale Ariwodola
dd5ea68915 new YRBL 2020-08-20 14:52:41 +01:00
Akinwale Ariwodola
b3bba4d273
Merge pull request #979 from lbryio/is-seen
check is_seen flag. display comment author thumbnails if present.
2020-08-20 13:30:28 +01:00
Akinwale Ariwodola
10c123ba6a check is_seen flag. display comment author thumbnails if present. 2020-08-20 13:26:41 +01:00
Akinwale Ariwodola
a8ba45b941 bumpversion 0.15.17 --> 0.16.0 2020-08-19 18:18:37 +01:00
Akinwale Ariwodola
3652cdf6bc CI apt-transport-https 2020-08-19 18:14:13 +01:00
Akinwale Ariwodola
f2a7a8c439 cleanup: yarn.lock 2020-08-19 18:10:57 +01:00
Akinwale Ariwodola
78d5a99441
Gradle fix (#978) 2020-08-19 18:09:37 +01:00
Akinwale Ariwodola
6931dbe79c
Instant verification (#974)
* add instant verification options and Google Play Billing
bumpversion 0.15.16 --> 0.15.17
restore account_undergo_review default string
twitter sign-in flow
fix build error
final changes
update api key and secret
* tweak build script
2020-08-19 17:23:35 +01:00
Akinwale Ariwodola
4d024c06cc
In-app notifications (#969)
* display notification bell icon beside URL bar
* notification model
* persist received notifications
* Refresh notification list. Add  is_read flag and display unread count.
* Hide notifications when opening the navigatinon drawer. Open selected notification item before hiding the list.
* update local store with remote notifications
* use card view for notification items
* make notification cards clickable
* handle comment hash
* fix remote notifications not loading. fix comment scroll.
* Improve in-app comment notification linking. Add icons.
2020-08-18 14:19:35 +01:00
Akinwale Ariwodola
ddcb190457 do not display global background servce initializing indicator 2020-08-07 10:11:57 +01:00
Akinwale Ariwodola
dd14b90d7e
Merge pull request #967 from kekkyojin/sendto-feat
Allow to publish files via Send To feature
2020-07-29 15:20:59 +01:00
Akinwale Ariwodola
4b86444478 bumpversion 0.15.15 --> 0.15.16 2020-07-27 11:11:10 +01:00
Javi Rueda
feb7f260dc Allow to publish files via Send To feature 2020-07-24 01:59:59 +02:00
Akinwale Ariwodola
74c7a1de4d sdk 0.79.1. Clear resolved sub cache after sync. 2020-07-23 20:04:48 +01:00
Akinwale Ariwodola
88a43dc679 set sync interval back to 5 minutes 2020-07-22 05:52:44 +01:00
Akinwale Ariwodola
1bb5ce72fa Proper fix for subscription sync retention. Eliminate double sync attempt on startup. 2020-07-22 05:49:48 +01:00
Akinwale Ariwodola
b4ce544965 bumpversion 0.15.14 --> 0.15.15 2020-07-21 21:25:26 +01:00
Akinwale Ariwodola
1ec6f6173a sdk 0.79.0 2020-07-21 21:13:05 +01:00
Akinwale Ariwodola
8ee19b3f5c
Sub sync fix (#965)
* improve sub sync merge handling logic
* do not try to re-subscribe local syncs remotely whhen merging
2020-07-21 19:49:22 +01:00
Akinwale Ariwodola
1055392b7f temporarily omit duration 2020-07-21 19:39:47 +01:00
Akinwale Ariwodola
c772cf2ead
check buffering events (#952)
* check buffering events
* use the claim permanent url for buffer events
* update request parameters
* hash user ids for buffer events
* update buffer event endpoint
2020-07-21 19:30:45 +01:00
Akinwale Ariwodola
481c50f465 fix open.lbry.com regex 2020-07-17 11:39:59 +01:00
Akinwale Ariwodola
71bc969f2a
Merge pull request #962 from kekkyojin/deeplink
Add open.lbry.com deep-links
2020-07-17 11:29:16 +01:00
Akinwale Ariwodola
e4edebfed7 fix for follow / unfollow confusion 2020-07-16 13:51:08 +01:00
Javi Rueda
e8a5ab8307 Add open.lbry.com deep-links 2020-07-13 19:00:12 +02:00
Akinwale Ariwodola
3738f3af21
Merge pull request #954 from lbryio/invalidated-auth
gracefully handle invalidated auth tokens
2020-07-05 19:07:21 +01:00
Akinwale Ariwodola
74d10e4199 gracefully handle invalidated auth tokens 2020-07-05 18:40:31 +01:00
Akinwale Ariwodola
080e00becf
Merge pull request #949 from kekkyojin/patch-1
Bintray repository is no longer needed
2020-06-30 15:30:18 +01:00
Javi Rueda
049d905d7d
Bintray repository is no longer needed
LBRY SDK is now hosted on JCenter, which is already available out-of-the-box on Android Studio. The Bintray url is no longer reguired. When building LBRY on F-Droid, I have to remove this line on the build YAML script and it is building correctly.

On my local machine, it builds after commenting it.
2020-06-26 21:06:12 +02:00
Akinwale Ariwodola
33094f8c88 fix empty bindArgs crash error for sql query to clear subscriptions 2020-06-25 23:33:04 +01:00
Akinwale Ariwodola
6c44e503db
fix subscriptions sync (#947) 2020-06-25 21:16:41 +01:00
Akinwale Ariwodola
fa78c80592 fix ClaimListAdapter and strings.xml 2020-06-25 20:42:55 +01:00
Akinwale Ariwodola
07630ca97b fix: crash bugs 2020-06-25 20:23:24 +01:00
Akinwale Ariwodola
a2b6d4e570 bumpversion 0.15.13 --> 0.15.14 2020-06-25 20:16:38 +01:00
Akinwale Ariwodola
9d6b3ddf81
combined tip / support dialog and signed supports (#944)
* combined tip / support dialog and signed supports
* update button label when amount is updated
2020-06-25 20:15:58 +01:00
Akinwale Ariwodola
0a2769859a fix issue with featured search result crash 2020-06-24 10:45:29 +01:00
Akinwale Ariwodola
c4a1ed801a make FontAwesome strings non-translatable 2020-06-19 07:18:19 +01:00
Akinwale Ariwodola
453394bf1b update README 2020-06-19 06:57:48 +01:00
Akinwale Ariwodola
4b7dfba5a1 sdk 0.76.0 2020-06-15 19:43:41 +01:00
Akinwale Ariwodola
e699fcf0b3 remove broken Bengali strings.xml 2020-06-15 19:29:26 +01:00
Akinwale Ariwodola
7e80f707e0 bumpversion 0.15.12 --> 0.15.13 2020-06-15 19:17:18 +01:00
Akinwale Ariwodola
467f037170 sFix default sort on channel page. Add Bengali and Javanese translations. 2020-06-15 19:11:20 +01:00
Akinwale Ariwodola
89d5b40e5f only allow sending to addresses that begin with b 2020-06-15 15:18:42 +01:00
Akinwale Ariwodola
34fba010e1 use lbryplayer.xyz streaming URLs for signed in users 2020-06-15 15:07:17 +01:00
Akinwale Ariwodola
d7396bb044
add MoonPay 'Buy LBC' button (#937)
* add MoonPay 'Buy LBC' button
* tweak button style
* tweak MoonPay parameters
2020-06-13 16:14:06 +01:00
joaquimbrugues
fda0817ad1
Add Catalan language (#928)
* Add Catalan language
* Add 'catalan' string to strings.xml
* Attempt to fix conflicting changes
2020-06-11 19:41:53 +01:00
Akinwale Ariwodola
895ca75506
Merge pull request #935 from lbryio/edit-publish-channel
auto select corresponding channel when editing a publish
2020-06-11 19:38:24 +01:00
Akinwale Ariwodola
a04448ebe8 auto select corresponding channel when editing a publish 2020-06-11 19:31:06 +01:00
Akinwale Ariwodola
26ccbf2709 reduce comment cost from 2 to 1 2020-06-10 09:54:07 +01:00
Akinwale Ariwodola
7d6c11a88c Remove lbrysdk AARs. Add bintray dependencies. 2020-06-09 22:27:42 +01:00
Akinwale Ariwodola
8742913c33 SDK 0.75.0. Update translations. 2020-06-05 15:31:13 +01:00
Akinwale Ariwodola
8e6e0f0099 fix player notification pending intent 2020-06-05 09:42:45 +01:00
Akinwale Ariwodola
a4585de807 reset playback notification large icon when content changes 2020-06-05 09:40:22 +01:00
Akinwale Ariwodola
6c24749ad5 tweak player view resume 2020-06-05 09:34:45 +01:00
Akinwale Ariwodola
c73509a4ca set large icon for playback notification 2020-06-05 09:30:54 +01:00
Akinwale Ariwodola
673b85b2aa bumpversion 0.15.11 --> 0.15.12 2020-06-05 09:07:35 +01:00
Akinwale Ariwodola
fe6e60cd67 implement background playback with control notification 2020-06-05 09:04:24 +01:00
Akinwale Ariwodola
8bcee90d68 Add background playback setting. Fix crash bugs. 2020-06-05 08:25:08 +01:00
Akinwale Ariwodola
084407e129 Update translations. Add Catalan and Serbian strings. 2020-06-05 07:50:52 +01:00
Akinwale Ariwodola
4a3db5ae20 enforce minimum spend / deposits 2020-06-05 07:40:44 +01:00
Akinwale Ariwodola
b36813ebe6 fix nsfw search flag 2020-06-05 07:23:56 +01:00
Akinwale Ariwodola
cc1ddfa16e use only txids for unlocking tips 2020-06-05 07:17:56 +01:00
Akinwale Ariwodola
5f1775d478 fix possible null item in channel id list 2020-06-05 07:04:54 +01:00
Akinwale Ariwodola
288e35dd64 fix margins 2020-06-02 09:40:17 +01:00
Akinwale Ariwodola
d4af28d1c5 display publisher title and thumbnail on file page 2020-06-02 09:34:59 +01:00
Akinwale Ariwodola
37cf85a5f6 bumpversion 0.15.10 --> 0.15.11 2020-06-02 09:05:04 +01:00
Akinwale Ariwodola
c2cbd76f49 change comment confirmation title 2020-06-02 09:03:56 +01:00
Akinwale Ariwodola
3d874435c3 change BigDecimal initialisation for comment cost 2020-06-02 08:57:12 +01:00
Akinwale Ariwodola
9ed8864f23 More crash fixes. Change comment cost to 2 LBC. 2020-06-02 08:55:34 +01:00
Akinwale Ariwodola
61263dd59d bumpversion 0.15.9 --> 0.15.10 2020-06-01 08:56:38 +01:00
Akinwale Ariwodola
2707e135c6 comment creation event 2020-06-01 08:53:58 +01:00
Akinwale Ariwodola
f9de0d7937 do not prompt again for content that is already purchased 2020-06-01 08:48:17 +01:00
Akinwale Ariwodola
f03d58d648 tweak PIP player for certain aspect ratios 2020-06-01 08:33:07 +01:00
Akinwale Ariwodola
f49a3570e9 fix file view display for cached reposts 2020-05-31 21:22:37 +01:00
Akinwale Ariwodola
1d97f9008d
implement commenting with tips (#922)
* implement commenting with tips
* add comments to channel page
2020-05-31 21:06:03 +01:00
Akinwale Ariwodola
e85ca9114c
Merge pull request #921 from lbryio/crash-fixes
fixes for Play Store crash reports
2020-05-31 16:20:59 +01:00
Akinwale Ariwodola
85ed2da518 fixes for Play Store crash reports 2020-05-31 16:19:33 +01:00
Clayton Hickey
dcc91f75cc
Added ability to read comments on claims (#920)
* Added ability to read comments on claims
* Added simple handling for pagination in CommentListTask
2020-05-30 00:47:50 +01:00
Akinwale Ariwodola
a40c160ac6 fix selection mode for reposts on Publishes page 2020-05-28 03:45:56 +01:00
Akinwale Ariwodola
e6861c8436 set timestamp when building claim object from edited claim 2020-05-28 03:25:42 +01:00
Akinwale Ariwodola
e6a5d97fb8 bumpversion 0.15.8 --> 0.15.9 2020-05-28 03:23:45 +01:00
Akinwale Ariwodola
ddeb209d51 fix publish release time and crash bug on publish form 2020-05-28 03:22:20 +01:00
Akinwale Ariwodola
3283b3a607 fix channel links on history page 2020-05-27 23:22:08 +01:00
Akinwale Ariwodola
83a41ca6ce auto-rotate video to sensor landscape orientation 2020-05-27 23:16:25 +01:00
Akinwale Ariwodola
6c63eb7d66 better handling of permanent storage permission denial on file view page 2020-05-27 23:11:09 +01:00
Akinwale Ariwodola
7cf9de8c2a fix typo 2020-05-27 23:01:00 +01:00
Akinwale Ariwodola
a859682954 fix permission request handling for permanently denied permissions 2020-05-27 22:56:07 +01:00
Akinwale Ariwodola
c844c4f896 fix PIP mode display for Android version < 10 2020-05-27 11:20:51 +01:00
Akinwale Ariwodola
a49cfe91da remove debug logs 2020-05-27 10:58:28 +01:00
Akinwale Ariwodola
2bacba2c87 properly close all activities when service is stopped 2020-05-27 10:52:25 +01:00
Akinwale Ariwodola
e473981063 fix more crash bugs reported in Play Store 2020-05-27 08:25:10 +01:00
Akinwale Ariwodola
34ea4f216c add Dutch and Hindi strings 2020-05-27 02:06:41 +01:00
Akinwale Ariwodola
52e34b3027 don't hide play / pause button while buffering 2020-05-27 01:15:02 +01:00
Akinwale Ariwodola
c6a6ea0445 reset click listener onStop 2020-05-27 01:11:18 +01:00
Akinwale Ariwodola
59ae6340e1 disable gif animation in thumbnails 2020-05-27 00:56:07 +01:00
Akinwale Ariwodola
cbf2aa2311 bumpversion 0.15.6 --> 0.15.7 2020-05-26 16:26:15 +01:00
Akinwale Ariwodola
94b0c7bc01 Fix additional Play Store crash bugs. 2020-05-26 16:25:37 +01:00
Akinwale Ariwodola
4c50ffac19
Merge pull request #898 from lbryio/user-bugs
fix reported bugs from 0.15.3
2020-05-26 16:09:51 +01:00
Akinwale Ariwodola
551e736651 fix reported bugs from 0.15.3 2020-05-26 16:09:14 +01:00
Akinwale Ariwodola
0380e35966 bumpversion 0.15.5 --> 0.15.6 2020-05-26 10:58:47 +01:00
Akinwale Ariwodola
5de0906fc1 make splash view clickable to prevent clicking views underneath 2020-05-26 10:57:12 +01:00
Akinwale Ariwodola
c2f17b6230 Add Italian strings. Save and resume from last media playback position. 2020-05-26 10:38:16 +01:00
Akinwale Ariwodola
6a3bbe6c0d bumpversion 0.15.4 --> 0.15.5 2020-05-25 20:10:34 +01:00
Akinwale Ariwodola
82307c9f98 Increase timeout for remote user requests. Wrap long pre lines in markdown display. 2020-05-25 20:08:24 +01:00
Akinwale Ariwodola
d2ec0e2aa1 Display reposts on following page. Update Spanish strings. 2020-05-25 15:15:48 +01:00
Akinwale Ariwodola
3951b1080d different new publish from publish update 2020-05-25 12:14:12 +01:00
Akinwale Ariwodola
ef7caeeead Fix subsequent web view display. Add Estonian and Russian strings. 2020-05-25 11:33:12 +01:00
Akinwale Ariwodola
7ef8e2029e Tweak transaction pending text display 2020-05-25 06:03:46 +01:00
Akinwale Ariwodola
aaec6ac6a3 wait for uploads to finish before saving channel form 2020-05-25 06:00:34 +01:00
Akinwale Ariwodola
731960da7c bumpversion 0.15.3 --> 0.15.4 2020-05-25 05:50:02 +01:00
Akinwale Ariwodola
ac282d2667 log cleanup 2020-05-25 05:48:26 +01:00
Akinwale Ariwodola
7a79601cfc don't enable fullscreen mode when entering PIP mode 2020-05-25 05:47:14 +01:00
Akinwale Ariwodola
d1167e4d2b Disable selection mode for purchases. Check additional cases for displaying unsupported content message. 2020-05-25 05:38:25 +01:00
Akinwale Ariwodola
613634adcf get transaction id for first_publish and new_channel rewards 2020-05-25 00:32:21 +01:00
Akinwale Ariwodola
acbe33c66d Limit gallery items to 150. Download filtering. Open rewards page from Invites reward driver card. 2020-05-25 00:04:40 +01:00
Akinwale Ariwodola
053ebbd70b dDisplay better error message if authentication fails on first run. Change lineHeight to lineSpacingMultiplier. 2020-05-24 21:27:49 +01:00
Akinwale Ariwodola
f5dc4fa4e7 Remove new intent debug logs. Update packages in build.gradle 2020-05-24 20:48:01 +01:00
Akinwale Ariwodola
343270b757 Show auto-claim rewards message at activity level. Add German strings. 2020-05-24 20:34:19 +01:00
Akinwale Ariwodola
65f5626aba More tweaks to PIP mode restore. 2020-05-24 20:29:11 +01:00
Akinwale Ariwodola
a051a73c2b Tweak PIP restore. Fix Library wunderbar value. 2020-05-24 18:54:33 +01:00
Akinwale Ariwodola
6840997793 Add 'subscription' to special URLs map. Fix PIP restore for onNewIntent. 2020-05-24 18:46:47 +01:00
Akinwale Ariwodola
2c98ed2d8d Always display rewards driver on Invites page. Rewards drivers minimum display amounts. 2020-05-24 18:37:05 +01:00
Akinwale Ariwodola
6a083c4152 Update Afrikaans strings. Add Vietnamese strings. 2020-05-24 18:18:39 +01:00
Akinwale Ariwodola
b60b5d16c3 fix crash bugs reported in Play Store 2020-05-24 10:11:31 +01:00
Akinwale Ariwodola
52cfe8dc12 add blocking param to txo_spend 2020-05-24 05:02:55 +01:00
Akinwale Ariwodola
737afca031 fix onNewIntent logging 2020-05-24 04:50:13 +01:00
Akinwale Ariwodola
456f41d28d Prevent image click through. Add Romanian strings. 2020-05-24 04:43:39 +01:00
Akinwale Ariwodola
238f59ad71 display correct label and amount for tip unlocks in tx history 2020-05-24 00:08:14 +01:00
Akinwale Ariwodola
cf6d567193 unify button font 2020-05-23 23:47:32 +01:00
Akinwale Ariwodola
20f8f3852d
Merge pull request #888 from lbryio/unlock-tips
add option to unlock all tips
2020-05-23 23:39:16 +01:00
Akinwale Ariwodola
4bb9f5cb43 add option to unlock all tips 2020-05-23 23:37:57 +01:00
Akinwale Ariwodola
540a841255 Fix pip restore and fullscreen quirks. French and Portuguese strings added. 2020-05-23 19:42:30 +01:00
Akinwale Ariwodola
3544637405 Fix reward code claiming. Remove broken French strings file. 2020-05-23 17:48:58 +01:00
Akinwale Ariwodola
651448dfa1
Merge pull request #886 from lbryio/reward-drivers
Add reward drivers. French, Indonesian, Malay and Turkish strings.
2020-05-23 17:46:16 +01:00
Akinwale Ariwodola
4bac266b8b Add reward drivers. French, Indonesian, Malay and Turkish strings. 2020-05-23 17:45:19 +01:00
Akinwale Ariwodola
f86b61741d
Merge pull request #885 from lbryio/visual-tweaks
Use thin divider in transaction history. Set font for action bar title.
2020-05-23 15:18:43 +01:00
Akinwale Ariwodola
6c60d299af Use thin divider in transaction history page. Set font for action bar title. 2020-05-23 15:17:43 +01:00
Akinwale Ariwodola
08582238c3
Merge pull request #884 from lbryio/dark-theme-fix
Fix dark theme reset error due to WebView. Apply dark theme to web views.
2020-05-23 09:41:59 +01:00
Akinwale Ariwodola
b931d0ce7d Fix dark theme reset error due to WebView. Apply dark theme to web views. 2020-05-23 09:37:58 +01:00
Akinwale Ariwodola
5e1fc9dbd8
Merge pull request #883 from lbryio/fullscreen-on-rotate
switch to fullscreen mode on rotate when viewing media
2020-05-23 09:03:00 +01:00
Akinwale Ariwodola
de4e6eee25 switch to fullscreen mode on rotate when viewing media 2020-05-23 09:01:30 +01:00
Akinwale Ariwodola
d5b4e6990f update material components version 2020-05-23 07:53:58 +01:00
Akinwale Ariwodola
26703815b2 cleanup top level directory 2020-05-23 07:51:56 +01:00
Akinwale Ariwodola
40c36df414
Native rewrite (#878)
* initial native rewrite commit
* update gitlab CI script
* add printVersionName gradle task
* fix Gitlab CI script
* Fix first time wallet sync. add Discover dialog to  Following page.
* Finish Following and All Content views. Add customize your tags view.
* Wallet sync get and set preferences, update interval.
* Editor's Choice. Reposts. Some ontent page tweaks.
* display no related content view when none loaded
* Search cache. File view updates. Floating wallet balance.
* Send tip dialog. Channel page share and follow/unfollow.
* Handle lbry:// url scheme. Properly set URL bar values. SDK 0.71.0.
* Channel follow/unfollow fixes. Display stream cost.
* Channel management and channel creation / editing
* phone number verification and rewards page
* add Invites page
* tweak player loading and playback when loading new claims
* tweak about page layout
* display text and markdown content
* purchase_uri for free content
* don't display invites history if none exist
* fix channel list adapters
* change launch mode from singleInstance to singleTask
* url history and player fixes
* Library page. URL and view history.
* bumpversion 0.15.0 --> 0.15.1
* Make file view a fragment to prevent headaches with multiple Android task recents
* Better handling of file view URLs. Some issue list fixes.
* Abandon channels and bulk delete files tasks. Some visual tweaks.
* bumpversion 0.15.1 --> 0.15.2
* fix some events
* Some visual tweaks. Wunderbar clear focus hotfix for some devices.
* sdk 0.74.0. Publish and Publishes pages.
* Fix displayed amounts. Send Firebase token with install_new.
* Some dark theme and crash fixes. Implement publish form.
* Fix minor typo for string in 'generate_address_hint'.
* Publish form and publish creation flow. UI tweaks and fixes.
* Basic native mobile publishing
* remove closeDatabase calls causing crashes
* Implement file and channel page delete actions. UI action cleanup.
* publish drivers for unresolved file page and featured search result item
* show URL suggestions and data network (DHT) settings
* Filter own claims from downloads. Fix address input.
* fix edit channel crash
* fix for possible blank / invalid video thumbnails
* adjust minimum deposit. fix channel edit mode.
* quick skip and playback speed media controls
* change play and pause icons
* Fix file size display. Tweak playback speed control.
* Add exoplayer mediasession extension. Set player auto attributes.
* Inline publish address validation error. Increase image upload request timeout.
* fix no related content display
* Claim new_android reward. Use canonical_url for share links.
* force US locale for amount / bid values sent with sdk requests
* Afrikaans and Spanish strings
* Add media player error handling policy. Use : in share links.
* don't proceed with publish if optimization is in progress.
2020-05-23 07:49:00 +01:00
Akinwale Ariwodola
6eb20d0e08 sdk 0.73.1 patch 2020-05-14 14:40:12 +01:00
Akinwale Ariwodola
cc3055f1c9 bumpversion 0.14.1 --> 0.14.2 2020-03-31 21:32:35 +01:00
Akinwale Ariwodola
25a1eac43b sdk 0.67.1 2020-03-31 21:18:19 +01:00
Akinwale Ariwodola
ff30e7f6a4 bumpversion 0.14.0 --> 0.14.1 2020-03-26 19:06:51 +01:00
Akinwale Ariwodola
3fcc01597d sdk 0.65.0 2020-03-26 19:03:47 +01:00
Akinwale Ariwodola
cbc4a662e6 bumpversion 0.13.4 --> 0.14.0 2020-03-23 09:45:21 +01:00
Akinwale Ariwodola
5aa0513324 add getNativeBooleanSetting method 2020-03-21 09:18:48 +01:00
Akinwale Ariwodola
4d1f142f9c check sdk ready 2020-03-20 11:15:41 +01:00
Akinwale Ariwodola
e9c8f9432f fix service notification not opening the app 2020-03-20 09:27:54 +01:00
Akinwale Ariwodola
56c375f344
lbry.tv hybrid mode (#869)
* lbry.tv experiment build
* add task for checking if the sdk is ready
* fix for special urls
* send onSdkStatusResponse events
* persist dht setting to file system
2020-03-20 08:30:34 +01:00
Akinwale Ariwodola
5b165a2339 remove dht debug logs 2020-03-17 23:10:10 +01:00
Akinwale Ariwodola
bfd3c711ab
0.13.4 patch (#868)
* 0.13.4 patch
* update gitlab CI
2020-03-16 18:50:17 +01:00
Akinwale Ariwodola
4627e284fa sdk 0.64.0. check dht setting on startup. 2020-03-13 17:06:05 +01:00
Akinwale Ariwodola
ea8ac783a8 bumpversion 0.13.2 --> 0.13.3 2020-03-13 08:32:09 +01:00
Akinwale Ariwodola
966dd2bf2c add log method to utility module 2020-03-13 02:03:39 +01:00
Akinwale Ariwodola
364de592fa use snake case for payload keys 2020-03-12 21:16:39 +01:00
Akinwale Ariwodola
d38241f0d1 check for contentTitle and channelUrl in payload 2020-03-11 15:55:35 +01:00
Akinwale Ariwodola
e217be6b67
Fast lite mode (native code) (#864)
* fast loading lite mode
* add react methods for lbrynet dir and platform
* send additional url parameters for cold start
* pending intent
* update gitlab CI
2020-03-11 15:21:41 +01:00
Akinwale Ariwodola
37f84f0399 versionCode for productFlavors 2020-03-03 16:48:22 +01:00
Akinwale Ariwodola
b618b9fa2b sdk 0.62.0. update secret files. 2020-03-02 18:39:35 +01:00
Akinwale Ariwodola
37b893103d readme: lbrynet-daemon -> LBRY SDK 2020-03-02 16:45:23 +01:00
Akinwale Ariwodola
e2d4852df7 include google-services.sample.json for test / debug builds 2020-03-02 16:41:10 +01:00
Akinwale Ariwodola
1e0298d73a update readme 2020-03-02 16:22:19 +01:00
Akinwale Ariwodola
64c13295d6 update release.sh for unsigned APKs 2020-03-01 21:37:57 +01:00
Akinwale Ariwodola
0261ece709 remove release signingConfig since we sign with jarsigner 2020-03-01 21:18:26 +01:00
Akinwale Ariwodola
a5799347ad
New build (#854)
* new project structure compatiable with Android Studio
2020-02-27 19:20:06 +01:00
Akinwale Ariwodola
6c7c4d1a88 app head: following page sign in message 2020-02-25 19:39:58 +01:00
Akinwale Ariwodola
f5390316a7 app head: fix suggested subscriptions state handling 2020-02-25 19:35:54 +01:00
Akinwale Ariwodola
da1ea77aa9 pass conf to get_loggly_handler 2020-02-25 08:34:50 +01:00
Akinwale Ariwodola
8ea48977ae sdk 0.61.0 2020-02-24 20:29:09 +01:00
Akinwale Ariwodola
6721db54e2 bumpversion 0.13.0 --> 0.13.1 2020-02-24 15:59:57 +01:00
Akinwale Ariwodola
6a7079c8b2 app head: basic repost redirect handling 2020-02-24 15:58:33 +01:00
Akinwale Ariwodola
8cc7e9d6c9
Following rework (#852)
* app head: following rework
* sdk 0.60.0. app head: following rework changes.
* app head: search and related content fixes
* app head: following rework updates
2020-02-24 15:21:13 +01:00
Akinwale Ariwodola
d0ac41c242 app head: timing 2020-02-17 18:34:28 +01:00
Akinwale Ariwodola
bc8f476ef1
Merge pull request #850 from lbryio/app-timing
app cold and warm start timing
2020-02-17 07:32:49 +01:00
Akinwale Ariwodola
2d01b63cfe app cold and warm start timing 2020-02-17 07:19:16 +01:00
Akinwale Ariwodola
88dc31e9af
Merge pull request #832 from michaeltintiuc/fix-npm-install
Fix npm install
2020-02-07 16:26:05 +01:00
Thomas Zarebczan
8d1e5eb64d
Merge pull request #834 from ykris45/patch-3
Update LICENSE
2020-02-03 17:04:42 -05:00
Akinwale Ariwodola
8113ef3f8a app head: fix splash screen stuck on authenticating 2020-02-03 09:21:22 +01:00
Akinwale Ariwodola
a74ed0e93b bumpversion 0.12.3 --> 0.13.0 2020-02-03 07:28:28 +01:00
Akinwale Ariwodola
11f42bf71e app head: resolved search nsfw 2020-02-03 07:27:40 +01:00
YULIUS KURNIAWAN KRISTIANTO
8eb96025ec
Update LICENSE 2020-02-03 04:38:17 +07:00
Akinwale Ariwodola
1ece7ff433 sdk 0.56.0 fixes 2020-01-31 19:43:49 +01:00
Michael Tintiuc
e312c451f8 Fix npm install 2020-01-31 19:51:32 +02:00
Akinwale Ariwodola
bb64e91648 sdk 0.56.0 2020-01-31 16:47:25 +01:00
Akinwale Ariwodola
69398f6a2c app head: search page fixes 2020-01-31 09:15:37 +01:00
Akinwale Ariwodola
bef7aa0ae9 app head: Invites page 2020-01-29 12:26:57 +01:00
Akinwale Ariwodola
2776696501 app head: fix thumbnailUrl check 2020-01-23 02:16:12 +01:00
Akinwale Ariwodola
fa075df278 app head: additional thumbnailUrl check 2020-01-23 00:56:11 +01:00
Akinwale Ariwodola
05311fd3a1 app head: fix additional channel creator edit error 2020-01-22 21:21:42 +01:00
Akinwale Ariwodola
79001239d9 app head: fix channel creator edit error 2020-01-22 18:40:19 +01:00
Akinwale Ariwodola
e344733bf0 sdk 0.54.1 2020-01-22 15:04:44 +01:00
Akinwale Ariwodola
282fdbb903 app head: download confirmation dialog 2020-01-20 23:36:35 +01:00
Akinwale Ariwodola
ee7c571101 download manager tweaks 2020-01-20 23:11:46 +01:00
Akinwale Ariwodola
87e42d6b7e app head: error on publish to existing content address 2020-01-20 21:53:57 +01:00
Akinwale Ariwodola
8fcf135280 add Stop action to download notifications 2020-01-20 21:42:25 +01:00
Akinwale Ariwodola
ae9364ad7e add filter to only get active downloads on service startup 2020-01-20 18:55:02 +01:00
Akinwale Ariwodola
6aa44d8a9e tweak sdkCall params and sdk poll interval 2020-01-17 07:24:50 +01:00
Akinwale Ariwodola
3f013d1272 bumpversion 0.12.2 --> 0.12.3 2020-01-17 06:53:51 +01:00
Akinwale Ariwodola
94d1f5a4eb fix queued download file_list response handling 2020-01-17 06:44:43 +01:00
Akinwale Ariwodola
1d8a7d838b
Merge pull request #818 from lbryio/sdk-0.53
sdk 0.53
2020-01-17 06:00:08 +01:00
Akinwale Ariwodola
c5d441fa1f sdk 0.53.3 2020-01-17 05:59:04 +01:00
Akinwale Ariwodola
4276a78a81 sdk 0.53.2 service updates 2020-01-16 22:34:36 +01:00
Akinwale Ariwodola
36c24a448f
Playable downloads (#817) 2020-01-16 22:05:22 +01:00
Akinwale Ariwodola
4bf1051549 app head: playable downloads update 2020-01-16 22:03:19 +01:00
Akinwale Ariwodola
fc4ab3128c app headd: fix error on opening related content or urls 2020-01-14 02:30:35 +01:00
Akinwale Ariwodola
65d32ea13e app head: react navigation drawer workaround 2020-01-13 12:24:32 +01:00
Akinwale Ariwodola
4cd8c80226 optimise download manager update broadcasts 2020-01-13 12:05:02 +01:00
Akinwale Ariwodola
7adcdc43cf app head: remove calls to doCheckSubscriptionsInit 2020-01-10 23:41:47 +01:00
Akinwale Ariwodola
77852dc135 app head: style fixes 2020-01-10 00:38:25 +01:00
Akinwale Ariwodola
746ca62ca7 app head: fix claim result item channel render checks 2020-01-09 20:34:52 +01:00
Akinwale Ariwodola
5e993f0fcc spinner dropdown styling 2020-01-09 20:20:22 +01:00
Akinwale Ariwodola
168dbba62c app head: fullscreen media player restore tweak 2020-01-09 19:00:25 +01:00
Akinwale Ariwodola
4db7bf814c app head: latest changes 2020-01-09 18:18:41 +01:00
Akinwale Ariwodola
21a3ff318b update font files 2020-01-09 15:44:10 +01:00
Akinwale Ariwodola
116de67d4c app head: downgrade drawer navigator 2020-01-07 11:21:30 +01:00
Akinwale Ariwodola
c6b8dfd539 app head: download and open file button fixes 2020-01-07 08:50:24 +01:00
Akinwale Ariwodola
37f33e9943 fix WebView package 2020-01-07 08:35:06 +01:00
Akinwale Ariwodola
4bae7fdf94 app head: fix tag search result 2020-01-06 23:02:06 +01:00
Akinwale Ariwodola
c455bde154 app head: performance and fixes. disable hermes engine. 2020-01-06 21:55:59 +01:00
Akinwale Ariwodola
5aa4321787 app head: merge resolved search commits 2020-01-05 19:08:52 +01:00
Akinwale Ariwodola
27a2100c72 app head: resolved search updates 2020-01-05 18:12:49 +01:00
Akinwale Ariwodola
4fc82c6527 app head: resolved search 2020-01-05 13:58:12 +01:00
Akinwale Ariwodola
56486ad274 app head: storage permission checks 2020-01-04 07:11:50 +01:00
Akinwale Ariwodola
99a38e655b bumpversion 0.12.1 --> 0.12.2 2020-01-03 19:12:14 +01:00
Akinwale Ariwodola
262050147d sdk 0.51.2 2020-01-03 18:55:47 +01:00
Akinwale Ariwodola
5ff2e608c2 app head: reactotron and search improvements 2019-12-29 11:17:13 +01:00
Akinwale Ariwodola
4e305faf5b app head: remove console.log 2019-12-29 07:24:26 +01:00
Akinwale Ariwodola
0bdbb843fb add android:exported to activity definition in manifest 2019-12-29 07:20:48 +01:00
Akinwale Ariwodola
c8736ad26e update gradle dependencies 2019-12-29 07:15:14 +01:00
Akinwale Ariwodola
57d6b72f5a
First run changes (#809)
* don't request for storage permission on first startup
* app head: download button tweaks
* fix download manager
2019-12-28 16:06:14 +01:00
Akinwale Ariwodola
d0117b14db
React Native 0.61 (#808)
* support for RN 0.61.5
* update gradle_dependencies
2019-12-28 15:42:26 +01:00
Akinwale Ariwodola
6729842ed8 app head: channel name and follower background 2019-12-20 18:55:10 +01:00
Akinwale Ariwodola
723ade8ba6 bumpversion 0.12.0 --> 0.12.1 2019-12-20 09:03:00 +01:00
Akinwale Ariwodola
83066232b6 sdk 0.50.1 2019-12-20 09:02:10 +01:00
Akinwale Ariwodola
4dc0b19c5d
Merge pull request #800 from lbryio/snackbars
snackbar support
2019-12-20 08:00:07 +01:00
Akinwale Ariwodola
a58cc820ef app head: update master 2019-12-18 16:51:07 +01:00
Akinwale Ariwodola
2b3397bc85 snackbar support 2019-12-18 11:48:29 +01:00
Akinwale Ariwodola
a519b5c0b1 app head: display balance on LBC input focus 2019-12-13 17:36:01 +01:00
Akinwale Ariwodola
fb3a34c871 disable sound on download notifications 2019-12-13 15:10:02 +01:00
Akinwale Ariwodola
a1bc3fcd7e fix notification icon 2019-12-13 14:51:44 +01:00
Akinwale Ariwodola
7daf3c6f55 add headers download to CI for 64-bit build 2019-12-11 17:06:28 +01:00
Akinwale Ariwodola
7d032179ef fix CI build 2019-12-11 16:20:45 +01:00
Akinwale Ariwodola
156507f8f7 remove headers file and dynamically download for build 2019-12-11 16:15:16 +01:00
Akinwale Ariwodola
032a1927db bumpversion 0.11.1 --> 0.12.0 2019-12-11 09:08:42 +01:00
Akinwale Ariwodola
f24bf570ef app head: fixes before release 2019-12-11 09:08:26 +01:00
Akinwale Ariwodola
75c2ece016
add headers file to package (#792)
* latest headers
2019-12-11 08:46:34 +01:00
Akinwale Ariwodola
0c1c1a6c79 sdk 0.49.0 2019-12-10 16:30:18 +01:00
Akinwale Ariwodola
5af25a9d43 app head: update 2019-12-06 17:24:34 +01:00
Akinwale Ariwodola
55fec0f578 sdk 0.48.0 2019-12-05 13:42:42 +01:00
Akinwale Ariwodola
b61fc3a148
Merge pull request #786 from lbryio/i18n
add language constant for app launch
2019-12-05 13:20:18 +01:00
Akinwale Ariwodola
e3cd0fc2b1 add language constant for app launch 2019-12-05 13:19:22 +01:00
g1tman
fe01f50c65 Perf: Use of sort and sorted functions optimized (#748)
* Update mixer.py
* Update graph.py
* Update mixer.py
* Update mixer.py
* Update bdistapk.py
* Update toolchain.py
* Update build.py
* Update build.py
2019-11-25 11:28:16 +01:00
Akinwale Ariwodola
cd378d16e3 app head: fetching cost info fix 2019-11-12 21:10:57 +01:00
Akinwale Ariwodola
e951fabf1c bumpversion 0.11.0 --> 0.11.1 2019-11-12 16:21:22 +01:00
Akinwale Ariwodola
48543a48fb
log events for received and opened notifications (#760)
* log events for received and opened notifications
* app head: update to master
2019-11-12 15:50:47 +01:00
Akinwale Ariwodola
2699893581 bumpversion 0.10.2 --> 0.11.0 2019-11-04 08:49:41 +01:00
Akinwale Ariwodola
21914a0bd7
Merge pull request #752 from lbryio/fcm-data
handle FCM data-only messages
2019-11-04 08:48:50 +01:00
Akinwale Ariwodola
d83667682d handle FCM data-only messages 2019-11-01 06:54:32 +01:00
Akinwale Ariwodola
a5dc01f589 app head: hide notification settings 2019-10-31 17:35:18 +01:00
Akinwale Ariwodola
fb497cebfe app head: fix launch urls and notification target urls 2019-10-31 07:55:36 +01:00
Akinwale Ariwodola
9ffaba4358 app head: normalise tag name from search result 2019-10-30 13:05:44 +01:00
Akinwale Ariwodola
be85307fe8 sdk 0.43.4 2019-10-30 11:24:04 +01:00
Akinwale Ariwodola
b55961bd83 bumpversion 0.10.1 --> 0.10.2 2019-10-30 11:21:26 +01:00
Akinwale Ariwodola
f4911394ba app head: master 2019-10-30 10:36:10 +01:00
Akinwale Ariwodola
42cf11358e
handle remote notification payloads (#737)
* handle remote notification payloads
* handle intent extras for background notifications
2019-10-30 10:34:57 +01:00
Akinwale Ariwodola
6e6ed07890 app head: rc 2019-10-30 10:33:09 +01:00
Thomas Zarebczan
22327bf33e
Merge pull request #723 from mohatagarvit/master
Update google-services.json path in BUILD.md #722
2019-10-28 10:31:15 -04:00
Thomas Zarebczan
57d8bc3311
Merge pull request #721 from sidhyatikku/patch-1
Initialised a GitHub PR Template
2019-10-28 10:30:17 -04:00
Thomas Zarebczan
6589799a2a
Update PULL_REQUEST_TEMPLATE.md 2019-10-28 10:29:43 -04:00
Thomas Zarebczan
7d6370163b
Merge pull request #734 from Janith96/patch-1
Update QUICKSTART.md
2019-10-28 10:28:17 -04:00
Thomas Zarebczan
9a5d63b7fc
Update QUICKSTART.md 2019-10-28 10:27:48 -04:00
Thomas Zarebczan
2d872a57ee
Merge pull request #715 from StrikerRUS/patch-1
Delete .travis.yml
2019-10-28 10:25:53 -04:00
Thomas Zarebczan
f9c0850acd
Merge pull request #724 from EricBrianAnil/patch-1
Updated screenshots
2019-10-23 17:38:42 -04:00
Janith Udayanga
994ec732a4
Update QUICKSTART.md
Corrected Typos, Added Links to the mentioned Repos, Made Topics more clear & more readable.
2019-10-23 10:48:48 +05:30
Akinwale Ariwodola
b44770c77f
Navigation drawer fix (#729)
* app head: downgrade react-navigation-drawer package
* app head: adjust drawer width
2019-10-21 18:42:12 +01:00
Akinwale Ariwodola
7ea836e249 app head: fix blank password wallet state 2019-10-21 15:56:22 +01:00
Eric Brian Anil
16d2401e38
Added gif as requested
Updated the old image with the gif from https://lbry.com/android as requested
2019-10-21 11:00:33 +05:30
Akinwale Ariwodola
259dc4c7cc bumpversion 0.10.0 --> 0.10.1 2019-10-20 19:33:58 +01:00
Akinwale Ariwodola
3bcd67b8fb sdk 0.43.3 2019-10-20 19:33:22 +01:00
Eric Brian Anil
648d9103b7
Updated screenshots
Updated the file with the screenshots of the most recent version of the app. The  existing screenshot had been of a previous version .
2019-10-20 23:02:27 +05:30
Garvit Mohata
faac434d33
Update google-services.json path in BUILD.md #722
Updates the google-services.json path as per the current directory structure
2019-10-20 16:28:06 +05:30
Sidhya Tikku
f558cc49f7
Create PULL_REQUEST_TEMPLATE.md 2019-10-20 00:27:38 +05:30
Akinwale Ariwodola
5add227e55 sdk 0.43.2 2019-10-17 20:27:55 +01:00
Akinwale Ariwodola
4519a5d174 app head: fix for devices without Firebase support 2019-10-17 19:55:55 +01:00
Akinwale Ariwodola
095bed4482 app head: proceed from splash if Firebase doesn't work 2019-10-17 19:12:49 +01:00
Akinwale Ariwodola
07dc95b639 app head: remove getSync wait before navigation to main 2019-10-17 18:20:38 +01:00
Akinwale Ariwodola
edc3ebcff1 bumpversion 0.9.3 --> 0.10.0 2019-10-17 16:04:56 +01:00
Akinwale Ariwodola
0f7055ca5b Revert "bumpversion 0.9.3 --> 0.9.4"
This reverts commit f426321e15.
2019-10-17 16:03:39 +01:00
Akinwale Ariwodola
f426321e15 bumpversion 0.9.3 --> 0.9.4 2019-10-17 14:57:49 +01:00
Akinwale Ariwodola
70d5cb3e2b
RC 0.9.4 (#712)
* sdk 0.43.1
2019-10-17 14:55:44 +01:00
Nikita Titov
15e4dca984
Delete .travis.yml 2019-10-16 02:10:12 +03:00
Thomas Zarebczan
3a7221d71b
Merge pull request #705 from sumitkharche/master
Added license badge
2019-10-15 12:18:57 -04:00
Thomas Zarebczan
e8cb3afb34
Update README.md 2019-10-15 12:18:40 -04:00
Thomas Zarebczan
2b7a580001
Merge pull request #708 from akshitsarin/patch-1
Fixed a typo in QUICKSTART.md
2019-10-13 17:58:47 -04:00
Akshit Sarin
b5d327581b
Fixed a typo in QUICKSTART.md
Signed-off-by: Akshit Sarin <akshitsarin99@gmail.com>

'*toolcahin* to toolchain'
2019-10-14 03:11:31 +05:30
Sumit Kharche
c0ca45e949
Added license and build badges 2019-10-13 00:41:09 +05:30
Akinwale Ariwodola
4acc107d3a
Share (#704)
* use native share interface for sharing LBRY URLs
2019-10-11 17:22:39 +01:00
Akinwale Ariwodola
1070dba0ae
sdk 0.42.1 (#703)
* sdk 0.42.1
2019-10-11 17:15:26 +01:00
Akinwale Ariwodola
7ae5d48767
add Firebase Cloud Messaging support (#702)
* add Firebase Cloud Messaging support
* add default notification channel for FCM
2019-10-11 14:18:45 +01:00
Akinwale Ariwodola
e5c05fac48
Merge pull request #700 from StrikerRUS/license
bump year in license
2019-10-11 13:58:37 +01:00
StrikerRUS
f7c4b94546 bump year in license 2019-10-09 00:00:31 +03:00
Akinwale Ariwodola
a58af97216 bumpversion 0.9.2 --> 0.9.3 2019-10-04 16:19:37 +01:00
Akinwale Ariwodola
3759a9703a app head: suggested subs and improvements 2019-10-03 16:50:02 +01:00
Akinwale Ariwodola
2d3ed191fd app head: fix channel creator edit mode 2019-09-27 00:50:12 +01:00
Akinwale Ariwodola
425817b896 bumpversion 0.9.1 --> 0.9.2 2019-09-27 00:04:23 +01:00
Akinwale Ariwodola
aaf3be2f7b app head: code cleanup 2019-09-27 00:02:59 +01:00
Akinwale Ariwodola
bc810c80d6 app head: fix publishing 2019-09-27 00:00:35 +01:00
Akinwale Ariwodola
e7a6f6f921 app head: fix typo 2019-09-26 09:54:42 +01:00
Akinwale Ariwodola
26542abc4d app head: channel creator fixes. fix wallet sync disable / re-enable errors. 2019-09-26 07:26:22 +01:00
Akinwale Ariwodola
46fd7f40d4 bumpversion 0.9.0 --> 0.9.1 2019-09-26 00:13:45 +01:00
Akinwale Ariwodola
40eaa80f4b app head: fix channel creator canSave flag 2019-09-25 23:35:24 +01:00
Akinwale Ariwodola
ea8f93061d app head: post-0.9.0 fixes 2019-09-25 23:22:12 +01:00
Akinwale Ariwodola
2ec2593704 app head: fix channel creator text input errors 2019-09-25 19:24:04 +01:00
Akinwale Ariwodola
c4949c7794 app head: back navigation tweak 2019-09-25 17:57:24 +01:00
Akinwale Ariwodola
7572a0da5a app head: blank passwords 2019-09-25 16:37:54 +01:00
Akinwale Ariwodola
678b9c3184 app head: fix back navigation and channel name validation 2019-09-25 14:45:19 +01:00
Akinwale Ariwodola
2900b18cce bumpversion 0.8.4 --> 0.9.0 2019-09-24 19:03:43 +01:00
Akinwale Ariwodola
580e78afab app head: show delete button for owned claims 2019-09-24 18:59:34 +01:00
Akinwale Ariwodola
ace430abe6
0.9.0 rc (#679)
* app head: sync user settings
* app head: fix errors and user shared state
* sdk 0.40.1
* app head: empty state views. fix publishing state.
2019-09-24 17:31:00 +01:00
Akinwale Ariwodola
54c6089bdc app head: better handling of pending form states 2019-09-15 12:47:38 +01:00
Akinwale Ariwodola
8b308abfb8
Merge pull request #676 from lbryio/publish-channel-selector
app head: fix channel selector issues on publish page
2019-09-15 12:06:23 +01:00
Akinwale Ariwodola
53696970a7 app head: fix channel selector issues on publish page 2019-09-13 08:50:45 +01:00
Akinwale Ariwodola
18e2d8ad5e app head: channel creator updates 2019-09-13 08:17:17 +01:00
Akinwale Ariwodola
46cf9ad4ad bumpversion 0.8.3 --> 0.8.4 2019-09-06 19:44:54 +01:00
Akinwale Ariwodola
a11f560183 app head: 0.8.4 rc 2019-09-06 19:43:58 +01:00
Akinwale Ariwodola
23fbde6df4 app head: pin lbryinc commit 2019-09-06 16:24:34 +01:00
Akinwale Ariwodola
512e4988d2 app head: unlock after set default account 2019-09-06 16:13:39 +01:00
Akinwale Ariwodola
eb41a5e529 app head: fix featured search item 2019-09-06 15:03:34 +01:00
Akinwale Ariwodola
cefc126ffe app head: account unlock after sync apply 2019-09-06 14:52:27 +01:00
Akinwale Ariwodola
29286efbd4 sdk 0.40.0. fix merge conflicts. 2019-09-05 16:48:18 +01:00
Akinwale Ariwodola
ea30ad5974
Channel creator (#663)
* app head: channel creator page
* remove react-native-document-picker
* app head: support optional parameters
* app head: channel creator updates. upload image assets.
2019-09-05 15:59:51 +01:00
Akinwale Ariwodola
5f30cca79b app head: channel creator page 2019-08-30 18:31:49 +01:00
Akinwale Ariwodola
d76cf4457e app head: cleanup 2019-08-27 07:10:34 +01:00
Akinwale Ariwodola
88d58f4344 app head: fix all content filter selectors 2019-08-27 06:52:16 +01:00
Akinwale Ariwodola
93819b3afd app head: fix: pin react-native-gesture-handler version 2019-08-26 21:18:37 +01:00
Akinwale Ariwodola
7b438db34f app head: fix not_tags and npm packages 2019-08-26 21:02:09 +01:00
Akinwale Ariwodola
f526d797f8 app head: fix buildURI calls 2019-08-26 20:46:29 +01:00
Akinwale Ariwodola
05f7b07449 bumpversion 0.8.2 --> 0.8.3 2019-08-26 09:41:34 +01:00
Akinwale Ariwodola
ddf7c66933 app head: master 2019-08-26 09:00:44 +01:00
Akinwale Ariwodola
715a52b291
app head: edit published content (#653) 2019-08-26 08:58:10 +01:00
Akinwale Ariwodola
660adb4a6f setCurrentScreen tweaks 2019-08-25 16:36:25 +01:00
Akinwale Ariwodola
e47a1e0bf2 add screen class override for setCurrentScreen 2019-08-23 14:39:08 +01:00
Akinwale Ariwodola
7b2044d2a4 sdk 0.39.0. app head: publish / featured search tweaks 2019-08-21 16:52:28 +01:00
Akinwale Ariwodola
1d3c961c3c app head: tweak video loading indicator 2019-08-21 07:06:09 +01:00
Akinwale Ariwodola
dc59a1270f sdk 0.39.2 2019-08-21 05:18:56 +01:00
Akinwale Ariwodola
7452efa047 app head: tweak publish page grid 2019-08-21 05:15:24 +01:00
Akinwale Ariwodola
8517f74c6d fix githubrelease command 2019-08-20 19:57:47 +01:00
Akinwale Ariwodola
637a62ea21 app head: fix your tags and wallet route navigation 2019-08-20 18:49:55 +01:00
Akinwale Ariwodola
16f270fb9f bumpversion 0.8.1 --> 0.8.2 2019-08-20 17:54:40 +01:00
Akinwale Ariwodola
c4f016c912
0.8.2 rc with sdk 0.39.0 update (#640)
* sdk 0.39.0
* update aioupnp commit hash
* add defusedxml dependency for aioupnp
2019-08-20 17:54:02 +01:00
Akinwale Ariwodola
e63bc44055 tweak fresco gradle dependencies. fail build if the bundle doesn't build. 2019-08-17 02:23:17 +01:00
Akinwale Ariwodola
99c8e14773
Merge pull request #637 from lbryio/gallery-thumbnails
app head: gallery thumbnails and publish style tweaks
2019-08-15 19:06:40 +01:00
Akinwale Ariwodola
d84fb51f6f app head: gallery thumbnails and publish style tweaks 2019-08-15 06:08:53 +01:00
Akinwale Ariwodola
a8309ffaf5 add ReactMethod to call firebase setCurrentScreen 2019-08-14 16:15:20 +01:00
Akinwale Ariwodola
fd97ba3ae9
Drawer menu stutter (#633)
* app head: fix drawer menu stuttering and getting stuck
* fix release script
* fix 32-bit gradle template
2019-08-13 12:32:38 +01:00
Akinwale Ariwodola
305e62746c different version codes for 32- and 64-bit 2019-08-12 16:43:51 +01:00
Akinwale Ariwodola
bf57de9d96 only include arm64-v8a for arm64 2019-08-12 15:11:53 +01:00
Akinwale Ariwodola
07e52d2a83 remove arm64-v8a folder from 32-bit builds 2019-08-12 15:07:09 +01:00
Akinwale Ariwodola
36a0450c1d fix last step in release apk stage 2019-08-12 14:33:19 +01:00
Akinwale Ariwodola
f49e8134dd app head: fix remaining publish bugs 2019-08-12 13:23:11 +01:00
Akinwale Ariwodola
a54037270b app head: fix navigate back to trending and claim_search end detection 2019-08-11 18:38:16 +01:00
Akinwale Ariwodola
4a6b091496 app head: yet more fixes. 2019-08-11 17:16:17 +01:00
Akinwale Ariwodola
03addf41c7 app head: misc fixes 2019-08-11 08:53:26 +01:00
Akinwale Ariwodola
9440855bf2 app head: fix publishing bugs 2019-08-11 00:08:06 +01:00
Akinwale Ariwodola
d53b1b94e5
Merge pull request #629 from lbryio/multi-arch-builds
build 32-bit and 64-bit APKs
2019-08-10 19:06:30 +01:00
Akinwale Ariwodola
16ebf7bb11 build 32-bit and 64-bit APKs 2019-08-10 12:25:57 +01:00
Akinwale Ariwodola
c8e7194a94 app head: display remaining discover tags and fix publish cancel bug 2019-08-10 10:14:44 +01:00
Akinwale Ariwodola
c6527fc57a app head: don't show anonymous while resolving file item 2019-08-10 08:13:23 +01:00
Akinwale Ariwodola
bf906479d8 app head: Daemon (lbrynet) --> LBRY SDK 2019-08-10 08:02:14 +01:00
Akinwale Ariwodola
938512f826 bumpversion 0.8.0 --> 0.8.1 2019-08-10 07:58:00 +01:00
Akinwale Ariwodola
bbc068b889
0.8.1 rc (#628)
* app head: fix first set of release blockers
* sdk 0.38.6
* app head: pin lbryinc version
* app head: fix error on tag page
* app head: update pinned lbry-redux version
* app head: fix tag page back navigation and routes
* app head: fix nsfw functionality. add GA events.
* app head: fix release blockers
2019-08-10 07:57:06 +01:00
Akinwale Ariwodola
0ae9fd44d2 app head: react navigation tweaks 2019-08-09 07:55:43 +01:00
Akinwale Ariwodola
d266b9f55b
Performance (#626) 2019-08-09 07:42:21 +01:00
Akinwale Ariwodola
57691fcd99 app head: hide blacklisted and filtered outpoints from lists 2019-07-31 12:18:52 +01:00
Akinwale Ariwodola
8cd41aae27 app head: pin new lbry-redux commit 2019-07-30 19:46:30 +01:00
Akinwale Ariwodola
8ac3efeedc Merge branch 'master' of https://github.com/lbryio/lbry-android 2019-07-30 19:37:19 +01:00
Akinwale Ariwodola
642c80779a app head: fixes and style tweaks 2019-07-30 19:36:28 +01:00
Alex Grin
17d43fcb7e
Update .gitlab-ci.yml 2019-07-30 12:00:37 -04:00
Akinwale Ariwodola
6bc67dd303 bumpversion 0.7.5 --> 0.8.0 2019-07-30 15:44:41 +01:00
Akinwale Ariwodola
2926225133 app head: use master branch 2019-07-30 15:43:27 +01:00
Akinwale Ariwodola
8fe078cc29
Merge pull request #620 from lbryio/release-0.8.0
app head: updates for next release
2019-07-30 15:42:52 +01:00
Akinwale Ariwodola
b721a52584 app head: updates for next release 2019-07-30 15:39:22 +01:00
Akinwale Ariwodola
e7eeb0bacd sdk 0.38.5. app head: final discovery fixes. (#618) 2019-07-29 23:48:45 +01:00
Akinwale Ariwodola
710abb1206
Merge pull request #617 from lbryio/publishes-page
app head: add publishes page
2019-07-29 23:44:14 +01:00
Akinwale Ariwodola
82c3efba07 app head: add publishes page 2019-07-26 17:13:02 +01:00
Akinwale Ariwodola
12a3b50e35 app head: fast-forward master 2019-07-26 15:36:25 +01:00
Akinwale Ariwodola
48884bc2de app head: pull master 2019-07-26 09:15:24 +01:00
Akinwale Ariwodola
d02689fc67
Discovery (#610)
* discovery changes
* app head: tag page and content sorting
* app head: fix styles and tag page load
* app head: update subscriptions view using claim_search results
* app head: add horizontal subscribed channels list
* app head: add tag customisation to explore and trending pages
* update to sdk 0.38.3. app head: subscriptions and suggested channels
2019-07-26 09:14:25 +01:00
Akinwale Ariwodola
9751b18c54
Merge pull request #608 from EnigmaCurry/docker-build2
DOCKER-DEV: Add arm64 glibc headers from #606 and other refactors
2019-07-17 18:55:08 +01:00
Ryan McGuire
f6a4ca42b1 DOCKER-DEV: Add arm64 glibc headers from #606 2019-07-15 17:36:31 -04:00
Akinwale Ariwodola
0f2d6bfa9b fix buildozer.spec.ci 2019-07-13 04:36:33 +01:00
Akinwale Ariwodola
84a7b930a8 gitlab CI force submodule update 2019-07-13 04:09:56 +01:00
Akinwale Ariwodola
7549ecbf45 update app HEAD 2019-07-13 01:27:57 +01:00
Akinwale Ariwodola
99f6150bdc
Merge pull request #607 from lbryio/rn-0.59.10
upgrade to React Native 0.59.10
2019-07-13 01:26:08 +01:00
Akinwale Ariwodola
dab8aec81c upgrade to React Native 0.59.10 2019-07-12 15:54:33 +01:00
Ryan McGuire
b0ddacbe89 DOCKER-DEV: Local development in a docker container (#595)
* DOCKER-DEV: Local lbry-android development via docker.
* DOCKER-DEV: Add git submodule init
2019-07-11 02:30:41 +01:00
Akinwale Ariwodola
530923640c
arm64 (#606)
* 64-bit support
* update gitlab CI build
* update android.arch in buildozer.spec
2019-07-10 21:34:52 +01:00
Akinwale Ariwodola
c977d2ed86
React Native codebase as a submodule (#604) 2019-07-09 05:34:46 +01:00
Akinwale Ariwodola
8459d10dc7
Publishing (#577)
* create gallery module for retrieving media from device
* gallery and ui flow for publishing
* publishing. add channel selector component.
* enable record and take photo buttons
* create thumbnails for camera media
* upload thumbnails. check publish success status.
* update to sdk 0.38.0. add tags / tag selection to publish.
2019-07-09 01:43:30 +01:00
Akinwale Ariwodola
60836ec5ec
Update wallet sync status display (#597)
* update wallet sync status display
* add disable wallet sync confirmation
* add wallet sync title
* use python 3.7 venv
2019-07-09 01:39:10 +01:00
Akinwale Ariwodola
20cd4affee
Merge pull request #598 from lbryio/blank-password-warning
add warning for proceeding with a blank password
2019-07-09 01:38:43 +01:00
Akinwale Ariwodola
120c3ca52f add warning for proceeding with a blank password 2019-07-08 04:22:02 +01:00
Akinwale Ariwodola
455dadd30d use python 3.7 venv 2019-07-07 16:59:15 +01:00
Akinwale Ariwodola
01534caf13
handle account unlock failure (#594)
* display information to the user upon account_unlock failure
* remove trailing dots in messages
2019-07-07 15:26:20 +01:00
Akinwale Ariwodola
4186081fdc
Merge pull request #596 from lbryio/sdk-0.38
upgrade to sdk 0.38.0
2019-07-07 15:25:43 +01:00
Akinwale Ariwodola
88a7a9b6b1 upgrade to sdk 0.38.0 2019-07-07 15:19:21 +01:00
Jeremy Kauffman
b4267d8d8b
Merge pull request #581 from lbryio/build-doc-update
updated Android build instructions
2019-06-25 10:09:12 -04:00
Akinwale Ariwodola
fdac63a299 increase status call timeout to 1000ms 2019-06-21 17:14:32 +01:00
Akinwale Ariwodola
0a210b6e09 bumpversion 0.7.4 --> 0.7.5 2019-06-21 10:20:44 +01:00
Akinwale Ariwodola
945308dfbc formatting 2019-06-21 10:19:25 +01:00
Akinwale Ariwodola
aa285f90ae
Merge pull request #588 from lbryio/wallet-send-paste
add paste button beside wallet address input
2019-06-21 10:17:59 +01:00
Akinwale Ariwodola
64bf12718a
Merge pull request #587 from lbryio/first-run-analytics
additional events to track first run flow
2019-06-21 10:17:49 +01:00
Akinwale Ariwodola
dd9677ea3b add paste button beside wallet address input 2019-06-21 09:46:27 +01:00
Akinwale Ariwodola
ea60df592f additional events to track first run flow 2019-06-21 08:21:14 +01:00
Akinwale Ariwodola
c140aa32b6 updated Android build instructions 2019-06-17 17:13:52 +01:00
netop:// ウェッブ
9d6cf369d6 Added updated Docker instructions (#574) 2019-06-17 16:03:02 +01:00
Akinwale Ariwodola
41c124e042 bumpversion 0.7.3 --> 0.7.4 2019-06-14 08:44:11 +01:00
Akinwale Ariwodola
eca962ad68
sdk 0.37.4 update (#579)
* sdk 0.37.4 update
* pin lbry-redux commit hash
* hide save file button
2019-06-14 08:42:46 +01:00
Akinwale Ariwodola
89c653e613
Merge pull request #578 from lbryio/prettier
add prettier and eslint
2019-06-12 16:39:35 +01:00
Akinwale Ariwodola
964ed2d129 add prettier and eslint 2019-06-12 08:56:08 +01:00
Akinwale Ariwodola
6a1287d1b0
Merge pull request #576 from lbryio/first-run-restart
do not proceed past Setup account without an email address
2019-06-08 22:18:12 +01:00
Akinwale Ariwodola
d3f4abc50e
allow blank passwords (#575) 2019-06-08 22:17:27 +01:00
Akinwale Ariwodola
20da1b6461 do not proceed past Setup account without an email address 2019-06-07 06:21:09 +01:00
Akinwale Ariwodola
044947d4ae
Save audio/video files (#564)
* add save file button for audio/video
* set state for downloads initiated using the save file button
* allow actions to be shown if there's a download_path in fileInfo
* do not auto play downloaded media
2019-06-05 15:53:11 +01:00
Akinwale Ariwodola
a2c0851ac7 bumpversion 0.7.2 --> 0.7.3 2019-06-04 05:57:36 +01:00
Akinwale Ariwodola
7e136faea5
perform user authentication on first page of first run (#572)
* perform user authentication on first page of first run
* additional firebase events for first run
2019-06-04 05:56:45 +01:00
2040 changed files with 63024 additions and 213093 deletions

32
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View file

@ -0,0 +1,32 @@
## PR Checklist
<!-- For the checkbox formatting to work properly, make sure there are no spaces on either side of the "x" -->
Please check all that apply to this PR using "x":
- [ ] I have checked that this PR is not a duplicate of an existing PR (open, closed or merged)
- [ ] I have checked that this PR does not introduce a breaking change
- [ ] This PR introduces breaking changes and I have provided a detailed explanation below
## PR Type
What kind of change does this PR introduce?
- [ ] Bugfix
- [ ] Feature
- [ ] Code style update (formatting)
- [ ] Refactoring (no functional changes)
- [ ] Documentation changes
- [ ] Other - Please describe:
## Fixes
Issue Number:
## What is the current behavior?
## What is the new behavior?
## Other information
<!-- If this PR contains a breaking change, please describe the impact and solution strategy for existing applications below. -->

1
.github/workflows/deploy.yml vendored Normal file
View file

@ -0,0 +1 @@

80
.gitignore vendored
View file

@ -1,15 +1,69 @@
.buildozer
app/node_modules/
bin
buildozer.spec
build.log
recipes/**/*.pyc
src/main/assets/index.android.bundle
src/main/assets/index.android.bundle.meta
# OSX
#
.DS_Store
# Xcode
#
build/
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata
*.xccheckout
*.moved-aside
DerivedData
*.hmap
*.ipa
*.xcuserstate
# Android/IntelliJ
#
build/
.idea
.gradle
local.properties
*.iml
# node.js
#
node_modules/
npm-debug.log
yarn-error.log
# BUCK
buck-out/
\.buckd/
*.keystore
!debug.keystore
# fastlane
#
# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
# screenshots whenever they are needed.
# For more information about the recommended setup visit:
# https://docs.fastlane.tools/best-practices/source-control/
*/fastlane/report.xml
*/fastlane/Preview.html
*/fastlane/screenshots
# Bundle artifact
*.jsbundle
# CocoaPods
/ios/Pods/
# Other Files
app/google-services.json
app/twitter.properties
*.log
.vagrant
lbry-android.keystore
p4a/pythonforandroid/bootstraps/lbry/build/templates/google-services.json
.gitsecret/keys/random_seed
*.hprof
app/build
bin
app/debuglib

View file

@ -3,56 +3,73 @@ stages:
- deploy
- release
build apk:
stage: build
image: lbry/android-base:latest
image: lbry/android-base:platform-28
before_script:
- export BUILD_VERSION=$(cat $CI_PROJECT_DIR/src/main/python/main.py | grep --color=never -oP '([0-9]+\.?)+')
- echo "$PGP_PRIVATE_KEY" | gpg --batch --import
- echo 'deb https://gitsecret.jfrog.io/artifactory/git-secret-deb git-secret main' >> /etc/apt/sources.list
- wget -qO - 'https://gitsecret.jfrog.io/artifactory/api/gpg/key/public' | apt-key add -
- apt-get -y update && apt-get -y install build-essential ca-certificates curl git gpg-agent openjdk-8-jdk software-properties-common wget zipalign git-secret
- git secret reveal
- chmod u+x $CI_PROJECT_DIR/gradlew
- export BUILD_VERSION=$($CI_PROJECT_DIR/gradlew -p $CI_PROJECT_DIR -q printVersionName --console=plain | tail -1)
artifacts:
paths:
- bin/browser-*-release.apk
- bin/browser-*-release__arm.apk
- bin/browser-*-release__arm64.apk
expire_in: 1 week
script:
- export PATH=/usr/bin:$PATH
- echo "$PGP_PRIVATE_KEY" | gpg --batch --import
- cd app
- npm install
- cd ..
- wget -q 'https://eu.crystax.net/download/crystax-ndk-10.3.2-linux-x86_64.tar.xz' -P ~/.buildozer/android/
- tar -xf ~/.buildozer/android/crystax-ndk-10.3.2-linux-x86_64.tar.xz -C ~/.buildozer/android/
- rm -rf ~/.buildozer/android/crystax-ndk-10.3.2/platforms/android-9
- ln -s ~/.buildozer/android/crystax-ndk-10.3.2/platforms/android-21 ~/.buildozer/android/crystax-ndk-10.3.2/platforms/android-9
- cp -f $CI_PROJECT_DIR/scripts/build-target-python.sh ~/.buildozer/android/crystax-ndk-10.3.2/build/tools/build-target-python.sh
- cp -f $CI_PROJECT_DIR/scripts/mangled-glibc-syscalls.h ~/.buildozer/android/crystax-ndk-10.3.2/platforms/android-21/arch-arm/usr/include/crystax/bionic/libc/include/sys/mangled-glibc-syscalls.h
- rm ~/.buildozer/android/crystax-ndk-10.3.2-linux-x86_64.tar.xz
- git secret reveal
- mv buildozer.spec.travis buildozer.spec
- "./release.sh | grep -Fv -e 'working:' -e 'copy' -e 'Compiling' --line-buffered"
- cp $CI_PROJECT_DIR/bin/browser-$BUILD_VERSION-release.apk /dev/null
- export ANDROID_SDK_ROOT=~/.buildozer/android/platform/android-sdk-23
- chmod u+x ./release.sh
- ./release.sh
- cp bin/browser-$BUILD_VERSION-release__arm.apk /dev/null
- cp bin/browser-$BUILD_VERSION-release__arm64.apk /dev/null
deploy build.lbry.io:
image: python:latest
image: python:stretch
stage: deploy
dependencies:
- build apk
before_script:
- apt-get -y update && apt-get -y install apt-transport-https
- echo "$PGP_PRIVATE_KEY" | gpg --batch --import
- echo 'deb https://gitsecret.jfrog.io/artifactory/git-secret-deb git-secret main' >> /etc/apt/sources.list
- wget -qO - 'https://gitsecret.jfrog.io/artifactory/api/gpg/key/public' | apt-key add -
- apt-get -y update && apt-get -y install openjdk-8-jdk git git-secret
- pip install awscli
- export BUILD_VERSION=$(cat $CI_PROJECT_DIR/src/main/python/main.py | grep --color=never -oP '([0-9]+\.?)+')
- export BUILD_APK_FILENAME=browser-$BUILD_VERSION-release.apk
- chmod u+x $CI_PROJECT_DIR/gradlew
- git secret reveal
- export BUILD_VERSION=$($CI_PROJECT_DIR/gradlew -p $CI_PROJECT_DIR -q printVersionName --console=plain | tail -1)
- export BUILD_APK_FILENAME__32=browser-$BUILD_VERSION-release__arm.apk
- export BUILD_APK_FILENAME__64=browser-$BUILD_VERSION-release__arm64.apk
script:
- aws s3 cp bin/$BUILD_APK_FILENAME s3://build.lbry.io/android/build-${CI_PIPELINE_IID}_commit-${CI_COMMIT_SHA:0:7}/$BUILD_APK_FILENAME
- aws s3 cp bin/$BUILD_APK_FILENAME s3://build.lbry.io/android/push.apk
- aws s3 cp bin/$BUILD_APK_FILENAME__64 s3://build.lbry.io/android/build-${CI_PIPELINE_IID}_commit-${CI_COMMIT_SHA:0:7}/$BUILD_APK_FILENAME__64
- aws s3 cp bin/$BUILD_APK_FILENAME__32 s3://build.lbry.io/android/build-${CI_PIPELINE_IID}_commit-${CI_COMMIT_SHA:0:7}/$BUILD_APK_FILENAME__32
- aws s3 cp bin/$BUILD_APK_FILENAME__64 s3://build.lbry.io/android/push.apk
release apk:
image: python:latest
image: python:stretch
stage: release
only:
- tags
dependencies:
- build apk
before_script:
- apt-get -y update && apt-get -y install apt-transport-https
- echo "$PGP_PRIVATE_KEY" | gpg --batch --import
- echo 'deb https://gitsecret.jfrog.io/artifactory/git-secret-deb git-secret main' >> /etc/apt/sources.list
- wget -qO - 'https://gitsecret.jfrog.io/artifactory/api/gpg/key/public' | apt-key add -
- apt-get -y update && apt-get -y install openjdk-8-jdk git git-secret
- pip install awscli githubrelease
- export BUILD_VERSION=$(cat $CI_PROJECT_DIR/src/main/python/main.py | grep --color=never -oP '([0-9]+\.?)+')
- export BUILD_APK_FILENAME=browser-$BUILD_VERSION-release.apk
- git secret reveal
- chmod u+x $CI_PROJECT_DIR/gradlew
- export BUILD_VERSION=$($CI_PROJECT_DIR/gradlew -p $CI_PROJECT_DIR -q printVersionName --console=plain | tail -1)
- export BUILD_APK_FILENAME__32=browser-$BUILD_VERSION-release__arm.apk
- export BUILD_APK_FILENAME__64=browser-$BUILD_VERSION-release__arm64.apk
script:
- githubrelease release lbryio/lbry-android create $CI_COMMIT_TAG --publish bin/$BUILD_APK_FILENAME
- aws s3 cp bin/$BUILD_APK_FILENAME s3://build.lbry.io/android/latest.apk
- githubrelease release lbryio/lbry-android create $CI_COMMIT_TAG --publish bin/$BUILD_APK_FILENAME__64 bin/$BUILD_APK_FILENAME__32
- githubrelease release lbryio/lbry-android edit $CI_COMMIT_TAG --draft
- aws s3 cp bin/$BUILD_APK_FILENAME__64 s3://build.lbry.io/android/latest.apk

1
.gitmodules vendored Normal file
View file

@ -0,0 +1 @@

Binary file not shown.

Binary file not shown.

BIN
.gitsecret/keys/random_seed Normal file

Binary file not shown.

View file

@ -1,2 +1,3 @@
lbry-android.keystore:
p4a/pythonforandroid/bootstraps/lbry/build/templates/google-services.json
lbry-android.keystore:0d958c531870694624cc877ea98ca1c583485f8ebbb3a5acca58b1930c190d65
app/google-services.json:896a0bee8294a36d061f10fa926129d8a780528b34d0a2f03113400c4246d67c
app/twitter.properties:01212d70712f2041efb5c814bf30ecbf6f72e1ca5179c7647c4f8cbd995dd033

View file

@ -1,95 +0,0 @@
sudo: required
dist: xenial
language: python
python:
- '3.7'
install:
- deactivate
- export PATH=/usr/bin:$PATH
- export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64
- sudo dpkg --add-architecture i386
- sudo add-apt-repository ppa:deadsnakes/ppa -y
- sudo apt-get -qq update
- sudo apt-get -qq install build-essential python3.7 python3.7-dev python3.7-venv python3-pip ccache git libncurses5:i386 libstdc++6:i386 libgtk2.0-0:i386 libpangox-1.0-0:i386 libpangoxft-1.0-0:i386 libidn11:i386 python2.7 python2.7-dev openjdk-8-jdk unzip zlib1g-dev zlib1g:i386 m4 libc6-dev-i386
- sudo pip install --upgrade cython==0.28.1 pip setuptools
- wget -q https://nodejs.org/dist/v8.11.1/node-v8.11.1-linux-x64.tar.xz
- tar -xf node-v8.11.1-linux-x64.tar.xz
- sudo ln -s $TRAVIS_BUILD_DIR/node-v8.11.1-linux-x64/bin/node /usr/bin/node
- sudo ln -s $TRAVIS_BUILD_DIR/node-v8.11.1-linux-x64/bin/npm /usr/bin/npm
- git clone https://github.com/lbryio/buildozer.git
- cd app
- npm config set registry="http://registry.npmjs.org/"
- npm install
- sudo npm install -g react-native-cli
- sudo ln -s $TRAVIS_BUILD_DIR/node-v8.11.1-linux-x64/bin/react-native /usr/bin/react-native
- cd ..
- cd buildozer
- sudo python setup.py install
- cd ..
- mv buildozer.spec.travis buildozer.spec
- mkdir -p cd ~/.buildozer/android/platform/
- wget -q 'https://dist.testnet.lbry.tech/crystax-ndk-10.3.2-linux-x86_64.tar.xz' -P ~/.buildozer/android/
- wget -q 'https://dl.google.com/android/android-sdk_r23-linux.tgz' -P ~/.buildozer/android/platform/
- wget -q 'https://dl.google.com/android/repository/platform-27_r01.zip' -P ~/.buildozer/android/platform/
- wget -q 'https://dl.google.com/android/repository/build-tools_r26.0.2-linux.zip' -P ~/.buildozer/android/platform/
- tar -xf ~/.buildozer/android/crystax-ndk-10.3.2-linux-x86_64.tar.xz -C ~/.buildozer/android/
- cp -f $TRAVIS_BUILD_DIR/scripts/build-target-python.sh ~/.buildozer/android/crystax-ndk-10.3.2/build/tools/build-target-python.sh
- rm -rf ~/.buildozer/android/crystax-ndk-10.3.2/platforms/android-9
- ln -s ~/.buildozer/android/crystax-ndk-10.3.2/platforms/android-21 ~/.buildozer/android/crystax-ndk-10.3.2/platforms/android-9
- tar -xf ~/.buildozer/android/platform/android-sdk_r23-linux.tgz -C ~/.buildozer/android/platform/
- mv ~/.buildozer/android/platform/android-sdk-linux ~/.buildozer/android/platform/android-sdk-23
- unzip -qq ~/.buildozer/android/platform/platform-27_r01.zip -d ~/.buildozer/android/platform/android-sdk-23/platforms
- mv ~/.buildozer/android/platform/android-sdk-23/platforms/android-8.1.0 ~/.buildozer/android/platform/android-sdk-23/platforms/android-27
- mkdir -p ~/.buildozer/android/platform/android-sdk-23/build-tools
- unzip -qq ~/.buildozer/android/platform/build-tools_r26.0.2-linux.zip -d ~/.buildozer/android/platform/android-sdk-23/build-tools
- mv ~/.buildozer/android/platform/android-sdk-23/build-tools/android-8.1.0 ~/.buildozer/android/platform/android-sdk-23/build-tools/26.0.2
- mkdir -p ~/.buildozer/android/platform/android-sdk-23/licenses
- echo $'\nd56f5187479451eabf01fb78af6dfcb131a6481e' > ~/.buildozer/android/platform/android-sdk-23/licenses/android-sdk-license
- echo $'\n84831b9409646a918e30573bab4c9c91346d8abd' > ~/.buildozer/android/platform/android-sdk-23/licenses/android-sdk-preview-license
script:
- "./release.sh | grep -Fv -e 'working:' -e 'copy' -e 'Compiling' --line-buffered"
- cp $TRAVIS_BUILD_DIR/bin/*.apk /dev/null
before_deploy:
- cd $TRAVIS_BUILD_DIR/bin
- export BUILD_VERSION=$(cat ../src/main/python/main.py | grep --color=never -oP '([0-9]+\.?)+')
- cp browser-$BUILD_VERSION-release.apk latest.apk
deploy:
- provider: releases
api_key:
secure: m+FYX7vHZoiLSHHiJ2d3y8Fm4qSRoIVjEei+5BV17awiow/U8UKvy/5J1n8qfBdq+dpst5z58pTHCKWPbJz84C3z/posJ5mwEcOAaD/kxSAMHbtlaPW90pRWHUu3aW86UM/ggqtljE9Qz8KS/9a0xNUDfcXLkLgxuxgwodMcacEulAAc9TIOCUeR3IFI+KN0ptTCVahCu2JN8DCHKomaR+yKZHdo/9v9XCAcvmImSDu9nUDLH3+A7xQeRpPJqSspk1dadgdXP76kU8t3OKsYuM7DS5AoKvMIc9lZot4UYYKAx7/zavbzeEmqnyskULgsmV8/UDI1AV9U7uFBdrR6dSjISA1k6EHnCgqzasF+lp0hz5iE/0yPxlE9Z1kLW9gZgxSJtjr6Kv2uqAjHYYmpkjtTwHPwBugRM7PWMTxHNcPwkIHpBSRkXjpyDjkWd/LY4X866Y1g2BdIhbGshjy/9Fb2vnYxNZW6drLHn+wWeHJ41Vfgtg1cn01yZGJqgIkcTkhzNL6Bi++y8EBJXDr4L870s336SpbqRuIrO/C16ZFB+XnOg4Ty50Fk5zkbySMHII58iWqSyDYWNvhqo9zU9jn1XQQeok12129Y4t9TUOcJRbxhQ+511lCmVcFIkWHsXDK2QSZ7TeMK5GQUA8OvcNe+WLCJaQ/YD7OZvwlPTvc=
file_glob: true
file: browser-*-release.apk
overwrite: true
skip_cleanup: true
on:
tags: true
- provider: s3
access_key_id:
secure: qEZZ73DWBn9+M2pS4VwsyX8YZjZOENIMP/eoU1A9Vbn155oZpbUaJ7k+4cAXqmBm0WBMKZDqpzCRSGehLAxHFH5rjkj9gLSgd8fY9cveABHkl50HeuxxNsQM+ytk9sCtP8bWOqf7rT/iCgM1soyF2pYmfHM3tU9l0fWK8oZ7pFRIg91hXxUvhvYY2u6B9D1NqSN9T3xtrwEkVjvmkmyKMLCtoIdyB7QdeQciFdGFhZC9DYJVRLxa3BlzZ1T8Qv4MCyIxPjxIugNvVR64VgGjdBdq0BEIyoRqbeIvtqQjlnne4DfJFeCmbDrSva1wDP1UyFoxsRhiWQ/jXXgIyN2CisI6QRD0J+a2LgmbmtkUzhRMuVQJmBrIauulOzcowwRV2J4TtUaAJK9iSHT9D3RLzpazCOnjvJZV9CK5w252Vs5eHnisCSCQk8Ozox96Sg6XW580NEXfkYoGzXLSGiy9zrZs813blUjssEY+jIQmJEby80C3guK7/G4lzthv57psqBWcYd0tFR+vTestS+EFlC02ToUngJhW7I7lPA2G2yrJ5319jFxUSniijb1n72TQthnbqTBahepvKvuG1iWZnCKxS5sWkutFoqEcpQyhXdf7QdR/VrOr8N5xrhK1B8dCYZM6h8eMZbBvOLH49+N6L9jiJz5x+Lk32wcssv1oOgI=
secret_access_key:
secure: lPygaaJdjFgWY4GcXUXC4Oc5op/TE85Md8lX2bzW19058lbcqYSdM0WySQCxoU/4rlM4Q0N8du0qQ3kZXDpP9XSqvFTVnTGTuB4yghUR1yXcpt6u3JOeOX+YAc3wyQ/pmod6VGO0n8pm8hBVsSFXufdBTjD2W+tNrDoa8RYnlWrt7BbICGltB7PcqYh1Qw6S1wDyZt8I4B5JHDhyJmX6FT5KfOb5cJyynpxlKUstUfy1rh81KuGkEcuEVOLg1s7HE1/IUkVIgezAuCrMHjc86qbNcHULJMFCVYntvvs07+tctrPxA/cfS24WkW7smyij+gdZAZWNNgkIDCuwqpex1v1nKn56mC8xXyUl4CnSCuubQtqUBzTmd4T5sF7trTtpVr9NInwy+4mUoCpz2UKZekTjZkqpzCAuC/cBVWE1/k3wsNat6dGyc9QnKXBqLVhuwYsCOteqLW50ToMMMW0ccDV6FXodwZmrunGd5wIX+UgZkf4l32vzKUxHtIupfYbsjylcPc3VO0OzMMKP/3sYLAN6QntVDFc30k1uqqpgJN4t0nV7vvjMI+b0Qr+o7GzUV2d+QulQXOySJgB2pH0kV1EoPAJ8KbqDOy8KgCJl0YIbOaz14+SiRQhotJ2hrLdtsvyVYXMX+d/CKHJSWa2MQq+jD7lMCwVaGg82PFN1gI4=
bucket: "build.lbry.io"
upload-dir: android
region: us-east-1
overwrite: true
skip_cleanup: true
on:
tags: true
- provider: s3
access_key_id:
secure: qEZZ73DWBn9+M2pS4VwsyX8YZjZOENIMP/eoU1A9Vbn155oZpbUaJ7k+4cAXqmBm0WBMKZDqpzCRSGehLAxHFH5rjkj9gLSgd8fY9cveABHkl50HeuxxNsQM+ytk9sCtP8bWOqf7rT/iCgM1soyF2pYmfHM3tU9l0fWK8oZ7pFRIg91hXxUvhvYY2u6B9D1NqSN9T3xtrwEkVjvmkmyKMLCtoIdyB7QdeQciFdGFhZC9DYJVRLxa3BlzZ1T8Qv4MCyIxPjxIugNvVR64VgGjdBdq0BEIyoRqbeIvtqQjlnne4DfJFeCmbDrSva1wDP1UyFoxsRhiWQ/jXXgIyN2CisI6QRD0J+a2LgmbmtkUzhRMuVQJmBrIauulOzcowwRV2J4TtUaAJK9iSHT9D3RLzpazCOnjvJZV9CK5w252Vs5eHnisCSCQk8Ozox96Sg6XW580NEXfkYoGzXLSGiy9zrZs813blUjssEY+jIQmJEby80C3guK7/G4lzthv57psqBWcYd0tFR+vTestS+EFlC02ToUngJhW7I7lPA2G2yrJ5319jFxUSniijb1n72TQthnbqTBahepvKvuG1iWZnCKxS5sWkutFoqEcpQyhXdf7QdR/VrOr8N5xrhK1B8dCYZM6h8eMZbBvOLH49+N6L9jiJz5x+Lk32wcssv1oOgI=
secret_access_key:
secure: lPygaaJdjFgWY4GcXUXC4Oc5op/TE85Md8lX2bzW19058lbcqYSdM0WySQCxoU/4rlM4Q0N8du0qQ3kZXDpP9XSqvFTVnTGTuB4yghUR1yXcpt6u3JOeOX+YAc3wyQ/pmod6VGO0n8pm8hBVsSFXufdBTjD2W+tNrDoa8RYnlWrt7BbICGltB7PcqYh1Qw6S1wDyZt8I4B5JHDhyJmX6FT5KfOb5cJyynpxlKUstUfy1rh81KuGkEcuEVOLg1s7HE1/IUkVIgezAuCrMHjc86qbNcHULJMFCVYntvvs07+tctrPxA/cfS24WkW7smyij+gdZAZWNNgkIDCuwqpex1v1nKn56mC8xXyUl4CnSCuubQtqUBzTmd4T5sF7trTtpVr9NInwy+4mUoCpz2UKZekTjZkqpzCAuC/cBVWE1/k3wsNat6dGyc9QnKXBqLVhuwYsCOteqLW50ToMMMW0ccDV6FXodwZmrunGd5wIX+UgZkf4l32vzKUxHtIupfYbsjylcPc3VO0OzMMKP/3sYLAN6QntVDFc30k1uqqpgJN4t0nV7vvjMI+b0Qr+o7GzUV2d+QulQXOySJgB2pH0kV1EoPAJ8KbqDOy8KgCJl0YIbOaz14+SiRQhotJ2hrLdtsvyVYXMX+d/CKHJSWa2MQq+jD7lMCwVaGg82PFN1gI4=
bucket: "build.lbry.io"
upload-dir: "android/build-${TRAVIS_BUILD_NUMBER}_commit-${TRAVIS_COMMIT:0:7}"
region: us-east-1
overwrite: true
skip_cleanup: true
on:
all_branches: true
env:
global:
- secure: GS3Cp1QXiX8UPye3kdk2A2f3iFRr02sHKpY+RE+Zvx3Q7GDmhDuepHKzx6Hq5Os5fZN9Y/Bdds+XH+vLIRtT6XsWR7AONPhSifVY3XB5/2F+lDcZ538W8P8GZvXejpY4VecMUWHoWbuyt0s3PpaGXZJcHp8ir+CUJ0NUmU3I9w449pqj9/de2LHtG3qKH1lG0Xz58iOC0mmEeH451cQv3dDw851ihA4ak9vCTV1KKuMJUcv+2u6PxXGVX0mrJLEssjL6ze6G5iZUB4PM1vUpe3HqcVw8CSOa8O79BQxoB00qyA3WD+LpZDPpI0wh6gmBsR/2nCFyMJndJr3CjyB6lHdK7PgBoK0CJjszKawiZqg74O9DOjzTJTO2v9bnkfPrNxu4/3D/tbDg+whY8k5oV1sgDue9KAo/2aEEO0LGlKP4W3Qqt/lzRKsfpMVrMTdCNKJ8rG/wUFWw8ehOCmAsJaQ1saDOZDMNPLLuYpxFgmXFqWV5ThbUHgEJVj+G7qt6CMEussKvuZJoJZx24Pdk5Prr7ENzTyPmE5gk4b8WNfVNleOEC09xu5tFk2yOdzF1dawKsa1Mog6gImirTQ/INC/3BANdKoG9/cLJEIt9boJaFDXE1dpqoLVzoez9znHKOGSAU/1PaH3thjVnbUyO5z24PpPZ12zM3+3P8DbI454=
before_install:
- openssl aes-256-cbc -K $encrypted_b4c9b905b12e_key -iv $encrypted_b4c9b905b12e_iv
-in lbry-android.keystore.enc -out lbry-android.keystore -d

117
BUILD.md
View file

@ -1,117 +0,0 @@
## Linux Build Instructions
This app has currently only been built on Ubuntu 14.04, 16.04, 17.10, and 18.04, but these instructions, or an analog of them, should work on most Linux or macOS environments.
### Install Prerequisites
#### Requirements
* JDK 1.8
* Android SDK
* Crystax Android NDK
* Buildozer
* Node.js
* npm
* yarn
#### apt Packages
Based on the quick-start instructions at http://buildozer.readthedocs.io/en/latest/installation.html
```
sudo dpkg --add-architecture i386
sudo apt-get update
sudo apt-get install autoconf autogen build-essential curl libtool libffi-dev python python-pip python-openssl python3.7 python3.7-dev python3-pip ccache git libncurses5:i386 libstdc++6:i386 libgtk2.0-0:i386 libpangox-1.0-0:i386 libpangoxft-1.0-0:i386 libidn11:i386 python2.7 python2.7-dev openjdk-8-jdk unzip zlib1g-dev zlib1g:i386 m4 libc6-dev-i386
```
Alternatively, the JDK available from http://www.oracle.com/technetwork/java/javase/downloads/index.html can be installed instead of the `openjdk-8-jdk` package.
#### Install Cython and Setuptools
```
sudo pip install --upgrade cython==0.28.1 setuptools
```
#### Install buildozer
A forked version of `buildozer` needs to be installed in order to copy the React Native UI source files into the corresponding directories.
```
git clone https://github.com/lbryio/buildozer.git
cd buildozer
sudo python2.7 setup.py install
```
#### Create buildozer.spec
Assuming `lbry-android` as the current working folder:
* Copy `buildozer.spec.sample` to `buildozer.spec` in the `lbry-android` folder. Running `buildozer init` instead will create a new `buildozer.spec` file.
* Update `buildozer.spec` settings to match your environment. The basic recommended settings are outlined below.
| Setting | Description |
|:------------------- |:-----------------------------|
| title | application title |
| package.name | package name (e.g. browser) |
| package.domain | package domain (e.g. io.lbry) |
| source.dir | the location of the application main.py |
| version | application version |
| requirements | the Python module requirements for building the application |
| services | list of Android background services and their corresponding Python entry points |
| android.permissions | Android manifest permissions required by the application. This should be set to `INTERNET` at the very least to enable internet connectivity |
| android.api | Android API version (Should be at least 23 for Gradle build support) |
| android.sdk | Android SDK version (Should be at least 23 for Gradle build support) |
| android.ndk | Android NDK version (not required when using crystax Android NDK) |
| android.ndk_path | Android NDK path. This should be set to the crystax Android NDK path) |
| android.sdk_path | Android SDK path. This should be set to the path where the Android SDK is manually set up (if not set up in the `.buildozer` path). |
| p4a.source_dir | Path to the python-for-android repository folder. Currently set to the included `p4a` folder |
| p4a.local_recipes | Path to a folder containing python_for_android recipes to be used in the build. The included `recipes` folder includes recipes for a successful build |
#### Setup Android SDK for buildozer
Download the Android SDK, platform and build tools archives.
* Android API 23 SDK - https://dl.google.com/android/android-sdk_r23-linux.tgz
* Android API 27 platform - https://dl.google.com/android/repository/platform-27_r01.zip
* Android build tools 26.0.1 - https://dl.google.com/android/repository/build-tools_r26.0.1-linux.
Create the `.buildozer` path (and the `android` sub-path) in your home folder if it doesn't already exist.
`mkdir ~/.buildozer`
`mkdir ~/.buildozer/android`
Extract the API 23 SDK to the `~/.buildozer/android` path and rename the extracted folder.
```
tar -xf android-sdk_r23-linux.tgz ~/.buildozer/android/platform/
mv ~/.buildozer/android/platform/android-sdk-linux ~/.buildozer/android/platform/android-sdk-23
```
Extract the API 27 platform archive into the `android-sdk-23` folder and rename the extracted folder.
```
unzip platform-27_r01.zip -d ~/.buildozer/android/platform/android-sdk-23/platforms
mv ~/.buildozer/android/platform/android-sdk-23/platforms/android-8.1.0 ~/.buildozer/android/platform/android-sdk-23/platforms/android-27
```
Extract the build tools 26.0.1 build tools into the `android-sdk-23` folder and rename the extracted folder.
```
mkdir -p ~/.buildozer/android/platform/android-sdk-23/build-tools
unzip ~/.buildozer/android/platform/build-tools_r26.0.1-linux.zip -d ~/.buildozer/android/platform/android-sdk-23/build-tools
mv ~/.buildozer/android/platform/android-sdk-23/build-tools/android-8.0.0 ~/.buildozer/android/platform/android-sdk-23/build-tools/26.0.1
```
Finally, create the Android SDK license file. This prevents being prompted to accept the SDK license during the build process.
```
mkdir -p ~/.buildozer/android/platform/android-sdk-23/licenses
echo $'\nd56f5187479451eabf01fb78af6dfcb131a6481e' > ~/.buildozer/android/platform/android-sdk-23/licenses/android-sdk-license
```
#### Setup Crystax Android NDK for buildozer
* Download the Crystax Android NDK from https://us.crystax.net/download/crystax-ndk-10.3.2-linux-x86_64.tar.xz and extract. Remember to update `android.ndk_path` in your `buildozer.spec` to the path of the extracted Crystax NDK archive.
* Copy `build-target-python.sh` from the `scripts` folder in the cloned `lbry-android` repository to the `crystax-ndk-10.3.2/build/tools/` folder.
* Delete the `android-9` folder in `crystax-ndk-10.3.2/platforms`, and create a symbolic link named `android-9` to the `android-21` folder.
#### Build and Deploy
Run `npm i` in the `lbry-android/app` folder to install the necessary modules required by the React Native user interface.
Run `./build.sh` in `lbry-android` to build the APK. The output can be found in the `bin` subdirectory.
To build and deploy, you can run `./deploy.sh`. This requires a connected device or running Android emulator.
#### Development
If you already installed `Android SDK` and `adb`
* Run `adb reverse tcp:8081 tcp:8081`
* Then go to the `lbry-android/app` folder and run `npm start`
Note: You need to have your device connected with USB debugging.
Once the bundler is ready, run the LBRY Browser app on your device and then shake the device violently until you see the React Native dev menu. You can enable "Live Reloading" and "Hot Reloading" from this menu, so any changes you make to the React Native code will be visible as you save. This will only reload React Native Javascript files. Native Java code needs to be redeployed by running the command `./deploy.sh`

View file

@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2017-2018 LBRY Inc
Copyright (c) 2017-2020 LBRY Inc
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish,distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

View file

@ -1,110 +0,0 @@
### Introduction
If you would like to contribute to the Android app, but find the build documentation a little daunting, this guide lets you copy-paste your way to a successful APK build.
#### Estimated build time
25 - 40 minutes (depending on Internet connection speeds)
#### What do you need?
* A computer running Ubuntu 18.04
* Internet access to download modules and packages.
* At least 15GB of free disk space.
* Alternatively, Docker. You can skip steps 1 through 5 if you make use of the `lbry/android-base` Docker base image. Scroll down to Fast track if you would prefer to use Docker.
### Step 1 of 10
Install all the apt packages required by running the following commands. You can copy-paste directly to your terminal.
```
sudo dpkg --add-architecture i386
sudo apt-get -y update
sudo apt-get install -y curl ca-certificates software-properties-common gpg-agent wget
sudo add-apt-repository ppa:deadsnakes/ppa -y && \
curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
sudo apt-get -y update && apt-get -y install autoconf autogen automake libtool libffi-dev \
build-essential python3.7 python3.7-dev python3.7-venv python3-pip ccache git libncurses5:i386 libstdc++6:i386 \
libgtk2.0-0:i386 libpangox-1.0-0:i386 libpangoxft-1.0-0:i386 libidn11:i386 python2.7 python2.7-dev \
python-pip openjdk-8-jdk unzip zlib1g-dev zlib1g:i386 m4 libc6-dev-i386 yarn gawk nodejs npm
```
### Step 2 of 10
Install a couple of packages using the Python package installer
```
sudo -H pip install --upgrade cython==0.28.1 setuptools
```
### Step 3 of 10
Install buildozer, a tool for creating the apk package using the python for android toolcahin.
```
git clone https://github.com/lbryio/buildozer.git
cd buildozer && python2.7 setup.py install && cd ..
```
### Step 4 of 10
The Android SDK needs to be setup for buildozer. This requires creating a few directories and downloading a number of files. Run the following commands to create the buildozer directory, download the required archives and extract them into their proper destination folders.
```
mkdir -p ~/.buildozer/android/platform
wget 'https://dl.google.com/android/android-sdk_r23-linux.tgz' -P ~/.buildozer/android/platform/ && \
wget 'https://dl.google.com/android/repository/platform-28_r06.zip' -P ~/.buildozer/android/platform/ && \
wget 'https://dl.google.com/android/repository/build-tools_r26.0.2-linux.zip' -P ~/.buildozer/android/platform/
tar -xvf ~/.buildozer/android/platform/android-sdk_r23-linux.tgz -C ~/.buildozer/android/platform/ && \
mv ~/.buildozer/android/platform/android-sdk-linux ~/.buildozer/android/platform/android-sdk-23 && \
unzip ~/.buildozer/android/platform/platform-28_r06.zip -d ~/.buildozer/android/platform/android-sdk-23/platforms && \
mv ~/.buildozer/android/platform/android-sdk-23/platforms/android-9 ~/.buildozer/android/platform/android-sdk-23/platforms/android-28 && \
mkdir -p ~/.buildozer/android/platform/android-sdk-23/build-tools && \
unzip ~/.buildozer/android/platform/build-tools_r26.0.2-linux.zip -d ~/.buildozer/android/platform/android-sdk-23/build-tools && \
mkdir -p ~/.buildozer/android/platform/android-sdk-23/licenses && \
echo $'\nd56f5187479451eabf01fb78af6dfcb131a6481e' > ~/.buildozer/android/platform/android-sdk-23/licenses/android-sdk-license
```
### Step 5 of 10
Install the react-native-cli npm package.
```
sudo npm install -g react-native-cli
```
### Step 6 of 10
Install the Crystax NDK which is required for building Python 3.7 for the mobile app, and a number of native C / C++ modules and packages used by the app. Run the following commands to download and extract the NDK.
```
wget 'https://www.crystax.net/download/crystax-ndk-10.3.2-linux-x86_64.tar.xz' -P ~/.buildozer/android/ && \
tar -xvf ~/.buildozer/android/crystax-ndk-10.3.2-linux-x86_64.tar.xz -C ~/.buildozer/android/ && \
rm -rf ~/.buildozer/android/crystax-ndk-10.3.2/platforms/android-9 && \
ln -s ~/.buildozer/android/crystax-ndk-10.3.2/platforms/android-21 ~/.buildozer/android/crystax-ndk-10.3.2/platforms/android-9
```
### Step 7 of 10
Clone the lbryio/lbry-android git repository and create your buildozer.spec file. The provide buildozer.spec.sample contains defaults provided you followed steps 1 through 5 exactly as described. You can also customise the spec file if you want to.
```
git clone https://github.com/lbryio/lbry-android
cd lbry-android
cp buildozer.spec.sample buildozer.spec
```
### Step 8 of 10
Install the npm packages required for the app's React Native code.
```
cd app
npm install
cd ..
```
### Step 9 of 10
Copy a couple of required files from the repository for the build to be successful.
```
cp scripts/build-target-python.sh ~/.buildozer/android/crystax-ndk-10.3.2/build/tools/build-target-python.sh
cp scripts/mangled-glibc-syscalls.h ~/.buildozer/android/crystax-ndk-10.3.2/platforms/android-21/arch-arm/usr/include/crystax/bionic/libc/include/sys/mangled-glibc-syscalls.h
```
### Step 10 of 10
If you made it this far, you're finally ready to build the package! You just have to run a single command to generate the APK.
```
buildozer android debug
```
### Fast Track
Install Docker and start a container using the `lbry/android-base` image, which is about 1.72GB in size. Run the following commands for Ubuntu and then follow steps 6 through 10 in the container's bash prompt.
```
sudo apt-get install docker-ce
docker run -it lbry/android-base:latest /bin/bash
```
**Protip:** You can also make use of Docker to run your builds on macOS or Windows.

View file

@ -1,9 +1,12 @@
# LBRY Android
[![pipeline status](https://ci.lbry.tech/lbry/lbry-android/badges/master/pipeline.svg)](https://ci.lbry.tech/lbry/lbry-android/commits/master)
[![GitHub license](https://img.shields.io/github/license/lbryio/lbry-android)](https://github.com/lbryio/lbry-android/blob/master/LICENSE)
An Android browser and wallet for the [LBRY](https://lbry.com) network. This app bundles [lbrynet-daemon](https://github.com/lbryio/lbry) as a background service with a UI layer built with React Native. The APK is built using buildozer and the Gradle build tool.
An Android browser and wallet for the [LBRY](https://lbry.com) network.
<img src="https://spee.ch/@lbry:3f/android-08-homepage.gif" alt="LBRY Android GIF" width="384px" />
<img src="https://spee.ch/8/lbry-android.png" alt="LBRY Android Screenshot" width="384px" />
## Installation
The minimum supported Android version is 5.0 Lollipop. There are two ways to install:
@ -12,10 +15,22 @@ The minimum supported Android version is 5.0 Lollipop. There are two ways to ins
1. Direct APK install available at [http://build.lbry.io/android/latest.apk](http://build.lbry.io/android/latest.apk). You will need to enable installation from third-party sources on your device in order to install from this source.
## Usage
The app can be launched by opening **LBRY Browser** from the device's app drawer or via the shortcut on the home screen if that was created upon installation.
The app can be launched by opening **LBRY** from the device's app drawer or via the shortcut on the home screen if that was created upon installation.
## Running from Source
The app is built from source via [Buildozer](https://github.com/kivy/buildozer). After cloning the repository, copy `buildozer.spec.sample` to `buildozer.spec` and modify this file as necessary for your environment. Please see [BUILD.md](BUILD.md) for detailed build instructions.
Clone the repository and open the project in Android Studio. Android Studio will automatically run the initial build process.
Create file 'twitter.properties' in app/ folder with the following content:
```
twitterConsumerKey=XXXXXX
twitterConsumerSecret=XXXXXX
```
Copy the file 'google-services.sample.json' to 'google-services.json' in the app/ folder.
Click the Sync button and when process finishes, the Run button to launch the app on your simulator or connected debugging device after the build process is complete.
## Contributing
Contributions to this project are welcome, encouraged, and compensated. For more details, see https://lbry.io/faq/contributing
@ -24,7 +39,7 @@ Contributions to this project are welcome, encouraged, and compensated. For more
This project is MIT licensed. For the full license, see [LICENSE](LICENSE).
## Security
We take security seriously. Please contact security@lbry.com regarding any security issues. Our PGP key is [here](https://keybase.io/lbry/key.asc) if you need it.
We take security seriously. Please contact security@lbry.com regarding any security issues. Our PGP key is [here](https://lbry.com/faq/pgp-key) if you need it.
## Contact
The primary contact for this project is [@akinwale](https://github.com/akinwale) (akinwale@lbry.com)

100
Vagrantfile vendored
View file

@ -1,100 +0,0 @@
echoed=false
Vagrant.configure("2") do |config|
config.vm.box = "ubuntu/bionic64"
#config.disksize.size = "20GB"
config.vm.provider "virtualbox" do |v|
host = RbConfig::CONFIG['host_os']
# Give VM 1/4 system memory & access to all cpu cores on the host
if host =~ /darwin/
cpus = `sysctl -n hw.ncpu`.to_i
# sysctl returns Bytes and we need to convert to MB
mem = `sysctl -n hw.memsize`.to_i / 1024 / 1024 / 4
elsif host =~ /linux/
cpus = `nproc`.to_i
# meminfo shows KB and we need to convert to MB
mem = `grep 'MemTotal' /proc/meminfo | sed -e 's/MemTotal://' -e 's/ kB//'`.to_i / 1024 / 4
else
cpus = `wmic cpu get NumberOfCores`.split("\n")[2].to_i
mem = `wmic OS get TotalVisibleMemorySize`.split("\n")[2].to_i / 1024 /4
end
mem = mem / 1024 / 4
mem = [mem, 2048].max # Minimum 2048
if echoed === false
echoed=true
puts("Memory", mem)
puts("CPUs", cpus)
end
#v.customize ["setextradata", :id, "VBoxInternal2/SharedFoldersEnableSymlinksCreate/home_vagrant_lbry-android", "1"]
#v.customize ["setextradata", :id, "VBoxInternal2/SharedFoldersEnableSymlinksCreate/vagrant", "1"]
v.customize ["modifyvm", :id, "--memory", mem]
v.customize ["modifyvm", :id, "--cpus", cpus]
end
config.vm.synced_folder "./", "/home/vagrant/lbry-android"
config.vm.provision "shell", inline: <<-SHELL
dpkg --add-architecture i386
apt-get update
apt-get install -y libssl-dev
apt-get install -y python3.6 python3.6-dev python3-pip autoconf libffi-dev pkg-config libtool build-essential ccache git libncurses5:i386 libstdc++6:i386 libgtk2.0-0:i386 libpangox-1.0-0:i386 libpangoxft-1.0-0:i386 libidn11:i386 python2.7 python2.7-dev openjdk-8-jdk unzip zlib1g-dev zlib1g:i386 m4 libc6-dev-i386 python-pip
pip install -f --upgrade setuptools pyopenssl
git clone https://github.com/lbryio/buildozer.git
cd buildozer
python2.7 setup.py install
cd ../
rm -rf ./buildozer
# Install additonal buildozer dependencies
sudo apt-get install cython
# Install node
curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash -
sudo apt-get install -y nodejs
export HOME=/home/vagrant
cp $HOME/lbry-android/buildozer.spec.vagrant $HOME/lbry-android/buildozer.spec
mkdir -p cd $HOME/.buildozer/android/platform/
wget -q 'https://us.crystax.net/download/crystax-ndk-10.3.2-linux-x86_64.tar.xz' -P $HOME/.buildozer/android/
wget -q 'https://dl.google.com/android/android-sdk_r23-linux.tgz' -P $HOME/.buildozer/android/platform/
wget -q 'https://dl.google.com/android/repository/platform-27_r01.zip' -P $HOME/.buildozer/android/platform/
wget -q 'https://dl.google.com/android/repository/build-tools_r26.0.1-linux.zip' -P $HOME/.buildozer/android/platform/
tar -xf ~/.buildozer/android/crystax-ndk-10.3.2-linux-x86_64.tar.xz -C $HOME/.buildozer/android/
rm $HOME/.buildozer/android/crystax-ndk-10.3.2-linux-x86_64.tar.xz
ln -s $HOME/.buildozer/android/crystax-ndk-10.3.2/platforms/android-21 $HOME/.buildozer/android/crystax-ndk-10.3.2/platforms/android-9
cp -f $HOME/lbry-android/scripts/build-target-python.sh $HOME/.buildozer/android/crystax-ndk-10.3.2/build/tools/build-target-python.sh
rm -rf $HOME/.buildozer/android/crystax-ndk-10.3.2/platforms/android-9
tar -xf $HOME/.buildozer/android/platform/android-sdk_r23-linux.tgz -C $HOME/.buildozer/android/platform/
rm $HOME/.buildozer/android/platform/android-sdk_r23-linux.tgz
mv $HOME/.buildozer/android/platform/android-sdk-linux $HOME/.buildozer/android/platform/android-sdk-23
unzip -qq $HOME/.buildozer/android/platform/android-23_r02.zip -d $HOME/.buildozer/android/platform/android-sdk-23/platforms
rm $HOME/.buildozer/android/platform/platform-27_r01.zip
mv $HOME/.buildozer/android/platform/android-sdk-23/platforms/android-8.1.0 $HOME/.buildozer/android/platform/android-sdk-23/platforms/android-27
mkdir -p $HOME/.buildozer/android/platform/android-sdk-23/build-tools
unzip -qq $HOME/.buildozer/android/platform/build-tools_r26.0.1-linux.zip -d $HOME/.buildozer/android/platform/android-sdk-23/build-tools
rm $HOME/.buildozer/android/platform/build-tools_r26.0.1-linux.zip
mv $HOME/.buildozer/android/platform/android-sdk-23/build-tools/android-8.0.0 $HOME/.buildozer/android/platform/android-sdk-23/build-tools/26.0.1
mkdir -p $HOME/.buildozer/android/platform/android-sdk-23/licenses
rm -rf $HOME/.buildozer/android/platform/android-sdk-23/tools
# https://dl.google.com/android/repository/sdk-tools-linux-3859397.zip
wget -q https://dl.google.com/android/repository/tools_r25.2.5-linux.zip
unzip -o -q ./tools_r25.2.5-linux.zip -d $HOME/.buildozer/android/platform/android-sdk-23/
rm sdk-tools-linux-3859397.zip
echo $'\nd56f5187479451eabf01fb78af6dfcb131a6481e' > $HOME/.buildozer/android/platform/android-sdk-23/licenses/android-sdk-license
sudo chown -r vagrant $HOME
echo "Installing React Native via NPM..."
sudo npm install -g react-native-cli
SHELL
end

View file

@ -1,9 +0,0 @@
{
"presets": ["module:metro-react-native-babel-preset"],
"plugins": [
"@babel/plugin-proposal-nullish-coalescing-operator",
["module-resolver", {
root: ["./src"],
}],
]
}

1
app/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/build

144
app/build.gradle Normal file
View file

@ -0,0 +1,144 @@
import com.google.gms.googleservices.GoogleServicesPlugin
apply plugin: 'com.android.application'
android {
compileSdkVersion 29
buildToolsVersion "29.0.2"
flavorDimensions "default"
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
defaultConfig {
applicationId "io.lbry.browser"
minSdkVersion 21
targetSdkVersion 29
versionCode 1701
versionName "0.17.1"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
packagingOptions {
exclude 'META-INF/DEPENDENCIES'
exclude 'lib/x86_64/darwin/libscrypt.dylib'
}
productFlavors {
__32bit {
versionCode android.defaultConfig.versionCode * 10 + 1
ndk {
abiFilter "armeabi-v7a"
}
}
__64bit {
versionCode android.defaultConfig.versionCode * 10 + 2
ndk {
abiFilter "arm64-v8a"
}
}
}
buildTypes {
debug {
Properties twitterProps = new Properties()
twitterProps.load(project.file('twitter.properties').newDataInputStream())
resValue "string", "TWITTER_CONSUMER_KEY", "\"${twitterProps.getProperty("twitterConsumerKey")}\""
resValue "string", "TWITTER_CONSUMER_SECRET", "\"${twitterProps.getProperty("twitterConsumerSecret")}\""
}
release {
Properties twitterProps = new Properties()
twitterProps.load(project.file('twitter.properties').newDataInputStream())
resValue "string", "TWITTER_CONSUMER_KEY", "\"${twitterProps.getProperty("twitterConsumerKey")}\""
resValue "string", "TWITTER_CONSUMER_SECRET", "\"${twitterProps.getProperty("twitterConsumerSecret")}\""
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
task printVersionName {
doLast {
println android.defaultConfig.versionName
}
}
configurations {
all {
exclude module: 'httpclient'
exclude module: 'commons-logging'
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.3.0-alpha01'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'com.google.android.material:material:1.3.0-alpha01'
implementation "androidx.cardview:cardview:1.0.0"
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
implementation 'androidx.navigation:navigation-fragment:2.3.1'
implementation 'androidx.navigation:navigation-ui:2.3.1'
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.0.0'
implementation 'androidx.preference:preference:1.1.1'
implementation 'androidx.webkit:webkit:1.4.0-rc01'
implementation 'androidx.camera:camera-core:1.0.0-beta03'
implementation 'androidx.camera:camera-camera2:1.0.0-beta03'
implementation 'androidx.camera:camera-lifecycle:1.0.0-beta03'
implementation 'androidx.camera:camera-view:1.0.0-alpha10'
implementation 'androidx.browser:browser:1.2.0'
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
implementation 'com.github.bumptech.glide:glide:4.11.0'
implementation 'com.squareup.okhttp3:okhttp:4.4.1'
implementation 'com.google.firebase:firebase-analytics:18.0.0'
implementation 'com.google.android.gms:play-services-base:17.5.0'
implementation 'com.google.firebase:firebase-messaging:21.0.0'
implementation 'com.google.oauth-client:google-oauth-client:1.30.4'
implementation 'com.android.billingclient:billing:3.0.2'
implementation 'com.google.code.gson:gson:2.8.6'
implementation 'com.google.android.exoplayer:exoplayer-core:2.12.2'
implementation 'com.google.android.exoplayer:exoplayer-dash:2.12.2'
implementation 'com.google.android.exoplayer:exoplayer-ui:2.12.2'
implementation 'com.google.android.exoplayer:extension-cast:2.12.2'
implementation 'com.google.android.exoplayer:extension-mediasession:2.12.2'
implementation 'com.google.android:flexbox:2.0.1'
implementation 'com.hbb20:ccp:2.3.8'
implementation 'com.github.chrisbanes:PhotoView:2.3.0'
implementation 'com.atlassian.commonmark:commonmark:0.14.0'
implementation 'com.arthenica:mobile-ffmpeg-full-gpl:4.3.1.LTS'
implementation 'commons-codec:commons-codec:1.15'
implementation 'org.bitcoinj:bitcoinj-tools:0.14.7'
implementation 'org.java-websocket:Java-WebSocket:1.5.1'
implementation ('com.journeyapps:zxing-android-embedded:4.1.0') { transitive = false }
implementation 'com.google.zxing:core:3.3.0'
compileOnly 'org.projectlombok:lombok:1.18.10'
annotationProcessor 'org.projectlombok:lombok:1.18.10'
annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.3.0'
androidTestImplementation 'androidx.test:rules:1.3.0'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
__32bitImplementation 'io.lbry:lbrysdk32:0.102.0'
__64bitImplementation 'io.lbry:lbrysdk64:0.102.0'
//__64bitImplementation(name: 'lbrysdk', ext: 'aar')
}
apply plugin: 'com.google.gms.google-services'
GoogleServicesPlugin.config.disableVersionCheck = true

View file

@ -1,2 +0,0 @@
#!/bin/sh
react-native bundle --platform android --dev false --entry-file src/index.js --bundle-output ../src/main/assets/index.android.bundle --assets-dest ../src/main/res/

Binary file not shown.

View file

@ -0,0 +1,41 @@
{
"project_info": {
"project_number": "861521963586",
"firebase_url": "https://lbry-mobile-builds-debug.firebaseio.com",
"project_id": "lbry-mobile-builds-debug",
"storage_bucket": "lbry-mobile-builds-debug.appspot.com"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:861521963586:android:592958d248940ab2",
"android_client_info": {
"package_name": "io.lbry.browser"
}
},
"oauth_client": [
{
"client_id": "861521963586-60cmvg5nmnrqkrc11a7bpmpv5ra2d50q.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyC7A3BYcIdZP9-Q-VNHoexYJWgZA7WzsPI"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "861521963586-60cmvg5nmnrqkrc11a7bpmpv5ra2d50q.apps.googleusercontent.com",
"client_type": 3
}
]
}
}
}
],
"configuration_version": "1"
}

View file

@ -1,3 +0,0 @@
import LBRYApp from './src/index';
export default LBRYApp;

8189
app/package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,47 +0,0 @@
{
"name": "LBRYApp",
"version": "0.0.1",
"private": "true",
"scripts": {
"start": "node node_modules/react-native/local-cli/cli.js start"
},
"dependencies": {
"base-64": "^0.1.0",
"@expo/vector-icons": "^8.1.0",
"lbry-redux": "lbryio/lbry-redux",
"lbryinc": "lbryio/lbryinc",
"lodash": ">=4.17.11",
"merge": ">=1.2.1",
"moment": "^2.22.1",
"react": "16.8.6",
"react-native": "0.59.3",
"@react-native-community/async-storage": "^1.2.2",
"react-native-country-picker-modal": "^0.6.2",
"react-native-exception-handler": "2.9.0",
"react-native-fast-image": "^5.0.3",
"react-native-gesture-handler": "^1.1.0",
"react-native-image-zoom-viewer": "^2.2.5",
"react-native-password-strength-meter": "^0.0.2",
"react-native-phone-input": "lbryio/react-native-phone-input",
"react-native-vector-icons": "^6.4.2",
"react-native-video": "lbryio/react-native-video#exoplayer-lbry-android",
"react-navigation": "^3.11.0",
"react-navigation-redux-helpers": "^3.0.2",
"react-redux": "^5.0.3",
"redux": "^3.6.0",
"redux-persist": "^4.10.2",
"redux-persist-filesystem-storage": "^1.3.2",
"redux-persist-transform-compress": "^4.2.0",
"redux-persist-transform-filter": "0.0.18",
"redux-thunk": "^2.3.0",
"rn-fetch-blob": "^0.10.15"
},
"devDependencies": {
"@babel/core": "^7.4.3",
"babel-preset-env": "^1.6.1",
"babel-preset-react-native": "5.0.2",
"babel-preset-stage-2": "^6.18.0",
"babel-plugin-module-resolver": "^3.1.1",
"flow-babel-webpack-plugin": "^1.1.1"
}
}

21
app/proguard-rules.pro vendored Normal file
View file

@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View file

@ -0,0 +1,27 @@
package io.lbry.browser;
import android.content.Context;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
assertEquals("io.lbry.browser", appContext.getPackageName());
}
}

View file

@ -0,0 +1,12 @@
package io.lbry.browser.utils;
import androidx.test.filters.SmallTest;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
@SmallTest
public class HelperTest {
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

View file

@ -1,392 +0,0 @@
import React from 'react';
import AboutPage from 'page/about';
import DiscoverPage from 'page/discover';
import DownloadsPage from 'page/downloads';
import DrawerContent from 'component/drawerContent';
import FilePage from 'page/file';
import FirstRunScreen from 'page/firstRun';
import RewardsPage from 'page/rewards';
import TrendingPage from 'page/trending';
import SearchPage from 'page/search';
import SettingsPage from 'page/settings';
import SplashScreen from 'page/splash';
import SubscriptionsPage from 'page/subscriptions';
import TransactionHistoryPage from 'page/transactionHistory';
import VerificationScreen from 'page/verification';
import WalletPage from 'page/wallet';
import {
createDrawerNavigator,
createStackNavigator,
NavigationActions
} from 'react-navigation';
import {
createReduxContainer,
createReactNavigationReduxMiddleware,
createNavigationReducer
} from 'react-navigation-redux-helpers';
import { connect } from 'react-redux';
import {
AppState,
BackHandler,
Linking,
NativeModules,
TextInput,
ToastAndroid
} from 'react-native';
import { selectDrawerStack } from 'redux/selectors/drawer';
import { SETTINGS, doDismissToast, doToast, selectToast } from 'lbry-redux';
import {
doGetSync,
doUserCheckEmailVerified,
doUserEmailVerify,
doUserEmailVerifyFailure,
selectEmailToVerify,
selectEmailVerifyIsPending,
selectEmailVerifyErrorMessage,
selectUser
} from 'lbryinc';
import { makeSelectClientSetting } from 'redux/selectors/settings';
import { decode as atob } from 'base-64';
import { dispatchNavigateBack, dispatchNavigateToUri } from 'utils/helper';
import AsyncStorage from '@react-native-community/async-storage';
import Colors from 'styles/colors';
import Constants from 'constants';
import Icon from 'react-native-vector-icons/FontAwesome5';
import NavigationButton from 'component/navigationButton';
import discoverStyle from 'styles/discover';
import searchStyle from 'styles/search';
import SearchRightHeaderIcon from 'component/searchRightHeaderIcon';
const menuNavigationButton = (navigation) => <NavigationButton
name="bars"
size={24}
style={discoverStyle.drawerMenuButton}
iconStyle={discoverStyle.drawerHamburger}
onPress={() => navigation.openDrawer() } />
const discoverStack = createStackNavigator({
Discover: {
screen: DiscoverPage,
navigationOptions: ({ navigation }) => ({
title: 'Explore',
header: null
}),
},
File: {
screen: FilePage,
navigationOptions: ({ navigation }) => ({
header: null
})
},
Search: {
screen: SearchPage,
navigationOptions: ({ navigation }) => ({
header: null
})
}
}, {
headerMode: 'screen',
transitionConfig: () => ({ screenInterpolator: () => null }),
});
discoverStack.navigationOptions = ({ navigation }) => {
let drawerLockMode = 'unlocked';
/*if (navigation.state.index > 0) {
drawerLockMode = 'locked-closed';
}*/
return {
drawerLockMode
};
};
const walletStack = createStackNavigator({
Wallet: {
screen: WalletPage,
navigationOptions: ({ navigation }) => ({
title: 'Wallet',
header: null
})
},
TransactionHistory: {
screen: TransactionHistoryPage,
navigationOptions: {
title: 'Transaction History',
header: null
}
}
}, {
headerMode: 'screen',
transitionConfig: () => ({ screenInterpolator: () => null }),
});
const drawer = createDrawerNavigator({
DiscoverStack: { screen: discoverStack, navigationOptions: {
title: 'Explore', drawerIcon: ({ tintColor }) => <Icon name="home" size={20} style={{ color: tintColor }} />
}},
TrendingStack: { screen: TrendingPage, navigationOptions: {
title: 'Trending', drawerIcon: ({ tintColor }) => <Icon name="fire" size={20} style={{ color: tintColor }} />
}},
MySubscriptionsStack: { screen: SubscriptionsPage, navigationOptions: {
title: 'Subscriptions', drawerIcon: ({ tintColor }) => <Icon name="heart" solid={true} size={20} style={{ color: tintColor }} />
}},
WalletStack: { screen: walletStack, navigationOptions: {
title: 'Wallet', drawerIcon: ({ tintColor }) => <Icon name="wallet" size={20} style={{ color: tintColor }} />
}},
Rewards: { screen: RewardsPage, navigationOptions: {
drawerIcon: ({ tintColor }) => <Icon name="award" size={20} style={{ color: tintColor }} />
}},
MyLBRYStack: { screen: DownloadsPage, navigationOptions: {
title: 'Library', drawerIcon: ({ tintColor }) => <Icon name="download" size={20} style={{ color: tintColor }} />
}},
Settings: { screen: SettingsPage, navigationOptions: {
drawerLockMode: 'locked-closed',
drawerIcon: ({ tintColor }) => <Icon name="cog" size={20} style={{ color: tintColor }} />
}},
About: { screen: AboutPage, navigationOptions: {
drawerLockMode: 'locked-closed',
drawerIcon: ({ tintColor }) => <Icon name="info" size={20} style={{ color: tintColor }} />
}}
}, {
drawerWidth: 300,
headerMode: 'none',
contentComponent: DrawerContent,
contentOptions: {
activeTintColor: Colors.LbryGreen,
labelStyle: discoverStyle.menuText
}
});
const mainStackNavigator = new createStackNavigator({
FirstRun: {
screen: FirstRunScreen,
navigationOptions: {
drawerLockMode: 'locked-closed'
}
},
Splash: {
screen: SplashScreen,
navigationOptions: {
drawerLockMode: 'locked-closed'
}
},
Main: {
screen: drawer
},
Verification: {
screen: VerificationScreen,
navigationOptions: {
drawerLockMode: 'locked-closed'
}
}
}, {
headerMode: 'none'
});
export const AppNavigator = mainStackNavigator;
export const navigatorReducer = createNavigationReducer(AppNavigator);
export const reactNavigationMiddleware = createReactNavigationReduxMiddleware(
state => state.nav,
);
const App = createReduxContainer(mainStackNavigator);
const appMapStateToProps = (state) => ({
state: state.nav,
});
const ReduxAppNavigator = connect(appMapStateToProps)(App);
class AppWithNavigationState extends React.Component {
static supportedDisplayTypes = ['toast'];
constructor() {
super();
this.emailVerifyCheckInterval = null;
this.state = {
emailVerifyDone: false,
verifyPending: false
};
}
componentWillMount() {
AppState.addEventListener('change', this._handleAppStateChange);
BackHandler.addEventListener('hardwareBackPress', function() {
const { dispatch, nav, drawerStack } = this.props;
// There should be a better way to check this
if (nav.routes.length > 0) {
if (nav.routes[0].routeName === 'Main') {
const mainRoute = nav.routes[0];
if (mainRoute.index > 0 ||
mainRoute.routes[0].index > 0 /* Discover stack index */ ||
mainRoute.routes[4].index > 0 /* Wallet stack index */ ||
mainRoute.index >= 5 /* Settings and About screens */) {
dispatchNavigateBack(dispatch, nav, drawerStack);
return true;
}
}
}
return false;
}.bind(this));
}
componentDidMount() {
this.emailVerifyCheckInterval = setInterval(() => this.checkEmailVerification(), 5000);
Linking.addEventListener('url', this._handleUrl);
}
checkEmailVerification = () => {
const { dispatch } = this.props;
AsyncStorage.getItem(Constants.KEY_EMAIL_VERIFY_PENDING).then(pending => {
this.setState({ verifyPending: ('true' === pending) });
if ('true' === pending) {
dispatch(doUserCheckEmailVerified());
}
});
}
componentWillUnmount() {
AppState.removeEventListener('change', this._handleAppStateChange);
BackHandler.removeEventListener('hardwareBackPress');
Linking.removeEventListener('url', this._handleUrl);
}
componentDidUpdate() {
const { dispatch, user } = this.props;
if (this.state.verifyPending && this.emailVerifyCheckInterval > 0 && user && user.has_verified_email) {
clearInterval(this.emailVerifyCheckInterval);
AsyncStorage.setItem(Constants.KEY_EMAIL_VERIFY_PENDING, 'false');
this.setState({ verifyPending: false });
ToastAndroid.show('Your email address was successfully verified.', ToastAndroid.LONG);
// upon successful email verification, do wallet sync (if password has been set)
NativeModules.UtilityModule.getSecureValue(Constants.KEY_FIRST_RUN_PASSWORD).then(walletPassword => {
if (walletPassword && walletPassword.trim().length > 0) {
dispatch(doGetSync(walletPassword));
}
});
}
}
componentWillUpdate(nextProps) {
const { dispatch } = this.props;
const {
toast,
emailToVerify,
emailVerifyPending,
emailVerifyErrorMessage,
user
} = nextProps;
if (toast) {
const { message } = toast;
let currentDisplayType;
if (!currentDisplayType && message) {
// default to toast if no display type set and there is a message specified
currentDisplayType = 'toast';
}
if ('toast' === currentDisplayType) {
ToastAndroid.show(message, ToastAndroid.LONG);
}
dispatch(doDismissToast());
}
if (user &&
!emailVerifyPending &&
!this.state.emailVerifyDone &&
(emailToVerify || emailVerifyErrorMessage)) {
AsyncStorage.getItem(Constants.KEY_SHOULD_VERIFY_EMAIL).then(shouldVerify => {
if ('true' === shouldVerify) {
this.setState({ emailVerifyDone: true });
const message = emailVerifyErrorMessage ?
String(emailVerifyErrorMessage) : 'Your email address was successfully verified.';
if (!emailVerifyErrorMessage) {
AsyncStorage.removeItem(Constants.KEY_FIRST_RUN_EMAIL);
}
AsyncStorage.removeItem(Constants.KEY_SHOULD_VERIFY_EMAIL);
dispatch(doToast({ message }));
}
});
}
}
_handleAppStateChange = (nextAppState) => {
const { backgroundPlayEnabled, dispatch } = this.props;
// Check if the app was suspended
if (AppState.currentState && AppState.currentState.match(/inactive|background/)) {
AsyncStorage.getItem('firstLaunchTime').then(start => {
if (start !== null && !isNaN(parseInt(start, 10))) {
// App suspended during first launch?
// If so, this needs to be included as a property when tracking
AsyncStorage.setItem('firstLaunchSuspended', 'true');
}
// Background media
if (backgroundPlayEnabled && NativeModules.BackgroundMedia && window.currentMediaInfo) {
const { title, channel, uri } = window.currentMediaInfo;
NativeModules.BackgroundMedia.showPlaybackNotification(title, channel, uri, false);
}
});
}
if (AppState.currentState && AppState.currentState.match(/active/)) {
if (backgroundPlayEnabled || NativeModules.BackgroundMedia) {
NativeModules.BackgroundMedia.hidePlaybackNotification();
}
}
}
_handleUrl = (evt) => {
const { dispatch, nav } = this.props;
if (evt.url) {
if (evt.url.startsWith('lbry://?verify=')) {
this.setState({ emailVerifyDone: false });
let verification = {};
try {
verification = JSON.parse(atob(evt.url.substring(15)));
} catch (error) {
console.log(error);
}
if (verification.token && verification.recaptcha) {
AsyncStorage.setItem(Constants.KEY_SHOULD_VERIFY_EMAIL, 'true');
try {
dispatch(doUserEmailVerify(verification.token, verification.recaptcha));
} catch (error) {
const message = 'Invalid Verification Token';
dispatch(doUserEmailVerifyFailure(message));
dispatch(doToast({ message }));
}
} else {
dispatch(doToast({
message: 'Invalid Verification URI',
}));
}
} else {
dispatchNavigateToUri(dispatch, nav, evt.url);
}
}
}
render() {
return <ReduxAppNavigator />;
}
}
const mapStateToProps = state => ({
backgroundPlayEnabled: makeSelectClientSetting(SETTINGS.BACKGROUND_PLAY_ENABLED)(state),
keepDaemonRunning: makeSelectClientSetting(SETTINGS.KEEP_DAEMON_RUNNING)(state),
nav: state.nav,
toast: selectToast(state),
drawerStack: selectDrawerStack(state),
emailToVerify: selectEmailToVerify(state),
emailVerifyPending: selectEmailVerifyIsPending(state),
emailVerifyErrorMessage: selectEmailVerifyErrorMessage(state),
showNsfw: makeSelectClientSetting(SETTINGS.SHOW_NSFW)(state),
user: selectUser(state)
});
export default connect(mapStateToProps)(AppWithNavigationState);

View file

@ -1,7 +0,0 @@
import { connect } from 'react-redux';
import { doToast } from 'lbry-redux';
import Address from './view';
export default connect(null, {
doToast,
})(Address);

View file

@ -1,28 +0,0 @@
// @flow
import * as React from 'react';
import { Clipboard, Text, View } from 'react-native';
import Button from '../button';
import walletStyle from '../../styles/wallet';
type Props = {
address: string,
doToast: ({ message: string }) => void,
};
export default class Address extends React.PureComponent<Props> {
render() {
const { address, doToast, style } = this.props;
return (
<View style={[walletStyle.row, style]}>
<Text selectable={true} numberOfLines={1} style={walletStyle.address}>{address || ''}</Text>
<Button icon={'clipboard'} style={walletStyle.button} onPress={() => {
Clipboard.setString(address);
doToast({
message: 'Address copied',
});
}} />
</View>
);
}
}

View file

@ -1,4 +0,0 @@
import { connect } from 'react-redux';
import Button from './view';
export default connect(null, null)(Button);

View file

@ -1,58 +0,0 @@
import React from 'react';
import { Text, TouchableOpacity } from 'react-native';
import buttonStyle from '../../styles/button';
import Colors from '../../styles/colors';
import Icon from 'react-native-vector-icons/FontAwesome5';
export default class Button extends React.PureComponent {
render() {
const {
disabled,
style,
text,
icon,
iconColor,
solid,
theme,
onPress,
onLayout
} = this.props;
let styles = [buttonStyle.button, buttonStyle.row];
if (style) {
if (style.length) {
styles = styles.concat(style);
} else {
styles.push(style);
}
}
if (disabled) {
styles.push(buttonStyle.disabled);
}
const textStyles = [buttonStyle.text];
if (icon && icon.trim().length > 0) {
textStyles.push(buttonStyle.textWithIcon);
}
if (theme === 'light') {
textStyles.push(buttonStyle.textDark);
} else {
// Dark background, default
textStyles.push(buttonStyle.textLight);
}
let renderIcon = (<Icon name={icon} size={18} color={iconColor ? iconColor : ('light' === theme ? Colors.DarkGrey : Colors.White)} />);
if (solid) {
renderIcon = (<Icon name={icon} size={18} color={iconColor ? iconColor : ('light' === theme ? Colors.DarkGrey : Colors.White)} solid />);
}
return (
<TouchableOpacity disabled={disabled} style={styles} onPress={onPress} onLayout={onLayout}>
{icon && renderIcon}
{text && (text.trim().length > 0) && <Text style={textStyles}>{text}</Text>}
</TouchableOpacity>
);
}
};

View file

@ -1,4 +0,0 @@
import { connect } from 'react-redux';
import CategoryList from './view';
export default connect(null, null)(CategoryList);

View file

@ -1,39 +0,0 @@
import React from 'react';
import NavigationActions from 'react-navigation';
import { FlatList, Text, View } from 'react-native';
import { normalizeURI } from 'lbry-redux';
import FileItem from '/component/fileItem';
import discoverStyle from 'styles/discover';
class CategoryList extends React.PureComponent {
render() {
const { category, categoryMap, navigation } = this.props;
return (
<FlatList
style={discoverStyle.horizontalScrollContainer}
contentContainerStyle={discoverStyle.horizontalScrollPadding}
initialNumToRender={3}
maxToRenderPerBatch={3}
removeClippedSubviews={true}
renderItem={ ({item}) => (
<FileItem
style={discoverStyle.fileItem}
mediaStyle={discoverStyle.fileItemMedia}
key={item}
uri={normalizeURI(item)}
navigation={navigation}
showDetails={true}
compactView={false} />
)
}
horizontal={true}
showsHorizontalScrollIndicator={false}
data={categoryMap[category]}
keyExtractor={(item, index) => item}
/>
);
}
}
export default CategoryList;

View file

@ -1,26 +0,0 @@
import { connect } from 'react-redux';
import { doToast } from 'lbry-redux';
import {
doClaimRewardType,
doClaimRewardClearError,
makeSelectClaimRewardError,
makeSelectIsRewardClaimPending,
rewards as REWARD_TYPES
} from 'lbryinc';
import CustomRewardCard from './view';
const select = state => ({
rewardIsPending: makeSelectIsRewardClaimPending()(state, {
reward_type: REWARD_TYPES.TYPE_REWARD_CODE,
}),
error: makeSelectClaimRewardError()(state, { reward_type: REWARD_TYPES.TYPE_REWARD_CODE }),
});
const perform = dispatch => ({
claimReward: reward => dispatch(doClaimRewardType(reward.reward_type, true)),
clearError: reward => dispatch(doClaimRewardClearError(reward)),
notify: data => dispatch(doToast(data)),
submitRewardCode: code => dispatch(doClaimRewardType(REWARD_TYPES.TYPE_REWARD_CODE, { params: { code } }))
});
export default connect(select, perform)(CustomRewardCard);

View file

@ -1,88 +0,0 @@
// @flow
import React from 'react';
import { ActivityIndicator, Keyboard, Text, TextInput, TouchableOpacity, View } from 'react-native';
import Colors from '../../styles/colors';
import Icon from 'react-native-vector-icons/FontAwesome5';
import Button from '../button';
import Link from '../link';
import rewardStyle from '../../styles/reward';
class CustomRewardCard extends React.PureComponent<Props> {
state = {
claimStarted: false,
rewardCode: ''
};
componentWillReceiveProps(nextProps) {
const { error, rewardIsPending } = nextProps;
const { clearError, notify } = this.props;
if (this.state.claimStarted && !rewardIsPending) {
if (error && error.trim().length > 0) {
notify({ message: error });
} else {
notify({ message: 'Reward successfully claimed!' });
this.setState({ rewardCode: '' });
}
this.setState({ claimStarted: false });
}
}
onClaimPress = () => {
const { canClaim, notify, showVerification, submitRewardCode } = this.props;
const { rewardCode } = this.state;
Keyboard.dismiss();
if (!canClaim) {
if (showVerification) {
showVerification();
}
notify({ message: 'Unfortunately, you are not eligible to claim this reward at this time.' });
return;
}
if (!rewardCode || rewardCode.trim().length === 0) {
notify({ message: 'Please enter a reward code to claim.' });
return;
}
this.setState({ claimStarted: true }, () => {
submitRewardCode(rewardCode);
});
}
render() {
const { canClaim, rewardIsPending } = this.props;
return (
<View style={[rewardStyle.rewardCard, rewardStyle.row]} >
<View style={rewardStyle.leftCol}>
{rewardIsPending && <ActivityIndicator size="small" color={Colors.LbryGreen} />}
</View>
<View style={rewardStyle.midCol}>
<Text style={rewardStyle.rewardTitle}>Custom Code</Text>
<Text style={rewardStyle.rewardDescription}>Are you a supermodel or rockstar that received a custom reward code? Claim it here.</Text>
<View>
<TextInput style={rewardStyle.customCodeInput}
placeholder={"0123abc"}
onChangeText={text => this.setState({ rewardCode: text })}
value={this.state.rewardCode} />
<Button style={rewardStyle.redeemButton}
text={"Redeem"}
disabled={(!this.state.rewardCode || this.state.rewardCode.trim().length === 0 || rewardIsPending)}
onPress={() => {
if (!rewardIsPending) { this.onClaimPress(); }
}} />
</View>
</View>
<View style={rewardStyle.rightCol}>
<Text style={rewardStyle.rewardAmount}>?</Text>
<Text style={rewardStyle.rewardCurrency}>LBC</Text>
</View>
</View>
);
}
};
export default CustomRewardCard;

View file

@ -1,16 +0,0 @@
import { connect } from 'react-redux';
import { makeSelectDateForUri } from 'lbry-redux';
import DateTime from './view';
const select = (state, props) => ({
date: props.date || makeSelectDateForUri(props.uri)(state),
});
const perform = dispatch => ({
fetchBlock: height => dispatch(doFetchBlock(height)),
});
export default connect(
select,
perform
)(DateTime);

View file

@ -1,55 +0,0 @@
// @flow
import React from 'react';
import moment from 'moment';
import { View, Text } from 'react-native';
type Props = {
date?: number,
timeAgo?: boolean,
formatOptions: {},
show?: string,
};
class DateTime extends React.PureComponent<Props> {
static SHOW_DATE = 'date';
static SHOW_TIME = 'time';
static SHOW_BOTH = 'both';
static defaultProps = {
formatOptions: {
month: 'long',
day: 'numeric',
year: 'numeric',
},
};
render() {
const { date, formatOptions, timeAgo, style, textStyle } = this.props;
const show = this.props.show || DateTime.SHOW_BOTH;
const locale = 'en-US'; // default to en-US until we get a working i18n module for RN
if (timeAgo) {
return date ? <View style={style}><Text style={textStyle}>{moment(date).from(moment())}</Text></View> : null;
}
// TODO: formatOptions not working as expected in RN
// date.toLocaleDateString([locale, 'en-US'], formatOptions)}
return (
<View style={style}>
<Text style={textStyle}>
{date &&
(show === DateTime.SHOW_BOTH || show === DateTime.SHOW_DATE) &&
moment(date).format('MMMM D, YYYY')}
{show === DateTime.SHOW_BOTH && ' '}
{date &&
(show === DateTime.SHOW_BOTH || show === DateTime.SHOW_TIME) &&
date.toLocaleTimeString()}
{!date && '...'}
</Text>
</View>
);
}
}
export default DateTime;

View file

@ -1,4 +0,0 @@
import { connect } from 'react-redux';
import DrawerContent from './view';
export default connect()(DrawerContent);

View file

@ -1,38 +0,0 @@
import React from 'react';
import { DrawerItems, SafeAreaView } from 'react-navigation';
import { ScrollView } from 'react-native';
import Constants from 'constants';
import discoverStyle from 'styles/discover';
class DrawerContent extends React.PureComponent {
render() {
const props = this.props;
const { navigation, onItemPress } = props;
return (
<ScrollView>
<SafeAreaView style={discoverStyle.drawerContentContainer} forceInset={{ top: 'always', horizontal: 'never' }}>
<DrawerItems
{...props}
onItemPress={(route) => {
const { routeName } = route.route;
if (Constants.FULL_ROUTE_NAME_DISCOVER === routeName) {
navigation.navigate({ routeName: Constants.DRAWER_ROUTE_DISCOVER });
return;
}
if (Constants.FULL_ROUTE_NAME_WALLET === routeName) {
navigation.navigate({ routeName: Constants.DRAWER_ROUTE_WALLET });
return;
}
onItemPress(route);
}}
/>
</SafeAreaView>
</ScrollView>
);
}
}
export default DrawerContent;

View file

@ -1,25 +0,0 @@
import { connect } from 'react-redux';
import {
doPurchaseUri,
makeSelectFileInfoForUri,
makeSelectDownloadingForUri,
makeSelectLoadingForUri,
} from 'lbry-redux';
import { doFetchCostInfoForUri, makeSelectCostInfoForUri } from 'lbryinc';
import { doStartDownload } from 'redux/actions/file';
import FileDownloadButton from './view';
const select = (state, props) => ({
fileInfo: makeSelectFileInfoForUri(props.uri)(state),
downloading: makeSelectDownloadingForUri(props.uri)(state),
costInfo: makeSelectCostInfoForUri(props.uri)(state),
loading: makeSelectLoadingForUri(props.uri)(state),
});
const perform = dispatch => ({
purchaseUri: (uri, costInfo, saveFile) => dispatch(doPurchaseUri(uri, costInfo, saveFile)),
restartDownload: (uri, outpoint) => dispatch(doStartDownload(uri, outpoint)),
fetchCostInfo: uri => dispatch(doFetchCostInfoForUri(uri)),
});
export default connect(select, perform)(FileDownloadButton);

View file

@ -1,103 +0,0 @@
import React from 'react';
import { NativeModules, Text, View, TouchableOpacity } from 'react-native';
import Button from '../button';
import fileDownloadButtonStyle from 'styles/fileDownloadButton';
class FileDownloadButton extends React.PureComponent {
componentDidMount() {
const { costInfo, fetchCostInfo, uri } = this.props;
if (costInfo === undefined) {
fetchCostInfo(uri);
}
}
componentWillReceiveProps(nextProps) {
//this.checkAvailability(nextProps.uri);
//this.restartDownload(nextProps);
}
restartDownload(props) {
const { downloading, fileInfo, uri, restartDownload } = props;
if (
!downloading &&
fileInfo &&
!fileInfo.completed &&
fileInfo.written_bytes !== false &&
fileInfo.written_bytes < fileInfo.total_bytes
) {
restartDownload(uri, fileInfo.outpoint);
}
}
render() {
const {
fileInfo,
downloading,
uri,
purchaseUri,
costInfo,
isPlayable,
isViewable,
onPlay,
onView,
loading,
doPause,
style,
openFile,
onButtonLayout,
} = this.props;
if ((fileInfo && !fileInfo.stopped) || loading || downloading) {
const progress =
fileInfo && fileInfo.written_bytes ? fileInfo.written_bytes / fileInfo.total_bytes * 100 : 0,
label = fileInfo ? progress.toFixed(0) + '% complete' : 'Connecting...';
return (
<View style={[style, fileDownloadButtonStyle.container]}>
<View style={{ width: `${progress}%`, backgroundColor: '#ff0000', position: 'absolute', left: 0, top: 0 }}></View>
<Text style={fileDownloadButtonStyle.text}>{label}</Text>
</View>
);
} else if (!fileInfo && !downloading) {
if (!costInfo) {
return (
<View style={[style, fileDownloadButtonStyle.container]}>
<Text style={fileDownloadButtonStyle.text}>Fetching cost info...</Text>
</View>
);
}
return (
<Button icon={isPlayable ? 'play' : null}
text={(isPlayable ? 'Play' : (isViewable ? 'View' : 'Download'))}
onLayout={onButtonLayout}
style={[style, fileDownloadButtonStyle.container]} onPress={() => {
if (NativeModules.Firebase) {
NativeModules.Firebase.track('purchase_uri', { uri: uri });
}
purchaseUri(uri, costInfo, !isPlayable);
if (NativeModules.UtilityModule) {
NativeModules.UtilityModule.checkDownloads();
}
if (isPlayable && onPlay) {
this.props.onPlay();
}
if (isViewable && onView) {
this.props.onView();
}
}} />
);
} else if (fileInfo && fileInfo.download_path) {
return (
<TouchableOpacity onLayout={onButtonLayout}
style={[style, fileDownloadButtonStyle.container]} onPress={openFile}>
<Text style={fileDownloadButtonStyle.text}>{isViewable ? 'View' : 'Open'}</Text>
</TouchableOpacity>
);
}
return null;
}
}
export default FileDownloadButton;

View file

@ -1,32 +0,0 @@
import { connect } from 'react-redux';
import {
doResolveUri,
makeSelectClaimForUri,
makeSelectMetadataForUri,
makeSelectFileInfoForUri,
makeSelectThumbnailForUri,
makeSelectTitleForUri,
makeSelectIsUriResolving,
makeSelectClaimIsNsfw
} from 'lbry-redux';
import { selectRewardContentClaimIds } from 'lbryinc';
import { selectShowNsfw } from 'redux/selectors/settings';
import FileItem from './view';
const select = (state, props) => ({
claim: makeSelectClaimForUri(props.uri)(state),
fileInfo: makeSelectFileInfoForUri(props.uri)(state),
metadata: makeSelectMetadataForUri(props.uri)(state),
rewardedContentClaimIds: selectRewardContentClaimIds(state, props),
isResolvingUri: makeSelectIsUriResolving(props.uri)(state),
obscureNsfw: !selectShowNsfw(state),
thumbnail: makeSelectThumbnailForUri(props.uri)(state),
title: makeSelectTitleForUri(props.uri)(state),
nsfw: makeSelectClaimIsNsfw(props.uri)(state),
});
const perform = dispatch => ({
resolveUri: uri => dispatch(doResolveUri(uri)),
});
export default connect(select, perform)(FileItem);

View file

@ -1,104 +0,0 @@
import React from 'react';
import { normalizeURI } from 'lbry-redux';
import { NavigationActions } from 'react-navigation';
import { NativeModules, Text, View, TouchableOpacity } from 'react-native';
import { navigateToUri } from 'utils/helper';
import Colors from 'styles/colors';
import DateTime from 'component/dateTime';
import FileItemMedia from 'component/fileItemMedia';
import FilePrice from 'component/filePrice';
import Icon from 'react-native-vector-icons/FontAwesome5';
import Link from 'component/link';
import NsfwOverlay from 'component/nsfwOverlay';
import discoverStyle from 'styles/discover';
class FileItem extends React.PureComponent {
constructor(props) {
super(props);
}
componentWillMount() {
this.resolve(this.props);
}
componentWillReceiveProps(nextProps) {
this.resolve(nextProps);
}
resolve(props) {
const { isResolvingUri, resolveUri, claim, uri } = props;
if (!isResolvingUri && claim === undefined && uri) {
resolveUri(uri);
}
}
navigateToFileUri = () => {
const { navigation, uri } = this.props;
const normalizedUri = normalizeURI(uri);
if (NativeModules.Firebase) {
NativeModules.Firebase.track('explore_click', { uri: normalizedUri });
}
navigateToUri(navigation, normalizedUri);
}
render() {
const {
claim,
title,
thumbnail,
fileInfo,
metadata,
isResolvingUri,
rewardedContentClaimIds,
style,
mediaStyle,
navigation,
showDetails,
compactView,
titleBeforeThumbnail
} = this.props;
const uri = normalizeURI(this.props.uri);
const obscureNsfw = this.props.obscureNsfw && metadata && metadata.nsfw;
const isRewardContent = claim && rewardedContentClaimIds.includes(claim.claim_id);
const channelName = claim ? claim.channel_name : null;
const channelClaimId = claim && claim.value && claim.value.publisherSignature && claim.value.publisherSignature.certificateId;
const fullChannelUri = channelClaimId ? `${channelName}#${channelClaimId}` : channelName;
const height = claim ? claim.height : null;
return (
<View style={style}>
<TouchableOpacity style={discoverStyle.container} onPress={this.navigateToFileUri}>
{!compactView && titleBeforeThumbnail && <Text numberOfLines={1} style={[discoverStyle.fileItemName, discoverStyle.rewardTitle]}>{title}</Text>}
<FileItemMedia title={title}
thumbnail={thumbnail}
blurRadius={obscureNsfw ? 15 : 0}
resizeMode="cover"
isResolvingUri={isResolvingUri}
style={mediaStyle} />
{(!compactView && fileInfo && fileInfo.completed && fileInfo.download_path) &&
<Icon style={discoverStyle.downloadedIcon} solid={true} color={Colors.NextLbryGreen} name={"folder"} size={16} />}
{(!compactView && (!fileInfo || !fileInfo.completed || !fileInfo.download_path)) &&
<FilePrice uri={uri} style={discoverStyle.filePriceContainer} textStyle={discoverStyle.filePriceText} />}
{!compactView && <View style={isRewardContent ? discoverStyle.rewardTitleContainer : null}>
<Text numberOfLines={1} style={[discoverStyle.fileItemName, discoverStyle.rewardTitle]}>{title}</Text>
{isRewardContent && <Icon style={discoverStyle.rewardIcon} name="award" size={14} />}
</View>}
{(!compactView && showDetails) &&
<View style={discoverStyle.detailsRow}>
{channelName &&
<Link style={discoverStyle.channelName} text={channelName} onPress={() => {
navigateToUri(navigation, normalizeURI(fullChannelUri));
}} />}
<DateTime style={discoverStyle.dateTime} textStyle={discoverStyle.dateTimeText} timeAgo uri={uri} />
</View>}
</TouchableOpacity>
{obscureNsfw && <NsfwOverlay onPress={() => navigation.navigate({ routeName: 'Settings', key: 'settingsPage' })} />}
</View>
);
}
}
export default FileItem;

View file

@ -1,7 +0,0 @@
import { connect } from 'react-redux';
import FileItemMedia from './view';
const select = state => ({});
const perform = dispatch => ({});
export default connect(select, perform)(FileItemMedia);

View file

@ -1,108 +0,0 @@
import React from 'react';
import { ActivityIndicator, Image, Text, View } from 'react-native';
import Colors from 'styles/colors';
import FastImage from 'react-native-fast-image'
import fileItemMediaStyle from 'styles/fileItemMedia';
class FileItemMedia extends React.PureComponent {
static AUTO_THUMB_STYLES = [
fileItemMediaStyle.autothumbPurple,
fileItemMediaStyle.autothumbRed,
fileItemMediaStyle.autothumbPink,
fileItemMediaStyle.autothumbIndigo,
fileItemMediaStyle.autothumbBlue,
fileItemMediaStyle.autothumbLightBlue,
fileItemMediaStyle.autothumbCyan,
fileItemMediaStyle.autothumbTeal,
fileItemMediaStyle.autothumbGreen,
fileItemMediaStyle.autothumbYellow,
fileItemMediaStyle.autothumbOrange,
];
state: {
imageLoadFailed: false
};
componentWillMount() {
this.setState({
autoThumbStyle:
FileItemMedia.AUTO_THUMB_STYLES[
Math.floor(Math.random() * FileItemMedia.AUTO_THUMB_STYLES.length)
],
});
}
getFastImageResizeMode(resizeMode) {
switch (resizeMode) {
case "contain":
return FastImage.resizeMode.contain;
case "stretch":
return FastImage.resizeMode.stretch;
case "center":
return FastImage.resizeMode.center;
default:
return FastImage.resizeMode.cover;
}
}
isThumbnailValid = (thumbnail) => {
if (!thumbnail || ((typeof thumbnail) !== 'string')) {
return false;
}
if (thumbnail.substring(0, 7) != 'http://' && thumbnail.substring(0, 8) != 'https://') {
return false;
}
return true;
}
render() {
let style = this.props.style;
const { blurRadius, isResolvingUri, thumbnail, title, resizeMode } = this.props;
const atStyle = this.state.autoThumbStyle;
if (this.isThumbnailValid(thumbnail) && !this.state.imageLoadFailed) {
if (style == null) {
style = fileItemMediaStyle.thumbnail;
}
if (blurRadius > 0) {
// No blur radius support in FastImage yet
return (
<Image
source={{uri: thumbnail}}
blurRadius={blurRadius}
resizeMode={resizeMode ? resizeMode : "cover"}
style={style}
/>);
}
return (
<FastImage
source={{uri: thumbnail}}
onError={() => this.setState({ imageLoadFailed: true })}
resizeMode={this.getFastImageResizeMode(resizeMode)}
style={style}
/>
);
}
return (
<View style={[style ? style : fileItemMediaStyle.autothumb, atStyle]}>
{isResolvingUri && (
<View style={fileItemMediaStyle.resolving}>
<ActivityIndicator color={Colors.White} size={"large"} />
<Text style={fileItemMediaStyle.text}>Resolving...</Text>
</View>
)}
{!isResolvingUri && <Text style={fileItemMediaStyle.autothumbText}>{title &&
title
.replace(/\s+/g, '')
.substring(0, Math.min(title.replace(' ', '').length, 5))
.toUpperCase()}</Text>}
</View>
);
}
}
export default FileItemMedia;

View file

@ -1,11 +0,0 @@
import { connect } from 'react-redux';
import FileList from './view';
import { selectClaimsById } from 'lbry-redux';
const select = state => ({
claimsById: selectClaimsById(state),
});
const perform = dispatch => ({});
export default connect(select, perform)(FileList);

View file

@ -1,196 +0,0 @@
// @flow
import * as React from 'react';
import { buildURI } from 'lbry-redux';
import { FlatList } from 'react-native';
import FileItem from 'component/fileItem';
import fileListStyle from 'styles/fileList';
// In the future, all Flow types need to be specified in a common source (lbry-redux, perhaps?)
type FileInfo = {
name: string,
channelName: ?string,
pending?: boolean,
channel_claim_id: string,
value?: {
publisherSignature: {
certificateId: string,
},
},
metadata: {
publisherSignature: {
certificateId: string,
},
},
};
type Props = {
hideFilter: boolean,
sortByHeight?: boolean,
claimsById: Array<{}>,
fileInfos: Array<FileInfo>,
checkPending?: boolean,
};
type State = {
sortBy: string,
};
class FileList extends React.PureComponent<Props, State> {
static defaultProps = {
hideFilter: false,
};
constructor(props: Props) {
super(props);
this.state = {
sortBy: 'dateNew',
};
(this: any).handleSortChanged = this.handleSortChanged.bind(this);
this.sortFunctions = {
dateNew: fileInfos =>
this.props.sortByHeight
? fileInfos.slice().sort((fileInfo1, fileInfo2) => {
if (fileInfo1.pending) {
return -1;
}
const height1 = this.props.claimsById[fileInfo1.claim_id]
? this.props.claimsById[fileInfo1.claim_id].height
: 0;
const height2 = this.props.claimsById[fileInfo2.claim_id]
? this.props.claimsById[fileInfo2.claim_id].height
: 0;
if (height1 > height2) {
return -1;
} else if (height1 < height2) {
return 1;
}
return 0;
})
: [...fileInfos].reverse(),
dateOld: fileInfos =>
this.props.sortByHeight
? fileInfos.slice().sort((fileInfo1, fileInfo2) => {
const height1 = this.props.claimsById[fileInfo1.claim_id]
? this.props.claimsById[fileInfo1.claim_id].height
: 999999;
const height2 = this.props.claimsById[fileInfo2.claim_id]
? this.props.claimsById[fileInfo2.claim_id].height
: 999999;
if (height1 < height2) {
return -1;
} else if (height1 > height2) {
return 1;
}
return 0;
})
: fileInfos,
title: fileInfos =>
fileInfos.slice().sort((fileInfo1, fileInfo2) => {
const getFileTitle = fileInfo => {
const { value, metadata, name, claim_name: claimName } = fileInfo;
if (metadata) {
// downloaded claim
return metadata.title || claimName;
} else if (value) {
// published claim
const { title } = value.stream.metadata;
return title || name;
}
// Invalid claim
return '';
};
const title1 = getFileTitle(fileInfo1).toLowerCase();
const title2 = getFileTitle(fileInfo2).toLowerCase();
if (title1 < title2) {
return -1;
} else if (title1 > title2) {
return 1;
}
return 0;
}),
filename: fileInfos =>
fileInfos.slice().sort(({ file_name: fileName1 }, { file_name: fileName2 }) => {
const fileName1Lower = fileName1.toLowerCase();
const fileName2Lower = fileName2.toLowerCase();
if (fileName1Lower < fileName2Lower) {
return -1;
} else if (fileName2Lower > fileName1Lower) {
return 1;
}
return 0;
}),
};
}
getChannelSignature = (fileInfo: FileInfo) => {
if (fileInfo.pending) {
return undefined;
}
if (fileInfo.value) {
return fileInfo.value.publisherSignature.certificateId;
}
return fileInfo.channel_claim_id;
};
handleSortChanged(event: SyntheticInputEvent<*>) {
this.setState({
sortBy: event.target.value,
});
}
sortFunctions: {};
render() {
const {
contentContainerStyle,
fileInfos,
hideFilter,
checkPending,
navigation,
onEndReached,
style
} = this.props;
const { sortBy } = this.state;
const items = [];
if (!fileInfos) {
return null;
}
this.sortFunctions[sortBy](fileInfos).forEach(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;
uriParams.contentName = name;
uriParams.claimId = claimId;
const uri = buildURI(uriParams);
items.push(uri);
});
return (
<FlatList
style={style}
contentContainerStyle={contentContainerStyle}
data={items}
onEndReached={onEndReached}
keyExtractor={(item, index) => item}
renderItem={({item}) => (
<FileItem style={fileListStyle.fileItem}
uri={item}
navigation={navigation}
showDetails={true}
compactView={false} />
)} />
);
}
}
export default FileList;

View file

@ -1,29 +0,0 @@
import { connect } from 'react-redux';
import {
doResolveUri,
makeSelectClaimForUri,
makeSelectMetadataForUri,
makeSelectFileInfoForUri,
makeSelectIsUriResolving,
makeSelectTitleForUri,
makeSelectThumbnailForUri,
} from 'lbry-redux';
import { selectShowNsfw } from 'redux/selectors/settings';
import FileListItem from './view';
const select = (state, props) => ({
claim: makeSelectClaimForUri(props.uri)(state),
fileInfo: makeSelectFileInfoForUri(props.uri)(state),
isDownloaded: !!makeSelectFileInfoForUri(props.uri)(state),
metadata: makeSelectMetadataForUri(props.uri)(state),
isResolvingUri: makeSelectIsUriResolving(props.uri)(state),
obscureNsfw: !selectShowNsfw(state),
title: makeSelectTitleForUri(props.uri)(state),
thumbnail: makeSelectThumbnailForUri(props.uri)(state),
});
const perform = dispatch => ({
resolveUri: uri => dispatch(doResolveUri(uri))
});
export default connect(select, perform)(FileListItem);

View file

@ -1,134 +0,0 @@
import React from 'react';
import { normalizeURI, parseURI } from 'lbry-redux';
import {
ActivityIndicator,
Platform,
Text,
TouchableOpacity,
View
} from 'react-native';
import { navigateToUri, formatBytes } from 'utils/helper';
import Colors from 'styles/colors';
import DateTime from 'component/dateTime';
import FileItemMedia from 'component/fileItemMedia';
import Icon from 'react-native-vector-icons/FontAwesome5';
import Link from 'component/link';
import NsfwOverlay from 'component/nsfwOverlay';
import ProgressBar from 'component/progressBar';
import fileListStyle from 'styles/fileList';
class FileListItem extends React.PureComponent {
getStorageForFileInfo = (fileInfo) => {
if (!fileInfo.completed) {
const written = formatBytes(fileInfo.written_bytes);
const total = formatBytes(fileInfo.total_bytes);
return `(${written} / ${total})`;
}
return formatBytes(fileInfo.written_bytes);
}
formatTitle = (title) => {
if (!title) {
return title;
}
return (title.length > 80) ? title.substring(0, 77).trim() + '...' : title;
}
getDownloadProgress = (fileInfo) => {
return Math.ceil((fileInfo.written_bytes / fileInfo.total_bytes) * 100);
}
componentDidMount() {
const { claim, resolveUri, uri } = this.props;
if (!claim) {
resolveUri(uri);
}
}
render() {
const {
claim,
fileInfo,
metadata,
featuredResult,
isResolvingUri,
isDownloaded,
style,
onPress,
navigation,
thumbnail,
title
} = this.props;
const uri = normalizeURI(this.props.uri);
const obscureNsfw = this.props.obscureNsfw && metadata && metadata.nsfw;
const isResolving = !fileInfo && isResolvingUri;
let name, channel, height, channelClaimId, fullChannelUri;
if (claim) {
name = claim.name;
channel = claim.channel_name;
height = claim.height;
channelClaimId = claim.value && claim.value.publisherSignature && claim.value.publisherSignature.certificateId;
fullChannelUri = channelClaimId ? `${channel}#${channelClaimId}` : channel;
}
if (featuredResult && !isResolvingUri && !claim && !title && !name) {
return null;
}
return (
<View style={style}>
<TouchableOpacity style={style} onPress={onPress}>
<FileItemMedia style={fileListStyle.thumbnail}
blurRadius={obscureNsfw ? 15 : 0}
resizeMode="cover"
title={(title || name)}
thumbnail={thumbnail} />
{(fileInfo && fileInfo.completed && fileInfo.download_path) &&
<Icon style={fileListStyle.downloadedIcon} solid={true} color={Colors.NextLbryGreen} name={"folder"} size={16} />}
<View style={fileListStyle.detailsContainer}>
{featuredResult && <Text style={fileListStyle.featuredUri} numberOfLines={1}>{uri}</Text>}
{!title && !name && !channel && isResolving && (
<View>
{(!title && !name) && <Text style={fileListStyle.uri}>{uri}</Text>}
{(!title && !name) && <View style={fileListStyle.row}>
<ActivityIndicator size={"small"} color={featuredResult ? Colors.White : Colors.LbryGreen} />
</View>}
</View>)}
{(title || name) && <Text style={featuredResult ? fileListStyle.featuredTitle : fileListStyle.title}>{this.formatTitle(title) || this.formatTitle(name)}</Text>}
{channel &&
<Link style={fileListStyle.publisher} text={channel} onPress={() => {
navigateToUri(navigation, normalizeURI(fullChannelUri));
}} />}
<View style={fileListStyle.info}>
{(fileInfo && !isNaN(fileInfo.written_bytes) && fileInfo.written_bytes > 0) &&
<Text style={fileListStyle.infoText}>{this.getStorageForFileInfo(fileInfo)}</Text>}
<DateTime style={fileListStyle.publishInfo} textStyle={fileListStyle.infoText} timeAgo uri={uri} />
</View>
{(fileInfo && fileInfo.download_path) &&
<View style={fileListStyle.downloadInfo}>
{!fileInfo.completed &&
<ProgressBar
borderRadius={3}
color={Colors.NextLbryGreen}
height={3}
style={fileListStyle.progress}
progress={this.getDownloadProgress(fileInfo)} />}
</View>
}
</View>
</TouchableOpacity>
{obscureNsfw && <NsfwOverlay onPress={() => navigation.navigate({ routeName: 'Settings', key: 'settingsPage' })} />}
</View>
);
}
}
export default FileListItem;

View file

@ -1,16 +0,0 @@
import { connect } from 'react-redux';
import { makeSelectClaimForUri } from 'lbry-redux';
import { doFetchCostInfoForUri, makeSelectCostInfoForUri, makeSelectFetchingCostInfoForUri } from 'lbryinc';
import FilePrice from './view';
const select = (state, props) => ({
costInfo: makeSelectCostInfoForUri(props.uri)(state),
fetching: makeSelectFetchingCostInfoForUri(props.uri)(state),
claim: makeSelectClaimForUri(props.uri)(state),
});
const perform = dispatch => ({
fetchCostInfo: uri => dispatch(doFetchCostInfoForUri(uri)),
});
export default connect(select, perform)(FilePrice);

View file

@ -1,120 +0,0 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Text, View } from 'react-native';
import { formatCredits, formatFullPrice } from 'lbry-redux';
class CreditAmount extends React.PureComponent {
static propTypes = {
amount: PropTypes.number.isRequired,
precision: PropTypes.number,
isEstimate: PropTypes.bool,
label: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
showFree: PropTypes.bool,
showFullPrice: PropTypes.bool,
showPlus: PropTypes.bool,
look: PropTypes.oneOf(['indicator', 'plain', 'fee']),
};
static defaultProps = {
precision: 2,
label: true,
showFree: false,
look: 'indicator',
showFullPrice: false,
showPlus: false,
};
render() {
const minimumRenderableAmount = Math.pow(10, -1 * this.props.precision);
const { amount, precision, showFullPrice, style } = this.props;
let formattedAmount;
const fullPrice = formatFullPrice(amount, 2);
if (showFullPrice) {
formattedAmount = fullPrice;
} else {
formattedAmount =
amount > 0 && amount < minimumRenderableAmount
? `<${minimumRenderableAmount}`
: formatCredits(amount, precision);
}
let amountText;
if (this.props.showFree && parseFloat(this.props.amount) === 0) {
amountText = 'FREE';
} else {
if (this.props.label) {
const label =
typeof this.props.label === 'string'
? this.props.label
: parseFloat(amount) == 1 ? 'credit' : 'credits';
amountText = `${formattedAmount} ${label}`;
} else {
amountText = formattedAmount;
}
if (this.props.showPlus && amount > 0) {
amountText = `+${amountText}`;
}
}
/*{this.props.isEstimate ? (
<span
className="credit-amount__estimate"
title={__('This is an estimate and does not include data fees')}
>
*
</span>
) : null}*/
return (
<Text style={style}>{amountText}</Text>
);
}
}
class FilePrice extends React.PureComponent {
componentWillMount() {
this.fetchCost(this.props);
}
componentWillReceiveProps(nextProps) {
this.fetchCost(nextProps);
}
fetchCost(props) {
const { costInfo, fetchCostInfo, uri, fetching, claim } = props;
if (costInfo === undefined && !fetching && claim) {
fetchCostInfo(uri);
}
}
render() {
const { costInfo, look = 'indicator', showFullPrice = false, style, textStyle } = this.props;
const isEstimate = costInfo ? !costInfo.includesData : null;
if (!costInfo) {
return (
<View style={style}>
<Text style={textStyle}>???</Text>
</View>
)
}
return (
<View style={style}>
<CreditAmount
style={textStyle}
label={false}
amount={parseFloat(costInfo.cost)}
isEstimate={isEstimate}
showFree
showFullPrice={showFullPrice}>???</CreditAmount>
</View>
);
}
}
export default FilePrice;

View file

@ -1,4 +0,0 @@
import { connect } from 'react-redux';
import FileRewardsDriver from './view';
export default connect()(FileRewardsDriver);

View file

@ -1,20 +0,0 @@
import React from 'react';
import { Text, TouchableOpacity } from 'react-native';
import Colors from 'styles/colors';
import Icon from 'react-native-vector-icons/FontAwesome5';
import filePageStyle from 'styles/filePage';
class FileRewardsDriver extends React.PureComponent<Props> {
render() {
const { navigation } = this.props;
return (
<TouchableOpacity style={filePageStyle.rewardDriverCard} onPress={() => navigation.navigate('Rewards')}>
<Icon name="award" size={16} style={filePageStyle.rewardIcon} />
<Text style={filePageStyle.rewardDriverText}>Earn some credits to access this content.</Text>
</TouchableOpacity>
);
}
}
export default FileRewardsDriver;

View file

@ -1,14 +0,0 @@
import { connect } from 'react-redux';
import { makeSelectClientSetting } from 'redux/selectors/settings';
import { selectBalance } from 'lbry-redux';
import { selectUnclaimedRewardValue } from 'lbryinc';
import Constants from 'constants';
import FloatingWalletBalance from './view';
const select = state => ({
balance: selectBalance(state),
unclaimedRewardAmount: selectUnclaimedRewardValue(state),
rewardsNotInterested: makeSelectClientSetting(Constants.SETTING_REWARDS_NOT_INTERESTED)(state),
});
export default connect(select, null)(FloatingWalletBalance);

View file

@ -1,38 +0,0 @@
// @flow
import React from 'react';
import { ActivityIndicator, Text, TouchableOpacity, View } from 'react-native';
import { formatCredits } from 'lbry-redux'
import Address from 'component/address';
import Button from 'component/button';
import Colors from 'styles/colors';
import Icon from 'react-native-vector-icons/FontAwesome5';
import floatingButtonStyle from 'styles/floatingButton';
type Props = {
balance: number,
};
class FloatingWalletBalance extends React.PureComponent<Props> {
render() {
const { balance, navigation, rewardsNotInterested, unclaimedRewardAmount } = this.props;
return (
<View style={[floatingButtonStyle.view, floatingButtonStyle.bottomRight]}>
{(!rewardsNotInterested && unclaimedRewardAmount > 0) &&
<TouchableOpacity style={floatingButtonStyle.pendingContainer}
onPress={() => navigation && navigation.navigate({ routeName: 'Rewards' })} >
<Icon name="award" size={18} style={floatingButtonStyle.rewardIcon} />
<Text style={floatingButtonStyle.text}>{unclaimedRewardAmount}</Text>
</TouchableOpacity>}
<TouchableOpacity style={floatingButtonStyle.container}
onPress={() => navigation && navigation.navigate({ routeName: 'WalletStack' })}>
{isNaN(balance) && <ActivityIndicator size="small" color={Colors.White} />}
{(!isNaN(balance) || balance === 0) && (
<Text style={floatingButtonStyle.text}>{(formatCredits(parseFloat(balance), 2) + ' LBC')}</Text>)}
</TouchableOpacity>
</View>
);
}
}
export default FloatingWalletBalance;

View file

@ -1,9 +0,0 @@
import { connect } from 'react-redux';
import { doToast } from 'lbry-redux';
import Link from './view';
const perform = dispatch => ({
notify: (data) => dispatch(doToast(data))
});
export default connect(null, perform)(Link);

View file

@ -1,68 +0,0 @@
import React from 'react';
import { Linking, Text, TouchableOpacity } from 'react-native';
export default class Link extends React.PureComponent {
constructor(props) {
super(props)
this.state = {
tappedStyle: false,
}
this.addTappedStyle = this.addTappedStyle.bind(this)
}
handlePress = () => {
const { error, href, navigation, notify } = this.props;
if (navigation && href.startsWith('#')) {
navigation.navigate(href.substring(1));
} else {
if (this.props.effectOnTap) this.addTappedStyle();
Linking.openURL(href)
.then(() => setTimeout(() => { this.setState({ tappedStyle: false }); }, 2000))
.catch(err => {
notify({ message: error, isError: true })
this.setState({tappedStyle: false})
}
);
}
}
addTappedStyle() {
this.setState({ tappedStyle: true });
setTimeout(() => { this.setState({ tappedStyle: false }); }, 2000);
}
render() {
const {
ellipsizeMode,
numberOfLines,
onPress,
style,
text
} = this.props;
let styles = [];
if (style) {
if (style.length) {
styles = styles.concat(style);
} else {
styles.push(style);
}
}
if (this.props.effectOnTap && this.state.tappedStyle) {
styles.push(this.props.effectOnTap);
}
return (
<Text
style={styles}
numberOfLines={numberOfLines}
ellipsizeMode={ellipsizeMode}
onPress={onPress ? onPress : this.handlePress}>
{text}
</Text>
);
}
};

View file

@ -1,18 +0,0 @@
import { connect } from 'react-redux';
import { SETTINGS, savePosition } from 'lbry-redux';
import { makeSelectClientSetting } from 'redux/selectors/settings';
import { doSetPlayerVisible } from 'redux/actions/drawer';
import { selectIsPlayerVisible } from 'redux/selectors/drawer';
import MediaPlayer from './view';
const select = state => ({
backgroundPlayEnabled: makeSelectClientSetting(SETTINGS.BACKGROUND_PLAY_ENABLED)(state),
isPlayerVisible: selectIsPlayerVisible(state),
});
const perform = dispatch => ({
savePosition: (claimId, outpoint, position) => dispatch(savePosition(claimId, outpoint, position)),
setPlayerVisible: () => dispatch(doSetPlayerVisible(true)),
});
export default connect(select, perform)(MediaPlayer);

View file

@ -1,472 +0,0 @@
import React from 'react';
import { Lbry } from 'lbry-redux';
import {
AppState,
ActivityIndicator,
DeviceEventEmitter,
NativeModules,
PanResponder,
Text,
View,
ScrollView,
TouchableOpacity
} from 'react-native';
import Colors from 'styles/colors';
import FastImage from 'react-native-fast-image'
import Video from 'react-native-video';
import Icon from 'react-native-vector-icons/FontAwesome5';
import FileItemMedia from 'component/fileItemMedia';
import mediaPlayerStyle from 'styles/mediaPlayer';
const positionSaveInterval = 10
class MediaPlayer extends React.PureComponent {
static ControlsTimeout = 3000;
seekResponder = null;
seekerWidth = 0;
trackingOffset = 0;
tracking = null;
video = null;
constructor(props) {
super(props);
this.state = {
buffering: false,
backgroundPlayEnabled: false,
autoPaused: false,
rate: 1,
volume: 1,
muted: false,
resizeMode: 'contain',
duration: 0.0,
currentTime: 0.0,
paused: !props.autoPlay,
fullscreenMode: false,
areControlsVisible: true,
controlsTimeout: -1,
seekerOffset: 0,
seekerPosition: 0,
firstPlay: true,
seekTimeout: -1
};
}
formatTime(time) {
let str = '';
let minutes = 0, hours = 0, seconds = parseInt(time, 10);
if (seconds > 60) {
minutes = parseInt(seconds / 60, 10);
seconds = seconds % 60;
if (minutes > 60) {
hours = parseInt(minutes / 60, 10);
minutes = minutes % 60;
}
str = (hours > 0 ? this.pad(hours) + ':' : '') + this.pad(minutes) + ':' + this.pad(seconds);
} else {
str = '00:' + this.pad(seconds);
}
return str;
}
pad(value) {
if (value < 10) {
return '0' + String(value);
}
return value;
}
onLoad = (data) => {
this.setState({
duration: data.duration
});
const { position } = this.props;
if (!isNaN(parseFloat(position)) && position > 0) {
this.video.seek(position);
this.setState({ currentTime: position }, () => this.setSeekerPosition(this.calculateSeekerPosition()));
}
if (this.props.onMediaLoaded) {
this.props.onMediaLoaded();
}
}
onProgress = (data) => {
const { savePosition, claim } = this.props;
this.setState({ buffering: false, currentTime: data.currentTime });
if (data.currentTime > 0 && Math.floor(data.currentTime) % positionSaveInterval === 0) {
const { claim_id: claimId, txid, nout } = claim;
savePosition(claimId, `${txid}:${nout}`, data.currentTime);
}
if (!this.state.seeking) {
this.setSeekerPosition(this.calculateSeekerPosition());
}
if (this.state.firstPlay) {
if (this.props.onPlaybackStarted) {
this.props.onPlaybackStarted();
}
this.setState({ firstPlay: false });
this.hidePlayerControls();
}
}
clearControlsTimeout = () => {
if (this.state.controlsTimeout > -1) {
clearTimeout(this.state.controlsTimeout)
}
}
showPlayerControls = () => {
this.clearControlsTimeout();
if (!this.state.areControlsVisible) {
this.setState({ areControlsVisible: true });
}
this.hidePlayerControls();
}
manualHidePlayerControls = () => {
this.clearControlsTimeout();
this.setState({ areControlsVisible: false });
}
hidePlayerControls() {
const player = this;
let timeout = setTimeout(() => {
player.setState({ areControlsVisible: false });
}, MediaPlayer.ControlsTimeout);
player.setState({ controlsTimeout: timeout });
}
togglePlayerControls = () => {
const { setPlayerVisible, isPlayerVisible } = this.props;
if (!isPlayerVisible) {
setPlayerVisible();
}
if (this.state.areControlsVisible) {
this.manualHidePlayerControls();
} else {
this.showPlayerControls();
}
}
togglePlay = () => {
this.showPlayerControls();
this.setState({ paused: !this.state.paused }, this.handlePausedState);
}
handlePausedState = () => {
if (!this.state.paused) {
// onProgress will automatically clear this, so it's fine
this.setState({ buffering: true });
}
}
toggleFullscreenMode = () => {
this.showPlayerControls();
const { onFullscreenToggled } = this.props;
this.setState({ fullscreenMode: !this.state.fullscreenMode }, () => {
if (onFullscreenToggled) {
onFullscreenToggled(this.state.fullscreenMode);
}
});
}
onEnd = () => {
this.setState({ paused: true });
if (this.props.onPlaybackFinished) {
this.props.onPlaybackFinished();
}
this.video.seek(0);
}
setSeekerPosition(position = 0) {
position = this.checkSeekerPosition(position);
this.setState({ seekerPosition: position });
if (!this.state.seeking) {
this.setState({ seekerOffset: position });
}
}
checkSeekerPosition(val = 0) {
if (val < 0) {
val = 0;
} else if (val >= this.seekerWidth) {
return this.seekerWidth;
}
return val;
}
seekTo(time = 0) {
if (time > this.state.duration) {
return;
}
this.video.seek(time);
this.setState({ currentTime: time });
}
initSeeker() {
this.seekResponder = PanResponder.create({
onStartShouldSetPanResponder: (evt, gestureState) => true,
onMoveShouldSetPanResponder: (evt, gestureState) => true,
onPanResponderGrant: (evt, gestureState) => {
this.clearControlsTimeout();
if (this.state.seekTimeout > 0) {
clearTimeout(this.state.seekTimeout);
}
this.setState({ seeking: true });
},
onPanResponderMove: (evt, gestureState) => {
const position = this.state.seekerOffset + gestureState.dx;
this.setSeekerPosition(position);
},
onPanResponderRelease: (evt, gestureState) => {
const time = this.getCurrentTimeForSeekerPosition();
if (time >= this.state.duration) {
this.setState({ paused: true }, this.handlePausedState);
this.onEnd();
} else {
this.seekTo(time);
this.setState({ seekTimeout: setTimeout(() => { this.setState({ seeking: false }); }, 100) });
}
this.hidePlayerControls();
}
});
}
getTrackingOffset() {
return this.state.fullscreenMode ? this.trackingOffset : 0;
}
getCurrentTimeForSeekerPosition() {
return this.state.duration * (this.state.seekerPosition / this.seekerWidth);
}
calculateSeekerPosition() {
return this.seekerWidth * this.getCurrentTimePercentage();
}
getCurrentTimePercentage() {
if (this.state.currentTime > 0) {
return parseFloat(this.state.currentTime) / parseFloat(this.state.duration);
}
return 0;
};
componentWillMount() {
this.initSeeker();
}
componentWillReceiveProps(nextProps) {
const { isPlayerVisible } = nextProps;
if (!isPlayerVisible && !this.state.backgroundPlayEnabled) {
// force pause if the player is not visible and background play is not enabled
this.setState({ paused: true });
}
}
componentDidMount() {
const { assignPlayer, backgroundPlayEnabled } = this.props;
if (assignPlayer) {
assignPlayer(this);
}
this.setState({ backgroundPlayEnabled: !!backgroundPlayEnabled });
this.setSeekerPosition(this.calculateSeekerPosition());
AppState.addEventListener('change', this.handleAppStateChange);
DeviceEventEmitter.addListener('onBackgroundPlayPressed', this.play);
DeviceEventEmitter.addListener('onBackgroundPausePressed', this.pause);
}
componentWillUnmount() {
AppState.removeEventListener('change', this.handleAppStateChange);
DeviceEventEmitter.removeListener('onBackgroundPlayPressed', this.play);
DeviceEventEmitter.removeListener('onBackgroundPausePressed', this.pause);
this.clearControlsTimeout();
this.setState({ paused: true, fullscreenMode: false });
const { onFullscreenToggled } = this.props;
if (onFullscreenToggled) {
onFullscreenToggled(false);
}
}
handleAppStateChange = () => {
if (AppState.currentState && AppState.currentState.match(/inactive|background/)) {
if (!this.state.backgroundPlayEnabled && !this.state.paused) {
this.setState({ paused: true, autoPaused: true });
}
}
if (AppState.currentState && AppState.currentState.match(/active/)) {
if (!this.state.backgroundPlayEnabled && this.state.autoPaused) {
this.setState({ paused: false, autoPaused: false });
}
}
}
onBuffer = () => {
if (!this.state.paused) {
this.setState({ buffering: true }, () => this.manualHidePlayerControls());
}
}
play = () => {
this.setState({ paused: false }, this.updateBackgroundMediaNotification);
}
pause = () => {
this.setState({ paused: true }, this.updateBackgroundMediaNotification);
}
updateBackgroundMediaNotification = () => {
this.handlePausedState();
const { backgroundPlayEnabled } = this.props;
if (backgroundPlayEnabled) {
if (NativeModules.BackgroundMedia && window.currentMediaInfo) {
const { title, channel, uri } = window.currentMediaInfo;
NativeModules.BackgroundMedia.showPlaybackNotification(title, channel, uri, this.state.paused);
}
}
}
renderPlayerControls() {
const { onBackButtonPressed } = this.props;
if (this.state.areControlsVisible) {
return (
<View style={mediaPlayerStyle.playerControlsContainer}>
<TouchableOpacity style={mediaPlayerStyle.backButton} onPress={onBackButtonPressed}>
<Icon name={"arrow-left"} size={18} style={mediaPlayerStyle.backButtonIcon} />
</TouchableOpacity>
<TouchableOpacity style={mediaPlayerStyle.playPauseButton}
onPress={this.togglePlay}>
{this.state.paused && <Icon name="play" size={40} color="#ffffff" />}
{!this.state.paused && <Icon name="pause" size={40} color="#ffffff" />}
</TouchableOpacity>
<TouchableOpacity style={mediaPlayerStyle.toggleFullscreenButton} onPress={this.toggleFullscreenMode}>
{this.state.fullscreenMode && <Icon name="compress" size={16} color="#ffffff" />}
{!this.state.fullscreenMode && <Icon name="expand" size={16} color="#ffffff" />}
</TouchableOpacity>
<Text style={mediaPlayerStyle.elapsedDuration}>{this.formatTime(this.state.currentTime)}</Text>
<Text style={mediaPlayerStyle.totalDuration}>{this.formatTime(this.state.duration)}</Text>
</View>
);
}
return null;
}
onSeekerTouchAreaPressed = (evt) => {
if (evt && evt.nativeEvent) {
const newSeekerPosition = evt.nativeEvent.locationX;
if (!isNaN(newSeekerPosition)) {
const time = this.state.duration * (newSeekerPosition / this.seekerWidth);
this.setSeekerPosition(newSeekerPosition);
this.seekTo(time);
}
}
}
onTrackingLayout = (evt) => {
this.trackingOffset = evt.nativeEvent.layout.x;
this.seekerWidth = evt.nativeEvent.layout.width;
this.setSeekerPosition(this.calculateSeekerPosition());
}
render() {
const { onLayout, source, style, thumbnail } = this.props;
const completedWidth = this.getCurrentTimePercentage() * this.seekerWidth;
const remainingWidth = this.seekerWidth - completedWidth;
let styles = [this.state.fullscreenMode ? mediaPlayerStyle.fullscreenContainer : mediaPlayerStyle.container];
if (style) {
if (style.length) {
styles = styles.concat(style);
} else {
styles.push(style);
}
}
const trackingStyle = [mediaPlayerStyle.trackingControls, this.state.fullscreenMode ?
mediaPlayerStyle.fullscreenTrackingControls : mediaPlayerStyle.containedTrackingControls];
return (
<View style={styles} onLayout={onLayout}>
<Video source={{ uri: source }}
bufferConfig={{ minBufferMs: 15000, maxBufferMs: 60000, bufferForPlaybackMs: 5000, bufferForPlaybackAfterRebufferMs: 5000 }}
ref={(ref: Video) => { this.video = ref; }}
resizeMode={this.state.resizeMode}
playInBackground={this.state.backgroundPlayEnabled}
style={mediaPlayerStyle.player}
rate={this.state.rate}
volume={this.state.volume}
paused={this.state.paused}
onLoad={this.onLoad}
onBuffer={this.onBuffer}
onProgress={this.onProgress}
onEnd={this.onEnd}
onError={this.onError}
minLoadRetryCount={999}
/>
{this.state.firstPlay && thumbnail && thumbnail.trim().length > 0 &&
<FastImage
source={{uri: thumbnail}}
resizeMode={FastImage.resizeMode.cover}
style={mediaPlayerStyle.playerThumbnail}
/>}
<TouchableOpacity style={mediaPlayerStyle.playerControls} onPress={this.togglePlayerControls}>
{this.renderPlayerControls()}
</TouchableOpacity>
{(!this.state.fullscreenMode || (this.state.fullscreenMode && this.state.areControlsVisible)) &&
<View style={trackingStyle} onLayout={this.onTrackingLayout}>
<View style={mediaPlayerStyle.progress}>
<View style={[mediaPlayerStyle.innerProgressCompleted, { width: completedWidth }]} />
<View style={[mediaPlayerStyle.innerProgressRemaining, { width: remainingWidth }]} />
</View>
</View>}
{this.state.buffering &&
<View style={mediaPlayerStyle.loadingContainer}>
<ActivityIndicator color={Colors.LbryGreen} size="large" />
</View>}
{this.state.areControlsVisible &&
<View style={{ left: this.getTrackingOffset(), width: this.seekerWidth }}>
<View style={[mediaPlayerStyle.seekerHandle,
(this.state.fullscreenMode ? mediaPlayerStyle.seekerHandleFs : mediaPlayerStyle.seekerHandleContained),
{ left: this.state.seekerPosition }]} { ...this.seekResponder.panHandlers }>
<View style={this.state.seeking ? mediaPlayerStyle.bigSeekerCircle : mediaPlayerStyle.seekerCircle} />
</View>
<TouchableOpacity
style={[mediaPlayerStyle.seekerTouchArea,
(this.state.fullscreenMode ? mediaPlayerStyle.seekerTouchAreaFs : mediaPlayerStyle.seekerTouchAreaContained)]}
onPress={this.onSeekerTouchAreaPressed} />
</View>}
</View>
);
}
}
export default MediaPlayer;

View file

@ -1,4 +0,0 @@
import { connect } from 'react-redux';
import NavigationButton from './view';
export default connect()(NavigationButton);

View file

@ -1,18 +0,0 @@
import React from 'react';
import Icon from 'react-native-vector-icons/FontAwesome5';
import { TouchableOpacity } from 'react-native';
class NavigationButton extends React.PureComponent {
render() {
const { iconStyle, name, onPress, size, style } = this.props;
return (
<TouchableOpacity onPress={onPress} style={style}>
<Icon name={name} size={size} style={iconStyle} />
</TouchableOpacity>
);
}
};
export default NavigationButton;

View file

@ -1,6 +0,0 @@
import { connect } from 'react-redux';
import NsfwOverlay from './view';
const perform = dispatch => ({});
export default connect(null, perform)(NsfwOverlay);

View file

@ -1,15 +0,0 @@
import React from 'react';
import { Text, TouchableOpacity } from 'react-native';
import discoverStyle from '../../styles/discover';
class NsfwOverlay extends React.PureComponent {
render() {
return (
<TouchableOpacity style={discoverStyle.overlay} activeOpacity={0.95} onPress={this.props.onPress}>
<Text style={discoverStyle.overlayText}>This content is Not Safe For Work. To view adult content, please change your Settings.</Text>
</TouchableOpacity>
)
}
}
export default NsfwOverlay;

View file

@ -1,6 +0,0 @@
import { connect } from 'react-redux';
import PageHeader from './view';
const perform = dispatch => ({});
export default connect(null, perform)(PageHeader);

View file

@ -1,52 +0,0 @@
// Based on https://github.com/react-navigation/react-navigation/blob/master/src/views/Header/Header.js
import React from 'react';
import {
Animated,
Platform,
StyleSheet,
Text,
TouchableOpacity,
View
} from 'react-native';
import Icon from 'react-native-vector-icons/FontAwesome5';
import NavigationButton from 'component/navigationButton';
import pageHeaderStyle from 'styles/pageHeader';
const APPBAR_HEIGHT = Platform.OS === 'ios' ? 44 : 56;
const AnimatedText = Animated.Text;
class PageHeader extends React.PureComponent {
render() {
const { title, onBackPressed } = this.props;
const containerStyles = [
pageHeaderStyle.container,
{ height: APPBAR_HEIGHT }
];
return (
<View style={containerStyles}>
<View style={pageHeaderStyle.flexOne}>
<View style={pageHeaderStyle.header}>
<View style={pageHeaderStyle.title}>
<AnimatedText
numberOfLines={1}
style={pageHeaderStyle.titleText}
accessibilityTraits="header">
{title}
</AnimatedText>
</View>
<NavigationButton
name="arrow-left"
style={pageHeaderStyle.left}
size={24}
iconStyle={pageHeaderStyle.backIcon}
onPress={onBackPressed}
/>
</View>
</View>
</View>
);
}
}
export default PageHeader;

View file

@ -1,4 +0,0 @@
import { connect } from 'react-redux';
import ProgressBar from './view';
export default connect()(ProgressBar);

View file

@ -1,54 +0,0 @@
// @flow
import React from 'react';
import PropTypes from 'prop-types';
import { View } from 'react-native';
const defaultHeight = 5;
const defaultBorderRadius = 5;
const minProgress = 0;
const maxProgress = 100;
class ProgressBar extends React.PureComponent {
static propTypes = {
borderRadius: PropTypes.number,
color: PropTypes.string.isRequired,
height: PropTypes.number,
progress: function(props, propName, componentName) {
const value = parseInt(props[propName], 10);
if (isNaN(value) || props[propName] < minProgress || props[propName] > maxProgress) {
return new Error('progress should be between 0 and 100');
}
},
style: PropTypes.any
};
render() {
const { borderRadius, color, height, progress, style } = this.props;
const currentProgress = Math.ceil(progress);
let styles = [];
if (style) {
if (style.length) {
styles = styles.concat(style);
} else {
styles.push(style);
}
}
styles.push({
borderRadius: borderRadius || defaultBorderRadius,
flexDirection: 'row',
height: height || defaultHeight,
overflow: 'hidden'
});
return (
<View style={styles}>
<View style={{ backgroundColor: color, borderRadius: borderRadius || defaultBorderRadius, flex: currentProgress }} />
<View style={{ backgroundColor: color, opacity: 0.2, flex: (100 - currentProgress) }} />
</View>
);
}
}
export default ProgressBar;

View file

@ -1,25 +0,0 @@
import { connect } from 'react-redux';
import {
makeSelectClaimForUri,
doSearch,
makeSelectRecommendedContentForUri,
makeSelectTitleForUri,
selectIsSearching,
} from 'lbry-redux';
import RelatedContent from './view';
const select = (state, props) => ({
claim: makeSelectClaimForUri(props.uri)(state),
recommendedContent: makeSelectRecommendedContentForUri(props.uri)(state),
title: makeSelectTitleForUri(props.uri)(state),
isSearching: selectIsSearching(state),
});
const perform = dispatch => ({
search: query => dispatch(doSearch(query, 20, undefined, true)),
});
export default connect(
select,
perform
)(RelatedContent);

View file

@ -1,65 +0,0 @@
import React from 'react';
import { ActivityIndicator, FlatList, Text, View } from 'react-native';
import { navigateToUri } from 'utils/helper';
import Colors from 'styles/colors';
import FileListItem from 'component/fileListItem';
import fileListStyle from 'styles/fileList';
import relatedContentStyle from 'styles/relatedContent';
export default class RelatedContent extends React.PureComponent<Props> {
constructor() {
super();
this.didSearch = undefined;
}
componentDidMount() {
this.getRecommendedContent();
}
componentDidUpdate(prevProps: Props) {
const { claim, uri } = this.props;
if (uri !== prevProps.uri) {
this.didSearch = false;
}
if (claim && !this.didSearch) {
this.getRecommendedContent();
}
}
getRecommendedContent() {
const { search, title } = this.props;
if (title) {
search(title);
this.didSearch = true;
}
}
didSearch: ?boolean;
render() {
const { recommendedContent, isSearching, navigation } = this.props;
if (!isSearching && (!recommendedContent || recommendedContent.length === 0)) {
return null;
}
return (
<View style={relatedContentStyle.container}>
<Text style={relatedContentStyle.title}>Related Content</Text>
{recommendedContent && recommendedContent.map(recommendedUri => (
<FileListItem
style={fileListStyle.item}
key={recommendedUri}
uri={recommendedUri}
navigation={navigation}
onPress={() => navigateToUri(navigation, recommendedUri, { autoplay: true })} />
))}
{isSearching && <ActivityIndicator size="small" color={Colors.LbryGreen} style={relatedContentStyle.loading} />}
</View>
);
}
}

View file

@ -1,29 +0,0 @@
import { connect } from 'react-redux';
import { doToast } from 'lbry-redux';
import {
doClaimRewardType,
doClaimRewardClearError,
makeSelectClaimRewardError,
makeSelectIsRewardClaimPending,
} from 'lbryinc';
import RewardCard from './view';
const makeSelect = () => {
const selectIsPending = makeSelectIsRewardClaimPending();
const selectError = makeSelectClaimRewardError();
const select = (state, props) => ({
errorMessage: selectError(state, props),
isPending: selectIsPending(state, props),
});
return select;
};
const perform = dispatch => ({
claimReward: reward => dispatch(doClaimRewardType(reward.reward_type, true)),
clearError: reward => dispatch(doClaimRewardClearError(reward)),
notify: data => dispatch(doToast(data))
});
export default connect(makeSelect, perform)(RewardCard);

View file

@ -1,103 +0,0 @@
// @flow
import React from 'react';
import { ActivityIndicator, Text, TouchableOpacity, View } from 'react-native';
import Colors from '../../styles/colors';
import Icon from 'react-native-vector-icons/FontAwesome5';
import Link from '../link';
import rewardStyle from '../../styles/reward';
type Props = {
canClaim: bool,
onClaimPress: object,
reward: {
id: string,
reward_title: string,
reward_amount: number,
transaction_id: string,
created_at: string,
reward_description: string,
reward_type: string,
},
};
class RewardCard extends React.PureComponent<Props> {
state = {
claimStarted: false
};
componentWillReceiveProps(nextProps) {
const { errorMessage, isPending } = nextProps;
const { clearError, notify, reward } = this.props;
if (this.state.claimStarted && !isPending) {
if (errorMessage && errorMessage.trim().length > 0) {
notify({ message: errorMessage });
clearError(reward);
} else {
notify({ message: 'Reward successfully claimed!' });
}
this.setState({ claimStarted: false });
}
}
onClaimPress = () => {
const {
canClaim,
claimReward,
notify,
reward,
showVerification
} = this.props;
if (!canClaim) {
if (showVerification) {
showVerification();
}
notify({ message: 'Unfortunately, you are not eligible to claim this reward at this time.' });
return;
}
this.setState({ claimStarted: true }, () => {
claimReward(reward);
});
}
render() {
const { canClaim, isPending, onClaimPress, reward } = this.props;
const claimed = !!reward.transaction_id;
return (
<TouchableOpacity style={[rewardStyle.rewardCard, rewardStyle.row]} onPress={() => {
if (!isPending && !claimed) {
this.onClaimPress();
}
}}>
<View style={rewardStyle.leftCol}>
{!isPending && <TouchableOpacity onPress={() => {
if (!claimed) {
this.onClaimPress();
}
}}>
{claimed && <Icon name={claimed ? "check-circle" : "circle"}
style={claimed ? rewardStyle.claimed : (canClaim ? rewardStyle.unclaimed : rewardStyle.disabled)}
size={20} />}
</TouchableOpacity>}
{isPending && <ActivityIndicator size="small" color={Colors.LbryGreen} />}
</View>
<View style={rewardStyle.midCol}>
<Text style={rewardStyle.rewardTitle}>{reward.reward_title}</Text>
<Text style={rewardStyle.rewardDescription}>{reward.reward_description}</Text>
{claimed && <Link style={rewardStyle.link}
href={`https://explorer.lbry.com/tx/${reward.transaction_id}`}
text={reward.transaction_id.substring(0, 7)}
error={'The transaction URL could not be opened'} />}
</View>
<View style={rewardStyle.rightCol}>
<Text style={rewardStyle.rewardAmount}>{reward.reward_amount}</Text>
<Text style={rewardStyle.rewardCurrency}>LBC</Text>
</View>
</TouchableOpacity>
);
}
};
export default RewardCard;

View file

@ -1,19 +0,0 @@
import { connect } from 'react-redux';
import { doToast } from 'lbry-redux';
import { doSetClientSetting } from 'redux/actions/settings';
import { doRewardList, selectUnclaimedRewardValue, selectFetchingRewards, selectUser } from 'lbryinc';
import RewardEnrolment from './view';
const select = state => ({
unclaimedRewardAmount: selectUnclaimedRewardValue(state),
fetching: selectFetchingRewards(state),
user: selectUser(state)
});
const perform = dispatch => ({
fetchRewards: () => dispatch(doRewardList()),
notify: data => dispatch(doToast(data)),
setClientSetting: (key, value) => dispatch(doSetClientSetting(key, value)),
});
export default connect(select, perform)(RewardEnrolment);

View file

@ -1,53 +0,0 @@
import React from 'react';
import { NativeModules, Text, TouchableOpacity, View } from 'react-native';
import AsyncStorage from '@react-native-community/async-storage';
import Button from 'component/button';
import Constants from 'constants';
import Link from 'component/link';
import Colors from 'styles/colors';
import Icon from 'react-native-vector-icons/FontAwesome5';
import rewardStyle from 'styles/reward';
class RewardEnrolment extends React.Component {
componentDidMount() {
this.props.fetchRewards();
}
onNotInterestedPressed = () => {
const { navigation, setClientSetting } = this.props;
setClientSetting(Constants.SETTING_REWARDS_NOT_INTERESTED, true);
navigation.navigate({ routeName: 'DiscoverStack' });
}
onEnrollPressed = () => {
const { navigation } = this.props;
navigation.navigate({ routeName: 'Verification', key: 'verification', params: { syncFlow: false }});
}
render() {
const { fetching, navigation, unclaimedRewardAmount, user } = this.props;
return (
<View style={rewardStyle.enrollContainer} onPress>
<View style={rewardStyle.summaryRow}>
<Icon name="award" size={36} color={Colors.White} />
<Text style={rewardStyle.summaryText}>
{unclaimedRewardAmount} unclaimed credits
</Text>
</View>
<View style={rewardStyle.onboarding}>
<Text style={rewardStyle.enrollDescText}>LBRY credits allow you to purchase content, publish content, and influence the network. You can start earning credits by watching videos on LBRY.</Text>
</View>
<View style={rewardStyle.buttonRow}>
<Link style={rewardStyle.notInterestedLink} text={"Not interested"} onPress={this.onNotInterestedPressed} />
<Button style={rewardStyle.enrollButton} theme={"light"} text={"Enroll"} onPress={this.onEnrollPressed} />
</View>
</View>
);
}
}
export default RewardEnrolment;

View file

@ -1,17 +0,0 @@
import { connect } from 'react-redux';
import { doToast } from 'lbry-redux';
import { doRewardList, selectUnclaimedRewardValue, selectFetchingRewards, selectUser } from 'lbryinc';
import RewardSummary from './view';
const select = state => ({
unclaimedRewardAmount: selectUnclaimedRewardValue(state),
fetching: selectFetchingRewards(state),
user: selectUser(state)
});
const perform = dispatch => ({
fetchRewards: () => dispatch(doRewardList()),
notify: data => dispatch(doToast(data))
});
export default connect(select, perform)(RewardSummary);

View file

@ -1,82 +0,0 @@
import React from 'react';
import { NativeModules, Text, TouchableOpacity, View } from 'react-native';
import AsyncStorage from '@react-native-community/async-storage';
import Button from 'component/button';
import Colors from 'styles/colors';
import Icon from 'react-native-vector-icons/FontAwesome5';
import rewardStyle from 'styles/reward';
class RewardSummary extends React.Component {
static itemKey = 'rewardSummaryDismissed';
state = {
actionsLeft: 0,
dismissed: false
};
componentDidMount() {
this.props.fetchRewards();
AsyncStorage.getItem(RewardSummary.itemKey).then(isDismissed => {
if ('true' === isDismissed) {
this.setState({ dismissed: true });
}
const { user } = this.props;
let actionsLeft = 0;
if (!user || !user.has_verified_email) {
actionsLeft++;
}
if (!user || !user.is_identity_verified) {
actionsLeft++;
}
this.setState({ actionsLeft });
});
}
onDismissPressed = () => {
AsyncStorage.setItem(RewardSummary.itemKey, 'true');
this.setState({ dismissed: true });
this.props.notify({
message: 'You can always claim your rewards from the Rewards page.',
});
}
handleSummaryPressed = () => {
const { showVerification } = this.props;
if (showVerification) {
showVerification();
}
}
render() {
const { fetching, navigation, unclaimedRewardAmount, user } = this.props;
if (!user) {
return null;
}
if (this.state.dismissed ||
(user && user.is_reward_approved) ||
this.state.actionsLeft === 0 ||
unclaimedRewardAmount === 0) {
return null;
}
return (
<TouchableOpacity style={rewardStyle.summaryContainer} onPress={this.handleSummaryPressed}>
<View style={rewardStyle.summaryRow}>
<Icon name="award" size={36} color={Colors.White} />
<Text style={rewardStyle.summaryText}>
{unclaimedRewardAmount} unclaimed credits
</Text>
</View>
<Button style={rewardStyle.dismissButton} theme={"light"} text={"Dismiss"} onPress={this.onDismissPressed} />
</TouchableOpacity>
);
}
}
export default RewardSummary;

View file

@ -1,16 +0,0 @@
import { connect } from 'react-redux';
import { NativeModules } from 'react-native';
import { doSearch, doUpdateSearchQuery } from 'lbry-redux';
import SearchInput from './view';
const perform = dispatch => ({
search: search => {
if (NativeModules.Firebase) {
NativeModules.Firebase.track('search', { query: search });
}
return dispatch(doSearch(search));
},
updateSearchQuery: query => dispatch(doUpdateSearchQuery(query, false))
});
export default connect(null, perform)(SearchInput);

View file

@ -1,40 +0,0 @@
import React from 'react';
import { TextInput } from 'react-native';
class SearchInput extends React.PureComponent {
static INPUT_TIMEOUT = 500;
state = {
changeTextTimeout: -1
};
handleChangeText = text => {
clearTimeout(this.state.changeTextTimeout);
if (!text || text.trim().length < 2) {
// only perform a search if 2 or more characters have been input
return;
}
const { search, updateSearchQuery } = this.props;
updateSearchQuery(text);
let timeout = setTimeout(() => {
search(text);
}, SearchInput.INPUT_TIMEOUT);
this.setState({ changeTextTimeout: timeout });
}
render() {
const { style, value } = this.props;
return (
<TextInput
style={style}
placeholder="Search"
underlineColorAndroid="transparent"
value={value}
onChangeText={text => this.handleChangeText(text)} />
);
}
}
export default SearchInput;

View file

@ -1,10 +0,0 @@
import { connect } from 'react-redux';
import SearchRightHeaderIcon from './view';
import { ACTIONS } from 'lbry-redux';
const perform = dispatch => ({
clearQuery: () => dispatch({
type: ACTIONS.HISTORY_NAVIGATE
})
});
export default connect(null, perform)(SearchRightHeaderIcon);

View file

@ -1,20 +0,0 @@
import React from 'react';
import { NavigationActions } from 'react-navigation';
import Feather from "react-native-vector-icons/Feather";
class SearchRightHeaderIcon extends React.PureComponent {
clearAndGoBack() {
const { navigation } = this.props;
this.props.clearQuery();
navigation.dispatch(NavigationActions.back())
}
render() {
const { style } = this.props;
return <Feather name="x" size={24} style={style} onPress={() => this.clearAndGoBack()} />;
}
}
export default SearchRightHeaderIcon;

View file

@ -1,4 +0,0 @@
import { connect } from 'react-redux';
import StorageStatsCard from './view';
export default connect()(StorageStatsCard);

View file

@ -1,132 +0,0 @@
import React from 'react';
import { normalizeURI, parseURI } from 'lbry-redux';
import {
ActivityIndicator,
Platform,
Switch,
Text,
TouchableOpacity,
View
} from 'react-native';
import { formatBytes } from '../../utils/helper';
import Colors from '../../styles/colors';
import storageStatsStyle from '../../styles/storageStats';
class StorageStatsCard extends React.PureComponent {
state = {
totalBytes: 0,
totalAudioBytes: 0,
totalAudioPercent: 0,
totalImageBytes: 0,
totalImagePercent: 0,
totalVideoBytes: 0,
totalVideoPercent: 0,
totalOtherBytes: 0,
totalOtherPercent: 0,
showStats: false
};
componentDidMount() {
// calculate total bytes
const { fileInfos } = this.props;
let totalBytes = 0, totalAudioBytes = 0, totalImageBytes = 0, totalVideoBytes = 0;
let totalAudioPercent = 0, totalImagePercent = 0, totalVideoPercent = 0;
fileInfos.forEach(fileInfo => {
if (fileInfo.completed) {
const bytes = fileInfo.written_bytes;
const type = fileInfo.mime_type;
totalBytes += bytes;
if (type) {
if (type.startsWith('audio/')) totalAudioBytes += bytes;
if (type.startsWith('image/')) totalImageBytes += bytes;
if (type.startsWith('video/')) totalVideoBytes += bytes;
}
}
});
totalAudioPercent = ((totalAudioBytes / totalBytes) * 100).toFixed(2);
totalImagePercent = ((totalImageBytes / totalBytes) * 100).toFixed(2);
totalVideoPercent = ((totalVideoBytes / totalBytes) * 100).toFixed(2);
this.setState({
totalBytes,
totalAudioBytes,
totalAudioPercent,
totalImageBytes,
totalImagePercent,
totalVideoBytes,
totalVideoPercent,
totalOtherBytes: totalBytes - (totalAudioBytes + totalImageBytes + totalVideoBytes),
totalOtherPercent: (100 - (parseFloat(totalAudioPercent) +
parseFloat(totalImagePercent) +
parseFloat(totalVideoPercent))).toFixed(2)
});
}
render() {
if (this.state.totalBytes == 0) {
return null;
}
return (
<View style={storageStatsStyle.card}>
<View style={[storageStatsStyle.row, storageStatsStyle.totalSizeContainer]}>
<View style={storageStatsStyle.summary}>
<Text style={storageStatsStyle.totalSize}>{formatBytes(this.state.totalBytes, 2)}</Text>
<Text style={storageStatsStyle.annotation}>used</Text>
</View>
<View style={[storageStatsStyle.row, storageStatsStyle.toggleStatsContainer]}>
<Text style={storageStatsStyle.statsText}>Stats</Text>
<Switch
style={storageStatsStyle.statsToggle}
value={this.state.showStats}
onValueChange={(value) => this.setState({ showStats: value })} />
</View>
</View>
{this.state.showStats &&
<View>
<View style={storageStatsStyle.distributionBar}>
<View style={[storageStatsStyle.audioDistribution, { flex: parseFloat(this.state.totalAudioPercent) }]} />
<View style={[storageStatsStyle.imageDistribution, { flex: parseFloat(this.state.totalImagePercent) }]} />
<View style={[storageStatsStyle.videoDistribution, { flex: parseFloat(this.state.totalVideoPercent) }]} />
<View style={[storageStatsStyle.otherDistribution, { flex: parseFloat(this.state.totalOtherPercent) }]} />
</View>
<View style={storageStatsStyle.legend}>
{this.state.totalAudioBytes > 0 &&
<View style={[storageStatsStyle.row, storageStatsStyle.legendItem]}>
<View style={[storageStatsStyle.legendBox, storageStatsStyle.audioDistribution]} />
<Text style={storageStatsStyle.legendText}>Audio</Text>
<Text style={storageStatsStyle.legendSize}>{formatBytes(this.state.totalAudioBytes, 2)}</Text>
</View>
}
{this.state.totalImageBytes > 0 &&
<View style={[storageStatsStyle.row, storageStatsStyle.legendItem]}>
<View style={[storageStatsStyle.legendBox, storageStatsStyle.imageDistribution]} />
<Text style={storageStatsStyle.legendText}>Images</Text>
<Text style={storageStatsStyle.legendSize}>{formatBytes(this.state.totalImageBytes, 2)}</Text>
</View>
}
{this.state.totalVideoBytes > 0 &&
<View style={[storageStatsStyle.row, storageStatsStyle.legendItem]}>
<View style={[storageStatsStyle.legendBox, storageStatsStyle.videoDistribution]} />
<Text style={storageStatsStyle.legendText}>Videos</Text>
<Text style={storageStatsStyle.legendSize}>{formatBytes(this.state.totalVideoBytes, 2)}</Text>
</View>
}
{this.state.totalOtherBytes > 0 &&
<View style={[storageStatsStyle.row, storageStatsStyle.legendItem]}>
<View style={[storageStatsStyle.legendBox, storageStatsStyle.otherDistribution]} />
<Text style={storageStatsStyle.legendText}>Other</Text>
<Text style={storageStatsStyle.legendSize}>{formatBytes(this.state.totalOtherBytes, 2)}</Text>
</View>
}
</View>
</View>}
</View>
)
}
}
export default StorageStatsCard;

View file

@ -1,23 +0,0 @@
import { connect } from 'react-redux';
import {
doChannelSubscribe,
doChannelUnsubscribe,
selectSubscriptions,
makeSelectIsSubscribed,
} from 'lbryinc';
import { doToast } from 'lbry-redux';
import SubscribeButton from './view';
const select = (state, props) => ({
subscriptions: selectSubscriptions(state),
isSubscribed: makeSelectIsSubscribed(props.uri, true)(state),
});
export default connect(
select,
{
doChannelSubscribe,
doChannelUnsubscribe,
doToast,
}
)(SubscribeButton);

View file

@ -1,49 +0,0 @@
import React from 'react';
import { normalizeURI, parseURI } from 'lbry-redux';
import { NativeModules, Text, View, TouchableOpacity } from 'react-native';
import Button from '../button';
import Colors from '../../styles/colors';
class SubscribeButton extends React.PureComponent {
render() {
const {
uri,
isSubscribed,
doChannelSubscribe,
doChannelUnsubscribe,
style
} = this.props;
let styles = [];
if (style) {
if (style.length) {
styles = styles.concat(style);
} else {
styles.push(style);
}
}
const iconColor = isSubscribed ? null : Colors.Red;
const subscriptionHandler = isSubscribed ? doChannelUnsubscribe : doChannelSubscribe;
const subscriptionLabel = isSubscribed ? null : __('Subscribe');
const { claimName } = parseURI(uri);
return (
<Button
style={styles}
theme={"light"}
icon={isSubscribed ? "heart-broken" : "heart"}
iconColor={iconColor}
solid={isSubscribed ? false : true}
text={subscriptionLabel}
onPress={() => {
subscriptionHandler({
channelName: claimName,
uri: normalizeURI(uri),
});
}} />
);
}
}
export default SubscribeButton;

View file

@ -1,25 +0,0 @@
import { connect } from 'react-redux';
import {
doChannelSubscriptionEnableNotifications,
doChannelSubscriptionDisableNotifications,
selectEnabledChannelNotifications,
selectSubscriptions,
makeSelectIsSubscribed,
} from 'lbryinc';
import { doToast } from 'lbry-redux';
import SubscribeNotificationButton from './view';
const select = (state, props) => ({
enabledChannelNotifications: selectEnabledChannelNotifications(state),
subscriptions: selectSubscriptions(state),
isSubscribed: makeSelectIsSubscribed(props.uri, true)(state),
});
export default connect(
select,
{
doChannelSubscriptionEnableNotifications,
doChannelSubscriptionDisableNotifications,
doToast,
}
)(SubscribeNotificationButton);

View file

@ -1,55 +0,0 @@
import React from 'react';
import { parseURI } from 'lbry-redux';
import { NativeModules, Text, View, TouchableOpacity } from 'react-native';
import Button from 'component/button';
import Colors from 'styles/colors';
class SubscribeNotificationButton extends React.PureComponent {
render() {
const {
uri,
name,
doChannelSubscriptionEnableNotifications,
doChannelSubscriptionDisableNotifications,
doToast,
enabledChannelNotifications,
isSubscribed,
style
} = this.props;
if (!isSubscribed) {
return null;
}
let styles = [];
if (style) {
if (style.length) {
styles = styles.concat(style);
} else {
styles.push(style);
}
}
const shouldNotify = enabledChannelNotifications.indexOf(name) > -1;
const { claimName } = parseURI(uri);
return (
<Button
style={styles}
theme={"light"}
icon={shouldNotify ? "bell-slash" : "bell"}
solid={true}
onPress={() => {
if (shouldNotify) {
doChannelSubscriptionDisableNotifications(name);
doToast({ message: 'You will not receive notifications for new content.' });
} else {
doChannelSubscriptionEnableNotifications(name);
doToast({ message: 'You will receive all notifications for new content.' });
}
}} />
);
}
}
export default SubscribeNotificationButton;

View file

@ -1,25 +0,0 @@
import { connect } from 'react-redux';
import {
makeSelectFetchingChannelClaims,
makeSelectClaimsInChannelForPage,
doFetchClaimsByChannel,
doResolveUris,
} from 'lbry-redux';
import { selectShowNsfw } from 'redux/selectors/settings';
import SuggestedSubscriptionItem from './view';
const select = (state, props) => ({
claims: makeSelectClaimsInChannelForPage(props.categoryLink)(state),
fetching: makeSelectFetchingChannelClaims(props.categoryLink)(state),
obscureNsfw: !selectShowNsfw(state),
});
const perform = dispatch => ({
fetchChannel: channel => dispatch(doFetchClaimsByChannel(channel)),
resolveUris: uris => dispatch(doResolveUris(uris, true)),
});
export default connect(
select,
perform
)(SuggestedSubscriptionItem);

View file

@ -1,74 +0,0 @@
import React from 'react';
import { buildURI, normalizeURI } from 'lbry-redux';
import { ActivityIndicator, FlatList, Text, View } from 'react-native';
import Colors from 'styles/colors';
import discoverStyle from 'styles/discover';
import FileItem from 'component/fileItem';
import subscriptionsStyle from 'styles/subscriptions';
class SuggestedSubscriptionItem extends React.PureComponent {
componentDidMount() {
const { fetching, categoryLink, fetchChannel, resolveUris, claims } = this.props;
if (!fetching && categoryLink && (!claims || claims.length)) {
fetchChannel(categoryLink);
}
}
uriForClaim = (claim) => {
const { name: claimName, claim_name: claimNameDownloaded, claim_id: claimId } = claim;
const uriParams = {};
// This is unfortunate
// https://github.com/lbryio/lbry/issues/1159
const name = claimName || claimNameDownloaded;
uriParams.contentName = name;
uriParams.claimId = claimId;
const uri = buildURI(uriParams);
return uri;
}
render() {
const { categoryLink, fetching, obscureNsfw, claims, navigation } = this.props;
if (!claims || !claims.length) {
return (
<View style={subscriptionsStyle.busyContainer}>
<ActivityIndicator size={'small'} color={Colors.LbryGreen} />
</View>
);
}
if (claims && claims.length > 0) {
return (
<View style={subscriptionsStyle.suggestedContainer}>
<FileItem
style={subscriptionsStyle.compactMainFileItem}
mediaStyle={subscriptionsStyle.fileItemMedia}
uri={this.uriForClaim(claims[0])}
navigation={navigation} />
{(claims.length > 1) &&
<FlatList style={subscriptionsStyle.compactItems}
horizontal={true}
renderItem={ ({item}) => (
<FileItem
style={subscriptionsStyle.compactFileItem}
mediaStyle={subscriptionsStyle.compactFileItemMedia}
key={item}
uri={normalizeURI(item)}
navigation={navigation}
compactView={true} />
)
}
data={claims.slice(1, 4).map(claim => this.uriForClaim(claim))}
keyExtractor={(item, index) => item}
/>}
</View>
);
}
return null;
}
}
export default SuggestedSubscriptionItem;

View file

@ -1,13 +0,0 @@
import { connect } from 'react-redux';
import { selectSuggestedChannels, selectIsFetchingSuggested } from 'lbryinc';
import SuggestedSubscriptions from './view';
const select = state => ({
suggested: selectSuggestedChannels(state),
loading: selectIsFetchingSuggested(state),
});
export default connect(
select,
null
)(SuggestedSubscriptions);

View file

@ -1,55 +0,0 @@
import React from 'react';
import { ActivityIndicator, SectionList, Text, View } from 'react-native';
import { normalizeURI } from 'lbry-redux';
import { navigateToUri } from 'utils/helper';
import SubscribeButton from 'component/subscribeButton';
import SuggestedSubscriptionItem from 'component/suggestedSubscriptionItem';
import Colors from 'styles/colors';
import discoverStyle from 'styles/discover';
import subscriptionsStyle from 'styles/subscriptions';
import Link from 'component/link';
class SuggestedSubscriptions extends React.PureComponent {
render() {
const { suggested, loading, navigation } = this.props;
if (loading) {
return (
<View>
<ActivityIndicator size="large" color={Colors.LbryGreen} />
</View>
);
}
return suggested ? (
<SectionList style={subscriptionsStyle.scrollContainer}
renderItem={ ({item, index, section}) => (
<SuggestedSubscriptionItem
key={item}
categoryLink={normalizeURI(item)}
navigation={navigation} />
)
}
renderSectionHeader={
({section: {title}}) => {
const titleParts = title.split(';');
const channelName = titleParts[0];
const channelUri = normalizeURI(titleParts[1]);
return (
<View style={subscriptionsStyle.titleRow}>
<Link style={subscriptionsStyle.channelTitle} text={channelName} onPress={() => {
navigateToUri(navigation, normalizeURI(channelUri));
}} />
<SubscribeButton style={subscriptionsStyle.subscribeButton} uri={channelUri} name={channelName} />
</View>
)
}
}
sections={suggested.map(({ uri, label }) => ({ title: (label + ';' + uri), data: [uri] }))}
keyExtractor={(item, index) => item}
/>
) : null;
}
}
export default SuggestedSubscriptions;

View file

@ -1,11 +0,0 @@
import { connect } from 'react-redux';
//import { selectClaimedRewardsByTransactionId } from 'redux/selectors/rewards';
import { selectAllMyClaimsByOutpoint } from 'lbry-redux';
import TransactionList from './view';
const select = state => ({
//rewards: selectClaimedRewardsByTransactionId(state),
myClaims: selectAllMyClaimsByOutpoint(state),
});
export default connect(select, null)(TransactionList);

View file

@ -1,56 +0,0 @@
// @flow
import React from 'react';
import { Text, View, Linking } from 'react-native';
import { buildURI, formatCredits } from 'lbry-redux';
import { navigateToUri } from '../../../utils/helper';
import Link from '../../link';
import moment from 'moment';
import transactionListStyle from '../../../styles/transactionList';
class TransactionListItem extends React.PureComponent {
capitalize(string: string) {
return string.charAt(0).toUpperCase() + string.slice(1);
}
render() {
const { transaction, navigation } = this.props;
const { amount, claim_id: claimId, claim_name: name, date, fee, txid, type } = transaction;
return (
<View style={transactionListStyle.listItem}>
<View style={[transactionListStyle.row, transactionListStyle.topRow]}>
<View style={transactionListStyle.col}>
<Text style={transactionListStyle.text}>{this.capitalize(type)}</Text>
{name && claimId && (
<Link
style={transactionListStyle.link}
onPress={() => navigateToUri(navigation, buildURI({ claimName: name, claimId }))}
text={name} />
)}
</View>
<View style={transactionListStyle.col}>
<Text style={[transactionListStyle.amount, transactionListStyle.text]}>{formatCredits(amount, 8)}</Text>
{ fee !== 0 && (<Text style={[transactionListStyle.amount, transactionListStyle.text]}>fee {formatCredits(fee, 8)}</Text>) }
</View>
</View>
<View style={transactionListStyle.row}>
<View style={transactionListStyle.col}>
<Link style={transactionListStyle.smallLink}
text={txid.substring(0, 8)}
href={`https://explorer.lbry.com/tx/${txid}`}
error={'The transaction URL could not be opened'} />
</View>
<View style={transactionListStyle.col}>
{date ? (
<Text style={transactionListStyle.smallText}>{moment(date).format('MMM D')}</Text>
) : (
<Text style={transactionListStyle.smallText}>Pending</Text>
)}
</View>
</View>
</View>
);
}
}
export default TransactionListItem;

View file

@ -1,70 +0,0 @@
// @flow
import React from 'react';
import { Text, View } from 'react-native';
import TransactionListItem from './internal/transaction-list-item';
import transactionListStyle from '../../styles/transactionList';
export type Transaction = {
amount: number,
claim_id: string,
claim_name: string,
fee: number,
nout: number,
txid: string,
type: string,
date: Date,
};
class TransactionList extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
filter: 'all',
};
(this: any).handleFilterChanged = this.handleFilterChanged.bind(this);
(this: any).filterTransaction = this.filterTransaction.bind(this);
}
handleFilterChanged(event: React.SyntheticInputEvent<*>) {
this.setState({
filter: event.target.value,
});
}
filterTransaction(transaction: Transaction) {
const { filter } = this.state;
return filter === 'all' || filter === transaction.type;
}
render() {
const { emptyMessage, rewards, transactions, navigation } = this.props;
const { filter } = this.state;
const transactionList = transactions.filter(this.filterTransaction);
return (
<View>
{!transactionList.length && (
<Text style={transactionListStyle.noTransactions}>{emptyMessage || 'No transactions to list.'}</Text>
)}
{!!transactionList.length && (
<View>
{transactionList.map(t => (
<TransactionListItem
key={`${t.txid}:${t.nout}`}
transaction={t}
navigation={navigation}
reward={rewards && rewards[t.txid]}
/>
))}
</View>
)}
</View>
);
}
}
export default TransactionList;

View file

@ -1,20 +0,0 @@
import { connect } from 'react-redux';
import {
doFetchTransactions,
selectRecentTransactions,
selectHasTransactions,
selectIsFetchingTransactions,
} from 'lbry-redux';
import TransactionListRecent from './view';
const select = state => ({
fetchingTransactions: selectIsFetchingTransactions(state),
transactions: selectRecentTransactions(state),
hasTransactions: selectHasTransactions(state),
});
const perform = dispatch => ({
fetchTransactions: () => dispatch(doFetchTransactions()),
});
export default connect(select, perform)(TransactionListRecent);

View file

@ -1,50 +0,0 @@
// @flow
import React from 'react';
//import BusyIndicator from 'component/common/busy-indicator';
import { Text, View } from 'react-native';
import Button from '../button';
import Link from '../link';
import TransactionList from '../transactionList';
import type { Transaction } from '../transactionList/view';
import walletStyle from '../../styles/wallet';
type Props = {
fetchTransactions: () => void,
fetchingTransactions: boolean,
hasTransactions: boolean,
transactions: Array<Transaction>,
};
class TransactionListRecent extends React.PureComponent<Props> {
componentDidMount() {
this.props.fetchTransactions();
}
render() {
const { fetchingTransactions, hasTransactions, transactions, navigation } = this.props;
return (
<View style={walletStyle.transactionsCard}>
<View style={[walletStyle.row, walletStyle.transactionsHeader]}>
<Text style={walletStyle.transactionsTitle}>Recent Transactions</Text>
<Link style={walletStyle.link}
navigation={navigation}
text={'View All'}
href={'#TransactionHistory'} />
</View>
{fetchingTransactions && (
<Text style={walletStyle.infoText}>Fetching transactions...</Text>
)}
{!fetchingTransactions && (
<TransactionList
navigation={navigation}
transactions={transactions}
emptyMessage={"Looks like you don't have any recent transactions."}
/>
)}
</View>
);
}
}
export default TransactionListRecent;

View file

@ -1,26 +0,0 @@
import { connect } from 'react-redux';
import {
doUpdateSearchQuery,
selectSearchState as selectSearch,
selectSearchValue,
selectSearchSuggestions
} from 'lbry-redux';
import { selectCurrentRoute } from 'redux/selectors/drawer';
import UriBar from './view';
const select = state => {
const { ...searchState } = selectSearch(state);
return {
...searchState,
query: selectSearchValue(state),
currentRoute: selectCurrentRoute(state),
suggestions: selectSearchSuggestions(state)
};
};
const perform = dispatch => ({
updateSearchQuery: query => dispatch(doUpdateSearchQuery(query)),
});
export default connect(select, perform)(UriBar);

View file

@ -1,45 +0,0 @@
// @flow
import React from 'react';
import { SEARCH_TYPES, normalizeURI } from 'lbry-redux';
import { Text, TouchableOpacity, View } from 'react-native';
import Icon from 'react-native-vector-icons/FontAwesome5';
import uriBarStyle from '../../../styles/uriBar';
class UriBarItem extends React.PureComponent {
render() {
const { item, onPress } = this.props;
const { shorthand, type, value } = item;
let icon;
switch (type) {
case SEARCH_TYPES.CHANNEL:
icon = <Icon name="at" size={18} />
break;
case SEARCH_TYPES.SEARCH:
icon = <Icon name="search" size={18} />
break;
case SEARCH_TYPES.FILE:
default:
icon = <Icon name="file" size={18} />
break;
}
return (
<TouchableOpacity style={uriBarStyle.item} onPress={onPress}>
{icon}
<View style={uriBarStyle.itemContent}>
<Text style={uriBarStyle.itemText} numberOfLines={1}>{shorthand || value} - {type === SEARCH_TYPES.SEARCH ? 'Search' : value}</Text>
<Text style={uriBarStyle.itemDesc} numberOfLines={1}>
{type === SEARCH_TYPES.SEARCH && `Search for '${value}'`}
{type === SEARCH_TYPES.CHANNEL && `View the @${shorthand} channel`}
{type === SEARCH_TYPES.FILE && `View content at ${value}`}
</Text>
</View>
</TouchableOpacity>
)
}
}
export default UriBarItem;

View file

@ -1,197 +0,0 @@
// @flow
import React from 'react';
import { SEARCH_TYPES, isNameValid, isURIValid, normalizeURI } from 'lbry-redux';
import { FlatList, Keyboard, TextInput, View } from 'react-native';
import { navigateToUri } from 'utils/helper';
import Constants from 'constants';
import UriBarItem from './internal/uri-bar-item';
import NavigationButton from 'component/navigationButton';
import discoverStyle from 'styles/discover';
import uriBarStyle from 'styles/uriBar';
class UriBar extends React.PureComponent {
static INPUT_TIMEOUT = 2500; // 2.5 seconds
textInput = null;
keyboardDidHideListener = null;
componentDidMount () {
this.keyboardDidHideListener = Keyboard.addListener('keyboardDidHide', this._keyboardDidHide);
this.setSelection();
}
componentWillUnmount() {
if (this.keyboardDidHideListener) {
this.keyboardDidHideListener.remove();
}
}
componentWillReceiveProps(nextProps) {
const { currentRoute, query } = nextProps;
const { currentRoute: prevRoute } = this.props;
if (Constants.DRAWER_ROUTE_SEARCH === currentRoute && currentRoute !== prevRoute) {
this.setState({ currentValue: query, inputText: query });
}
}
constructor(props) {
super(props);
this.state = {
changeTextTimeout: null,
currentValue: null,
inputText: null,
focused: false,
// TODO: Add a setting to enable / disable direct search?
directSearch: true
};
}
handleChangeText = text => {
const newValue = text ? text : '';
clearTimeout(this.state.changeTextTimeout);
const { updateSearchQuery, onSearchSubmitted, navigation } = this.props;
let timeout = setTimeout(() => {
if (text.trim().length === 0) {
// don't do anything if the text is empty
return;
}
updateSearchQuery(text);
if (!text.startsWith('lbry://')) {
// not a URI input, so this is a search, perform a direct search
if (onSearchSubmitted) {
onSearchSubmitted(text);
} else {
navigation.navigate({ routeName: 'Search', key: 'searchPage', params: { searchQuery: text }});
}
}
}, UriBar.INPUT_TIMEOUT);
this.setState({ inputText: newValue, currentValue: newValue, changeTextTimeout: timeout });
}
handleItemPress = (item) => {
const { navigation, onSearchSubmitted, updateSearchQuery } = this.props;
const { type, value } = item;
Keyboard.dismiss();
if (SEARCH_TYPES.SEARCH === type) {
this.setState({ currentValue: value });
updateSearchQuery(value);
if (onSearchSubmitted) {
onSearchSubmitted(value);
return;
}
navigation.navigate({ routeName: 'Search', key: 'searchPage', params: { searchQuery: value }});
} else {
const uri = normalizeURI(value);
navigateToUri(navigation, uri);
}
}
_keyboardDidHide = () => {
if (this.textInput) {
this.textInput.blur();
}
this.setState({ focused: false });
}
setSelection() {
if (this.textInput) {
this.textInput.setNativeProps({ selection: { start: 0, end: 0 }});
}
}
handleSubmitEditing = () => {
const { navigation, onSearchSubmitted, updateSearchQuery } = this.props;
if (this.state.inputText) {
let inputText = this.state.inputText;
if (inputText.startsWith('lbry://') && isURIValid(inputText)) {
// if it's a URI (lbry://...), open the file page
const uri = normalizeURI(inputText);
navigateToUri(navigation, uri);
} else {
updateSearchQuery(inputText);
// Not a URI, default to a search request
if (onSearchSubmitted) {
// Only the search page sets the onSearchSubmitted prop, so call this prop if set
onSearchSubmitted(inputText);
return;
}
// Open the search page with the query populated
navigation.navigate({ routeName: 'Search', key: 'searchPage', params: { searchQuery: inputText }});
}
}
}
onSearchPageBlurred() {
this.setState({ currenValueSet: false });
}
render() {
const { navigation, suggestions, query, value } = this.props;
if (this.state.currentValue === null) {
this.setState({ currentValue: value });
}
let style = [uriBarStyle.overlay];
// TODO: Add optional setting to enable URI / search bar suggestions
/*if (this.state.focused) { style.push(uriBarStyle.inFocus); }*/
return (
<View style={style}>
<View style={uriBarStyle.uriContainer}>
<NavigationButton
name="bars"
size={24}
style={uriBarStyle.drawerMenuButton}
iconStyle={discoverStyle.drawerHamburger}
onPress={() => navigation.openDrawer() } />
<TextInput ref={(ref) => { this.textInput = ref }}
style={uriBarStyle.uriText}
onLayout={() => { this.setSelection(); }}
selectTextOnFocus={true}
placeholder={'Search movies, music, and more'}
underlineColorAndroid={'transparent'}
numberOfLines={1}
clearButtonMode={'while-editing'}
value={this.state.currentValue}
returnKeyType={'go'}
inlineImageLeft={'baseline_search_black_24'}
inlineImagePadding={16}
onFocus={() => this.setState({ focused: true })}
onBlur={() => {
this.setState({ focused: false });
this.setSelection();
}}
onChangeText={this.handleChangeText}
onSubmitEditing={this.handleSubmitEditing}/>
{(this.state.focused && !this.state.directSearch) && (
<View style={uriBarStyle.suggestions}>
<FlatList style={uriBarStyle.suggestionList}
data={suggestions}
keyboardShouldPersistTaps={'handled'}
keyExtractor={(item, value) => item.value}
renderItem={({item}) => (
<UriBarItem
item={item}
navigation={navigation}
onPress={() => this.handleItemPress(item)}
/>)} />
</View>)}
</View>
</View>
);
}
}
export default UriBar;

View file

@ -1,20 +0,0 @@
import { connect } from 'react-redux';
import {
doCheckAddressIsMine,
doGetNewAddress,
selectReceiveAddress,
selectGettingNewAddress,
} from 'lbry-redux';
import WalletAddress from './view';
const select = state => ({
receiveAddress: selectReceiveAddress(state),
gettingNewAddress: selectGettingNewAddress(state),
});
const perform = dispatch => ({
checkAddressIsMine: address => dispatch(doCheckAddressIsMine(address)),
getNewAddress: () => dispatch(doGetNewAddress()),
});
export default connect(select, perform)(WalletAddress);

Some files were not shown because too many files have changed in this diff Show more