Compare commits

...

944 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
Akinwale Ariwodola
309b1e70e6 bumpversion 0.7.1 --> 0.7.2 2019-06-03 09:02:00 +01:00
Akinwale Ariwodola
e2399c257d
Merge pull request #566 from lbryio/custom-drawer-content
add custom drawer content to navigate to the topmost item in nested stacks
2019-06-03 08:14:21 +01:00
Akinwale Ariwodola
c892b51ff8 add custom drawer content to navigate to the topmost item in nested stacks 2019-05-31 05:41:44 +01:00
Akinwale Ariwodola
8b3a0d22be bumpversion 0.7.0 --> 0.7.1 2019-05-29 18:04:42 +01:00
Akinwale Ariwodola
f4fe9294f0 fix backspace in search uri bar 2019-05-29 17:45:14 +01:00
Akinwale Ariwodola
67a2b76e41
create progress bar component (#560) 2019-05-29 16:40:59 +01:00
Akinwale Ariwodola
499e406c5d
Merge pull request #563 from lbryio/search-uri-bar-fix
fix typing in uri bar on search page
2019-05-29 16:40:22 +01:00
Akinwale Ariwodola
90ccf18fbf fix typing in uri bar on search page 2019-05-29 16:39:34 +01:00
Akinwale Ariwodola
7f57447e57
change the appearance of the uri bar input (#561)
* change the appearance of the uri bar input
* improve no search results display
2019-05-29 11:53:27 +01:00
Akinwale Ariwodola
10beb9935f change manual reward verification message 2019-05-28 20:41:57 +01:00
Akinwale Ariwodola
5fc2e1247b
Set default account upon wallet sync restore (#556) 2019-05-28 19:26:53 +01:00
Akinwale Ariwodola
67d4e97582
add reveal password icon and more UI tweaks (#554)
* add reveal password icon and more UI tweaks
* navigation workaround. more UI updates and tweaks.
* update control colours. fix search.
* optimise launcher icon. file page style tweak.
* optimise media player buffer values
2019-05-28 16:00:15 +01:00
Akinwale Ariwodola
abeadd858e
sdk 0.37.2 update for release (#547) 2019-05-27 10:30:33 +01:00
Akinwale Ariwodola
5a737ce38d
wait for user to complete email verification (#548)
* wait for user to complete email verification on first run
* add password strength meter. fix auth bugs in first run.
2019-05-23 22:11:52 +01:00
Akinwale Ariwodola
97f1b530b2
additional rewards page changes and new verification flow (#542) 2019-05-15 11:00:15 +01:00
Akinwale Ariwodola
f1393ae707 Merge branch 'master' of https://github.com/lbryio/lbry-android 2019-05-03 19:32:39 +01:00
Akinwale Ariwodola
0c274617cb fix settings page background 2019-05-03 19:31:13 +01:00
Akinwale Ariwodola
f33a8c3829
Merge pull request #538 from lbryio/rewards-rework
optimise display of rewards verification requirements
2019-05-03 12:27:00 +01:00
Akinwale Ariwodola
c243645124 optimise display of rewards verification requirements 2019-05-03 12:21:56 +01:00
Akinwale Ariwodola
4655678481 Merge branch 'master' of https://github.com/lbryio/lbry-android 2019-05-03 11:58:08 +01:00
Akinwale Ariwodola
cec8ddeeee change launcher icon. remove unused images. 2019-05-03 11:57:21 +01:00
Akinwale Ariwodola
8d987a02aa
Merge pull request #537 from lbryio/quickstart
add quick start build instructions
2019-05-02 23:46:00 +01:00
Akinwale Ariwodola
a6d87d570f add quick start build instructions 2019-05-02 23:41:22 +01:00
Akinwale Ariwodola
f3b07be01f bumpversion 0.6.2 --> 0.7.0 2019-05-02 07:10:23 +01:00
Akinwale Ariwodola
07f23ba927
Channel page redesign (#528)
* channel page redesign changes
* add constants. change publisher thumbnail resize mode.
2019-05-02 07:07:26 +01:00
Akinwale Ariwodola
7a7e96388b
Replace Mixpanel with Firebase (Google) analytics (#535)
* replace mixpanel with firebase analytics
* add encrypted google-services.json file
2019-05-02 07:06:42 +01:00
Akinwale Ariwodola
73d91f7268
Merge pull request #536 from lbryio/player-fullscreen-overlay-fix
fix transparent player background covering touchable items
2019-05-01 16:36:58 +01:00
Akinwale Ariwodola
6371296b28 fix transparent player background covering touchable items 2019-05-01 12:45:04 +01:00
Akinwale Ariwodola
cdeadf9d6d update .gitignore 2019-05-01 12:29:32 +01:00
Akinwale Ariwodola
c332acb2c1
Merge pull request #529 from lbryio/media-player-update
update react native video version
2019-04-29 21:10:08 +01:00
Akinwale Ariwodola
0d68f1a24b update react native video version 2019-04-29 21:07:58 +01:00
Akinwale Ariwodola
1666ea88fc
File view tags (#527)
* display claim tags below description
2019-04-29 11:26:30 +01:00
Akinwale Ariwodola
ff163a31bf
sdk 0.36 updates (#526)
* add requirements to support sdk 0.36
* updates for sdk 0.36
2019-04-29 10:38:17 +01:00
Akinwale Ariwodola
73d469dc8d
Explore page redesign (#518) 2019-04-24 15:31:44 +01:00
Akinwale Ariwodola
d0226ab4cc
Cross-device sync implementation (#505)
* first run updates for sync
* finish sync implementation and fix build for openssl 1.1.1b required for sdk
* fix openssl recipe and tweak build
* fix NativeModules import on wallet page
* display total wallet balance. fix dispatch prop.
* add pipeline status to README.md
* remove unused build recipes
* hide 'No, thanks' button during email new request
* bumpversion 0.6.0 --> 0.6.1
* move unclaimed reward amount to the left of floating wallet balance
* Upgrade to React Native 0.59.3 (#513)
* upgrade to react native 0.59.3
* add FOREGROUND_SERVICE permission for Android 9 Pie (target sdk 28)
* put android.permission.FOREGROUND_SERVICE permission directly in AndroidManifest
* allow cleartext traffic
* minor copy changes
* enable secure password input and auto account_unlock on startup
2019-04-22 13:42:47 +01:00
Akinwale Ariwodola
3d1b07f11c
Merge pull request #517 from lbryio/rewards-rework
streamline reward summary
2019-04-19 05:41:55 +01:00
Akinwale Ariwodola
f98d7c26dc streamline reward summary 2019-04-17 16:37:55 +01:00
YULIUS KURNIAWAN KRISTIANTO
c5fca74e39 change io to com (#504)
* Update README.md
* Update issue_template.md
2019-04-05 15:54:56 +01:00
Akinwale Ariwodola
f79ad3dabc
Upgrade to React Native 0.59.3 (#513)
* upgrade to react native 0.59.3
* add FOREGROUND_SERVICE permission for Android 9 Pie (target sdk 28)
* put android.permission.FOREGROUND_SERVICE permission directly in AndroidManifest
* allow cleartext traffic
2019-04-05 09:13:35 +01:00
Akinwale Ariwodola
c5ebfa5021 fix navigate to main on splash page 2019-04-02 22:38:55 +01:00
Akinwale Ariwodola
534a966ee8 bumpversion 0.6.1 --> 0.6.2 2019-04-02 22:17:52 +01:00
Akinwale Ariwodola
7484596fb4
0.6.1 fixes (#512)
* fix issues with 0.6.1 release
2019-04-02 22:16:53 +01:00
Akinwale Ariwodola
1637752b02
Merge pull request #510 from lbryio/release-0.6.1 2019-04-02 14:51:57 +01:00
Akinwale Ariwodola
4ce424d4db move unclaimed reward amount to the left of floating wallet balance 2019-04-02 12:00:33 +01:00
Akinwale Ariwodola
916af88c53 bumpversion 0.6.0 --> 0.6.1 2019-04-02 11:40:58 +01:00
Akinwale Ariwodola
b21776c517
Merge pull request #509 from lbryio/sdk-requirements-cleanup
clean up python sdk requirements
2019-03-31 06:51:37 +01:00
Akinwale Ariwodola
6bb128e38a clean up python sdk requirements 2019-03-30 23:51:38 +01:00
Akinwale Ariwodola
8b2694efb7
New build (#508)
* fix build for openssl 1.1.1b required for sdk
(cherry picked from commit aa49e3b275)

* use js code from master

* fix openssl recipe and tweak build
(cherry picked from commit 6e94c27021)

* remove unused build recipes
(cherry picked from commit f5c0577bdb)
2019-03-30 21:58:45 +01:00
Akinwale Ariwodola
f853132e9b use different gradle output (until sync build update) 2019-03-30 21:19:31 +01:00
Akinwale Ariwodola
39e8d5513a add modified mangled-glibc-syscalls.h for crystax build 2019-03-30 20:43:15 +01:00
Akinwale Ariwodola
6feadf73dd revert to default gradle apk output folder 2019-03-30 20:36:56 +01:00
Akinwale Ariwodola
d683c48338 add pipeline status to README.md 2019-03-30 10:24:20 +01:00
Akinwale Ariwodola
4a684b0bec
Merge pull request #502 from lbryio/search-fix
fix search and related content
2019-03-28 18:01:47 +01:00
Akinwale Ariwodola
6d7768e904
Merge pull request #503 from lbryio/file-page-tweaks
some pre-redesign tweaks to the file page
2019-03-27 10:17:16 +01:00
Akinwale Ariwodola
a645c4530f some pre-redesign tweaks to the file page 2019-03-27 10:13:13 +01:00
Akinwale Ariwodola
4d61462290 fix search and related content 2019-03-27 08:13:09 +01:00
Akinwale Ariwodola
877ce8d008 fix imports on trending page 2019-03-26 16:21:38 +01:00
Akinwale Ariwodola
fbff91774e use pipeline number as build number 2019-03-26 15:49:08 +01:00
Akinwale Ariwodola
53fb072373
Collapse description (#490)
* collapse file description by default and add display toggle
2019-03-26 15:10:07 +01:00
Akinwale Ariwodola
f30f1f47d5
Gitlab CI (#498) 2019-03-26 15:08:50 +01:00
Akinwale Ariwodola
d8b0e89c6c
Build update (#495)
* package and build updates
* add sdk preview license to build
* use build tools 26.0.2
* use different libgmp mirror
2019-03-25 07:45:19 +01:00
Akinwale Ariwodola
a353f13ebb
Merge pull request #494 from lbryio/lbry-dependencies
update to use new imports from lbryinc and lbry-redux
2019-03-22 08:22:29 +01:00
Akinwale Ariwodola
0d3415441f update to use new imports from lbryinc and lbry-redux 2019-03-20 15:37:14 +01:00
Akinwale Ariwodola
860d509d0f
Merge pull request #492 from lbryio/lbry.com
update lbry.io references to lbry.com
2019-03-20 15:02:20 +01:00
Akinwale Ariwodola
c86fdec8e6
Save media position (#489) 2019-03-20 15:01:21 +01:00
Akinwale Ariwodola
ca6fedd05c
Merge pull request #488 from lbryio/search-hint
shorten search hint
2019-03-15 14:37:14 +01:00
Akinwale Ariwodola
07209a79de
Merge pull request #487 from lbryio/channel-page-header
add channel name to channel page
2019-03-15 14:36:39 +01:00
Akinwale Ariwodola
4132416f0d shorten search hint 2019-03-15 13:18:45 +01:00
Akinwale Ariwodola
e62d5741c2 add channel name to channel page 2019-03-15 12:50:58 +01:00
Akinwale Ariwodola
81dca20b17
Merge pull request #480 from lbryio/playable-content
fix Play icon being displayed for non-playable content
2019-03-15 11:58:28 +01:00
Akinwale Ariwodola
f203f63c36 update lbry.io references to lbry.com 2019-03-11 18:16:17 +01:00
Akinwale Ariwodola
26cd218ec0 fix play icon being displayed for non-playable content 2019-03-11 12:11:42 +01:00
Akinwale Ariwodola
e402a0376a
implement direct search and show featured claim result (#468) 2019-03-11 12:09:08 +01:00
Akinwale Ariwodola
bac202d4ec
Pending Rewards (#467)
* show unclaimed rewards amount beside floating wallet balance
2019-03-11 09:47:14 +01:00
Akinwale Ariwodola
bb8d856d17
Merge pull request #469 from lbryio/send-log-android6
fix send log error on devices running Android 6 and lower
2019-03-09 08:41:14 +01:00
Akinwale Ariwodola
42075291ce fix send log error on devices running Android 6 and lower 2019-03-08 17:23:09 +01:00
Akinwale Ariwodola
32b128fe40
upgrade to sdk 0.32.4 (#458)
* upgrade to sdk 0.32.4
* update aiohttp version
* fix top margin on explore page
2019-03-06 15:11:26 +01:00
Akinwale Ariwodola
df63ab5f91 fix lodash vulnerability 2019-03-06 12:37:56 +01:00
Akinwale Ariwodola
88e3670493 fix merge module in package.json 2019-03-06 07:30:34 +01:00
Akinwale Ariwodola
eceeed8290 bumpversion 0.5.0 --> 0.6.0 2019-03-05 14:46:59 +01:00
Akinwale Ariwodola
caa9c80d44
Improved uri bar (#450)
* add descriptions to uri bar items
2019-03-05 10:17:50 +01:00
Akinwale Ariwodola
7e76e47d77
Merge pull request #449 from lbryio/improve-suggested-subs
add button to view subscriptions from the suggested subscriptions view
2019-03-05 10:17:22 +01:00
Akinwale Ariwodola
ba76c9c17e fix missing import on transaction history page 2019-03-04 17:14:55 +01:00
Akinwale Ariwodola
9555c6fa76 add button to view subscriptions from the suggested subscriptions view 2019-03-04 16:06:51 +01:00
Akinwale Ariwodola
c37a6f5c27
move uri omnibar to top (#444) 2019-03-01 19:25:16 +01:00
Akinwale Ariwodola
b5af71d798
improved back navigation with file URIs and drawer menu items (#443) 2019-03-01 19:25:01 +01:00
Akinwale Ariwodola
8f609fa900
0.5.0 rc (#436)
* fixes for release
* fix subscriptions view. change Latest First to Latest Only.
* fix channel subscription uri
* fix subscription notifications
* some iconography and label changes
* change sdk log level for release builds
* sort all subscriptions by newest first
* fix crash with Picasso thumbnail fetch operation
* add check for null / undefined filenames after stopping download
* update sdk to 0.32.3. fix download notification.
2019-02-22 04:28:11 +01:00
Akinwale Ariwodola
5329154121
updates for lbry sdk 0.32.0 (#427) 2019-02-18 20:43:14 +01:00
Akinwale Ariwodola
3a9187d795
App rating reminder (#428)
* updates for lbry sdk 0.32.0
* update package.json
* update interval to 7 days
2019-02-18 19:19:18 +01:00
Akinwale Ariwodola
e4e23e8017
added subscription view options - all and latest first (#425)
* added subscription view options - all and latest first
* persist subscriptions view mode
2019-02-18 09:30:06 +01:00
Akinwale Ariwodola
9638ad4f06
handle new email verification links (#426)
* handle new email verification links
* some updates to work with new auth flow
2019-02-18 07:50:32 +01:00
Akinwale Ariwodola
c8de700460 bumpversion 0.4.0 --> 0.5.0 2019-02-16 06:07:11 +01:00
Akinwale Ariwodola
e0f746b5ae Rename 'My LBRY' to Downloads 2019-02-11 17:40:24 +01:00
Akinwale Ariwodola
9efcc36e15
Merge pull request #424 from lbryio/channel-page-tweaks
* optimise space usage by the page navigation buttons on the channel page
* use full URIs for channel name links
2019-02-11 17:32:19 +01:00
Akinwale Ariwodola
918a7e64bd use full URIs for channelname links 2019-02-11 11:56:14 +01:00
Akinwale Ariwodola
7f6874b791
Suggested subscriptions (#423)
* suggested subscriptions implementation
* some style and loading tweaks
* add subscribe buttons and style tweaks
2019-02-08 16:48:35 +01:00
Akinwale Ariwodola
1731462b41 optimise space usage by the page navigation buttons on the channel page 2019-02-08 14:01:22 +01:00
Akinwale Ariwodola
654d50cd1b change app title to LBRY 2019-02-06 12:22:58 +01:00
Akinwale Ariwodola
f631dd5c7b bumpversion 0.3.1 --> 0.4.0 2019-01-31 15:58:33 +01:00
Akinwale Ariwodola
4c5558fa29
Merge pull request #420 from lbryio/pre-release-fixes
some tweaks before release
2019-01-31 15:57:02 +01:00
Akinwale Ariwodola
2892abc7a8 log final settings 2019-01-31 00:55:37 +01:00
Akinwale Ariwodola
529385bc5b display publish date on file page 2019-01-30 20:31:22 +01:00
Akinwale Ariwodola
e3bb5d0fb5 truncate long channel names on file page 2019-01-30 19:39:23 +01:00
Akinwale Ariwodola
2da930cd41 fix: claim content download path 2019-01-30 19:27:29 +01:00
Jack Robison
f41983a7b6 update and clean up lbrynetservice.py (#367) 2019-01-30 00:59:07 +01:00
Akinwale Ariwodola
198791ca27
display a thumbnail while the media player is loading (#413)
* show an overlay with the video thumbnail in the media player
2019-01-28 14:55:25 +01:00
Akinwale Ariwodola
5b02ed9b0b
Merge pull request #415 from lbryio/relative-publish-time
display relative published time for claims
2019-01-25 18:35:48 +01:00
Akinwale Ariwodola
760bad821b
View images or text claims immediately after downloading (#414)
* enable the download button to open images and text file types immediately after download
* change display text to View for downloaded image or text file claims
2019-01-24 23:01:19 +01:00
Akinwale Ariwodola
b8b2aab9bb display relative published time for claims 2019-01-24 21:22:12 +01:00
Akinwale Ariwodola
a2b08606f1
Merge pull request #412 from lbryio/recommendations-after-video-playback
automatically scroll to related content when a media file finishes playing
2019-01-23 23:02:15 +01:00
Akinwale Ariwodola
5d40bd6f8e fix: navigateBack missing variable on about page 2019-01-23 06:15:17 +01:00
Akinwale Ariwodola
91639d887f automatically scroll to related content when a media file finishes playing 2019-01-23 05:02:43 +01:00
Akinwale Ariwodola
6d234672b8
reorder items in drawer menu to match the desktop app menu (#410)
* reorder items in drawer menu to match the desktop app menu
* change icon for Explore
2019-01-22 21:17:21 +01:00
Akinwale Ariwodola
4e22b53907
Merge pull request #411 from lbryio/show-custom-reward-always
Always show the custom reward card
2019-01-22 20:23:34 +01:00
Akinwale Ariwodola
f389e315a6 dismiss soft keyboard upon claim button press 2019-01-22 14:33:30 +01:00
Akinwale Ariwodola
7f54c02a1c make the claim custom reward card always visible 2019-01-22 14:29:59 +01:00
Akinwale Ariwodola
eaaa2b97b4
Merge pull request #409 from lbryio/phone-verification-fail
show message for manual verification when phone verification fails
2019-01-21 20:26:37 +01:00
Akinwale Ariwodola
d1362f2ea3 show message for manual verification when phone verification fails 2019-01-21 18:53:01 +01:00
Akinwale Ariwodola
2c56c78467
Subscription notifications implementation (#407)
* add notifications for unread subscriptions
2019-01-21 17:11:31 +01:00
Akinwale Ariwodola
ec928c943d
better back button navigation handling (#408)
* better back button navigation handling
* add console=plain option to gradlew
2019-01-21 14:35:11 +01:00
Akinwale Ariwodola
53bfba0320 bumpversion 0.3.0 --> 0.3.1 2019-01-08 19:14:38 +01:00
Akinwale Ariwodola
847c3e85fa Add backup warning to wallet page. Sort subscriptions. 2019-01-08 18:39:10 +01:00
Akinwale Ariwodola
c96b4afcc7
Merge pull request #387 from lbryio/channel-page-pagination
add previous and next buttons to navigate channel pages
2019-01-08 03:03:09 +01:00
Akinwale Ariwodola
4c741b9ac9
remove the RECEIVE_SMS permission (#386) 2019-01-07 11:28:19 +01:00
Akinwale Ariwodola
6b184c49ad add previous and next buttons to navigate channel pages 2019-01-07 11:00:30 +01:00
Akinwale Ariwodola
6991b99ea9
Mobile subscriptions (#382)
* add subscribe button to file page
* add My Subscriptions page
* get module resolve babel plugin working to eliminate ugly imports
2019-01-07 08:26:47 +01:00
Akinwale Ariwodola
0cc2b4e368 fix for duplicates appearing on My LBRY page 2018-12-27 12:25:44 +01:00
Akinwale Ariwodola
c51f834636 update seeker circle colour 2018-12-27 09:08:34 +01:00
Akinwale Ariwodola
9a567ff5d0
Python 3.7 build (#381)
* Updated for Python 3.7.1
2018-12-27 09:04:21 +01:00
Akinwale Ariwodola
bb420542ef bumpversion 0.2.3 --> 0.3.0 2018-12-13 00:15:29 +01:00
Akinwale Ariwodola
14ec13a2e6 use transaction_id as the key for the list of claimed rewards 2018-12-13 00:15:29 +01:00
Akinwale Ariwodola
bf2b038632 reverse order of claimed rewards 2018-12-13 00:15:29 +01:00
Akinwale Ariwodola
b2fa6bb3a9 change font to Inter-UI. change LBRY green colour. 2018-12-13 00:15:29 +01:00
Akinwale Ariwodola
53166d9bba pin lbrynet to v0.30.1. set build_type to dev or release based on build config. 2018-12-13 00:15:29 +01:00
Akinwale Ariwodola
1560e44d36
Merge pull request #374 from lbryio/custom-reward-codes
Custom reward codes
2018-12-12 19:45:44 +01:00
Akinwale Ariwodola
1dbc8847b1 pin torba branch with fix for current_task 2018-12-11 20:14:31 +01:00
Akinwale Ariwodola
8bbfd1007d add support for custom reward codes 2018-12-11 19:37:48 +01:00
Akinwale Ariwodola
851e117381
Merge pull request #371 from lbryio/share-log-file
enable easy sharing of lbrynet log file
2018-12-03 12:35:55 +01:00
Akinwale Ariwodola
2e31a7fbdb enable easy sharing of lbrynet log file 2018-12-02 00:34:57 +01:00
Akinwale Ariwodola
f3316160fb
add support for special links (#369) 2018-12-01 23:56:33 +01:00
Akinwale Ariwodola
48b92ed2a6
fix for drawer menu and title text on OnePlus devices (#370)
* use Metropolis font for drawer menu items
* change title font to Metropolis
2018-12-01 23:07:21 +01:00
Akinwale Ariwodola
4d075095ad
implement send tip functionality (#366) 2018-11-28 15:44:08 +01:00
Akinwale Ariwodola
9c1985bab3 remove unused package-lock.json 2018-11-24 14:47:17 +01:00
Akinwale Ariwodola
e11e1a0d5b
Merge pull request #363 from lbryio/new-notifications
* move to new notification logic
* updates to handle the updated notification implementation in lbry-redux
2018-11-24 14:45:58 +01:00
Akinwale Ariwodola
f202797954 merge with master to fix package-lock.json conflict 2018-11-24 14:22:56 +01:00
Akinwale Ariwodola
f1ee7586f9 updates to handle the updated notification implementation in lbry-redux 2018-11-24 14:19:44 +01:00
Akinwale Ariwodola
6cc74488a3
Merge pull request #365 from lbryio/confirm-send-lbc
add confirmation dialog for sending LBC
2018-11-22 15:39:17 +01:00
Akinwale Ariwodola
dbf9760780 add confirmation dialog for sending LBC 2018-11-21 11:23:38 +01:00
Akinwale Ariwodola
6de1e41628
some updates to work with the latest lbrynet master (#364)
* build with lbrynet v0.30.1
* updates to use latest lbrynet master
* Disable DHT and hash announcer components.
* fix playback bug after download has started
2018-11-21 11:13:19 +01:00
Akinwale Ariwodola
9977aac9f6 make reward icon red 2018-11-21 11:09:54 +01:00
Sean Yesmunt
eb4995da86 move to new notificaion logic - UNTESTED 2018-11-20 12:07:12 -05:00
Alyssa Callahan
dffff47a9f
added dod 2018-11-12 14:48:16 -05:00
Thomas Zarebczan
96cc982e01
remove ? 2018-11-06 15:55:15 -05:00
Akinwale Ariwodola
116ab4fcfb
Merge pull request #355 from preserveddarnell/newcopyedits
Update typos & minor edits.
2018-11-01 05:33:22 +01:00
Akinwale Ariwodola
c9c0249d4f
React native error handling (#350)
* added react native error handler package
* implement Mixpanel error tracking
2018-11-01 05:31:38 +01:00
preserveddarnell
85833f91e3 Update typos & minor edits. 2018-10-29 15:56:35 -04:00
Akinwale Ariwodola
b76498852e
daemon 0.30 changes (#346) 2018-10-28 22:44:52 +01:00
Akinwale Ariwodola
e75b0e51d9
show Continue if an email is already set upon return (#347) 2018-10-28 22:43:48 +01:00
Akinwale Ariwodola
6b746bc0b3
Merge pull request #349 from lbryio/gradle-travis-fix
try setting JAVA_HOME
2018-10-28 20:06:15 +01:00
Akinwale Ariwodola
dd31a59524 try setting JAVA_HOME 2018-10-28 19:39:40 +01:00
Akinwale Ariwodola
ca75b44d3b
Merge pull request #348 from lbryio/pyjnius-recipe
update PyJNIus recipe
2018-10-28 19:21:31 +01:00
Akinwale Ariwodola
d9a9a310a8 update PyJNIus recipe 2018-10-28 19:20:40 +01:00
Akinwale Ariwodola
8ece8cc14d
Python 3 asyncio selectors fix (#344) 2018-10-28 19:12:40 +01:00
Akinwale Ariwodola
425a83faec
Improved stop download handling (#342) 2018-10-23 15:53:08 +01:00
Akinwale Ariwodola
f034b313b3
increased button touch areas and improved soft keyboard touch handling (#335) 2018-10-23 15:52:44 +01:00
Akinwale Ariwodola
b600cbdc34 update gradle compileJava configuration 2018-10-22 10:38:53 +01:00
Akinwale Ariwodola
ad3fce5b17
Merge pull request #337 from lbryio/faq
add android basics FAQ
2018-10-19 13:25:58 +01:00
Akinwale Ariwodola
25604657b6
Merge pull request #339 from lbryio/build-doc-updates
updated build instructions
2018-10-15 04:46:29 +01:00
Akinwale Ariwodola
996ff027e5 updated build instructions 2018-10-15 04:44:58 +01:00
Akinwale Ariwodola
71c595df15
Merge pull request #338 from lbryio/build-doc-updates
build documentation updates
2018-10-14 15:38:10 +01:00
Akinwale Ariwodola
70d00b7d62 build documentation updates 2018-10-14 11:23:04 +01:00
Thomas Zarebczan
e8828d8658
add android basics FAQ 2018-10-10 13:53:43 -04:00
Akinwale Ariwodola
e08f6ee73c
add / update recipes and build changes for Python 3.6.6 compatibility (#315)
* add / update recipes and build changes for Python 3.6.6 compatibility
* include Python 3 apt packages in travis build script
* use Python 3.6 in Travis
* Enable _blake2 and _sha3 in Python 3. Remove unnecessary files.
* change zope.interface version
* update cffi version
2018-10-07 15:59:03 +01:00
Akinwale Ariwodola
f12460e83a
display connected email on About page (#327)
* display connected email on About page
* add mailing preferences link
2018-10-07 15:55:01 +01:00
Akinwale Ariwodola
baef12a26d
refresh the reward list upon a successful reward claim (#329) 2018-10-07 14:23:45 +01:00
Akinwale Ariwodola
79400dd2b1
Merge pull request #328 from lbryio/reward-card-touch-area
make the entire reward card area respond to touch
2018-10-05 15:55:40 +01:00
Akinwale Ariwodola
4409849143 make the entire reward card area respond to touch 2018-10-04 13:57:15 +01:00
Akinwale Ariwodola
3d77756da0 bumpversion 0.2.2 --> 0.2.3 2018-10-03 07:16:02 +01:00
Akinwale Ariwodola
d45dac4587 bumpversion 0.2.1 --> 0.2.2 2018-09-30 17:00:39 +01:00
Akinwale Ariwodola
38292bcbcc
Merge pull request #316 from lbryio/stop-download-tweaks
improve stop download experience
2018-09-28 20:58:22 +01:00
Akinwale Ariwodola
8b8cf9cd7a improve stop download experience 2018-09-26 21:11:55 +01:00
Akinwale Ariwodola
7c969cbe93 fix for red screen during phone number verification 2018-09-26 17:55:03 +01:00
Akinwale Ariwodola
3283cc447e
Merge pull request #303 from ykris45/patch-1
add telegram link
2018-09-25 15:00:58 +01:00
Akinwale Ariwodola
810ba74e75
Merge pull request #313 from lbryio/blacklist
show blocked message for blacklisted content
2018-09-25 14:47:17 +01:00
Akinwale Ariwodola
5e1a20c5de
Merge pull request #314 from lbryio/dismiss-reward-summary
dismiss button added to reward summary, and some style tweaks.
2018-09-25 14:46:33 +01:00
Akinwale Ariwodola
975c59a114 dismiss button added to reward summary, and some style tweaks. 2018-09-24 14:59:00 +01:00
Akinwale Ariwodola
51fcf04b0b show blocked message for blacklisted content 2018-09-24 14:19:34 +01:00
Akinwale Ariwodola
d921347d73 updated readme for beta 2018-09-24 13:30:06 +01:00
YULIUS KURNIAWAN KRISTIANTO
5e25b542fb
add telegram link 2018-09-18 00:48:44 +07:00
Akinwale Ariwodola
9b4ef98a3d bumpversion 0.2.0 --> 0.2.1 2018-09-14 14:10:30 -04:00
Akinwale Ariwodola
8a862439cc do not display reward summary if the user is approved for rewards 2018-09-14 13:39:18 -04:00
Akinwale Ariwodola
6719953cf1 fix React Native bundle 2018-09-14 11:52:56 -04:00
Akinwale Ariwodola
2bf73eb961 update state if user data changed 2018-09-14 11:28:34 -04:00
Akinwale Ariwodola
fe5d711fea
Merge pull request #293 from lbryio/rewards-eligible-check
do not display phone verification action for users who are already reward approved
2018-09-14 08:58:07 -04:00
Akinwale Ariwodola
33c8aaf36f do not display phone verification action for users who are already reward approved 2018-09-14 04:06:23 -04:00
Akinwale Ariwodola
d5366b10fa
Merge pull request #292 from lbryio/build-doc-fix
update build instructions with missing packages
2018-09-14 03:56:56 -04:00
Akinwale Ariwodola
50d07fd31f update build instructions with missing packages 2018-09-10 15:43:27 -04:00
Akinwale Ariwodola
792d64a33a
Merge pull request #285 from lbryio/download-failed-callback
display the play / download button again upon a failure condition
2018-09-08 10:40:54 +01:00
Akinwale Ariwodola
adc9550e58 display the play / download button again upon a failure condition 2018-09-08 10:11:52 +01:00
Akinwale Ariwodola
0638b9f133
ongoing pre-beta tasks (#284)
* tapping on the player controls container while it is visible should hide the container
* change 'click' to 'tap'
* add related content component
* file list item resolving display tweaks
* increase number of search results to 25
* fix name display for identity claims in search results
2018-09-05 14:43:39 +01:00
Akinwale Ariwodola
05531e0bc5 change 'alpha' to 'beta' in wallet warning 2018-09-03 20:53:09 +01:00
Akinwale Ariwodola
44ec2270f2 update lbryinc in package.json 2018-09-03 20:47:01 +01:00
Akinwale Ariwodola
ffd4f474ed bumpversion 0.1.10 --> 0.2.0 2018-09-03 20:44:12 +01:00
Akinwale Ariwodola
2c22780c91
Merge pull request #281 from lbryio/mobile-platform
send Platform.OS as operating system value for the install/new request
2018-09-03 20:35:32 +01:00
Akinwale Ariwodola
1d03d09119 send Platform.OS as operating system value for the install/new request 2018-09-03 20:19:12 +01:00
Akinwale Ariwodola
404647c4cb
add storage stats card to My LBRY downloads page (#278)
* add storage stats card to My LBRY downloads page
* add decimalPoints parameter to formatBytes method
* some more tweaks to notifications and startup
* cancel all notifications if the service is not running when the activity is destroyed
2018-09-03 03:00:54 +01:00
Akinwale Ariwodola
c0b464ae36
implement phone verification (#274)
* implement phone verification
* update permissions in buildozer.spec
2018-09-03 02:57:54 +01:00
Akinwale Ariwodola
e8185e0f9c cancel specific notifications instead of using cancelAll 2018-09-02 17:54:37 +01:00
Akinwale Ariwodola
0592c42df0 Unify notification channels for background service and background media player 2018-09-02 11:38:15 +01:00
Akinwale Ariwodola
87a50c494f use openDrawer in react-navigation v2. Tweak hardware back button behaviour. 2018-09-02 08:32:09 +01:00
Akinwale Ariwodola
8257d7b41d
more navigation tweaks (#277)
* upgrade react-navigation module, implement associated code updates
* call resolveUri for a file list item if the claim is not yet resolved
2018-09-02 08:12:21 +01:00
Akinwale Ariwodola
77e471d671
Merge pull request #276 from lbryio/bg-media-notification-intent
group the background service and background media player notifications
2018-09-02 03:05:11 +01:00
Akinwale Ariwodola
92f5e6e77c group the background service and background media player notifications 2018-09-01 22:45:20 +01:00
Akinwale Ariwodola
4b7be60c27
better performance on lower end devices with react-native-fast-image (#275)
* thumbnail aspect ratio sizing tweaks
* show approximate values for formatted bytes
* truncate titles over 80 characters in the file item list component
2018-09-01 22:04:50 +01:00
Akinwale Ariwodola
e9abbf256e
implement my LBRY downloads page (#273) 2018-08-31 08:56:41 +01:00
Akinwale Ariwodola
002d8c7430
Merge pull request #272 from lbryio/search-results-tweaks
update thumbnail display in search results and add channel links
2018-08-31 00:51:00 +01:00
Akinwale Ariwodola
346c7a027d update thumbnail display in search results and add channel links 2018-08-31 00:39:25 +01:00
Akinwale Ariwodola
7313e2d1c4
implement touch to seek for media playback using the seek bar (#271) 2018-08-31 00:15:13 +01:00
Akinwale Ariwodola
a34a8136c2
add time to start (in seconds) to Play track event for new downloads (#269)
* add time to start (in seconds) to Play track event for new downloads
* send time_to_start parameter with file/view call
2018-08-30 18:11:03 +01:00
Akinwale Ariwodola
3b76dca8f1
Merge pull request #270 from lbryio/ux-tweaks
some file page UX tweaks
2018-08-30 14:39:41 +01:00
Akinwale Ariwodola
30682bf8f5
Merge pull request #267 from lbryio/back-navigation-part-deux
create navigation button component and handle onPress events properly
2018-08-30 14:38:46 +01:00
Akinwale Ariwodola
e7b83326d0 some file page UX tweaks 2018-08-30 13:48:29 +01:00
Akinwale Ariwodola
ef55bd2719 create navigation button component and handle onPress events properly 2018-08-29 21:19:49 +01:00
Akinwale Ariwodola
0c29785a7e
Merge pull request #265 from lbryio/thumbnails
tweak thumbnail aspect ratio and sizing on discover and search pages
2018-08-29 06:19:46 +01:00
Akinwale Ariwodola
a5b67d4923
Merge pull request #266 from lbryio/blob-delete-revisited
do not delete the sd hash blob when deleting file blobs
2018-08-29 01:01:00 +01:00
Akinwale Ariwodola
34a4df96fc do not delete the sd hash blob when deleting file blobs 2018-08-28 21:10:11 +01:00
Akinwale Ariwodola
eeacbbb979 tweak thumbnail aspect ratio and sizing on discover and search pages 2018-08-28 20:23:48 +01:00
Akinwale Ariwodola
2a010e2643 update package.json 2018-08-28 19:25:18 +01:00
Akinwale Ariwodola
c25785ccf4
Mobile rewards (#251) 2018-08-28 11:59:14 +01:00
Akinwale Ariwodola
050fc2b29e
tweaks to the download notifications (#260) 2018-08-28 07:29:12 +01:00
Akinwale Ariwodola
e1e8fa410a
escape special characters for the encoded path (#262) 2018-08-27 18:14:29 +01:00
Akinwale Ariwodola
becf21b7ea
Merge pull request #263 from lbryio/fix-search
submit search queries from the omnibar on the search page
2018-08-27 16:53:36 +01:00
Akinwale Ariwodola
9c3f2f44da
show animated activity indicator after the user presses the Play button (#261) 2018-08-27 16:53:03 +01:00
Akinwale Ariwodola
793541474a submit search queries from the omnibar on the search page 2018-08-27 09:01:05 +01:00
Akinwale Ariwodola
94f9ad6cc4
display floating wallet balance (#252)
* display floating wallet balance
2018-08-24 11:10:30 +01:00
Sean Yesmunt
9a89d4c44c
Merge pull request #250 from lbryio/search-selector
use new search suggestion selector
2018-08-22 11:13:41 -04:00
Akinwale Ariwodola
b99ffa0395
add stop action button to LBRY service notification (#248) 2018-08-22 13:50:59 +01:00
Akinwale Ariwodola
f926dc28be
Merge pull request #249 from lbryio/omnibar-text-alignment
URI bar text visible from the left when it's not focused
2018-08-21 06:10:10 +01:00
Sean Yesmunt
5b92d477e2 use new search suggestion selector 2018-08-21 00:30:36 -04:00
Akinwale Ariwodola
df561cc582
Background media controls (#242)
* create background control notification when background play is enabled
2018-08-20 16:00:16 +01:00
Akinwale Ariwodola
da60aeb71b
delete individual blob files for completed file downloads to save space (#234) 2018-08-17 19:11:15 +01:00
Akinwale Ariwodola
684f4867c3 URI bar text visible from the left when it's not focused 2018-08-17 15:08:19 +01:00
Akinwale Ariwodola
82a7846e6d
Merge pull request #238 from lbryio/hide-navigation-bar-fix
obtain the proper activity reference in the utility module
2018-08-16 19:27:54 +01:00
Akinwale Ariwodola
a9199661a4 obtain the proper activity reference in the utility module 2018-08-16 18:42:07 +01:00
Akinwale Ariwodola
d07fc29a96
Merge pull request #237 from lbryio/video-aspect-ratio-tweak
better media aspect ratio handling
2018-08-16 18:04:46 +01:00
Akinwale Ariwodola
066919259c better media aspect ratio handling 2018-08-16 17:50:59 +01:00
Akinwale Ariwodola
a094ba7d5c
Merge pull request #236 from lbryio/email-verify-tweak
tweaks to the user email verification process
2018-08-16 13:43:02 +01:00
Akinwale Ariwodola
76a9485f0b tweaks to the user email verification process 2018-08-16 13:21:28 +01:00
Akinwale Ariwodola
413ef66701
complete authentication flow and email verification link implementation (#232)
* complete authentication flow and email verification link implementation
* send appVersion and deviceId with authentication request
2018-08-16 10:48:34 +01:00
Akinwale Ariwodola
1e91a53a8a
Merge pull request #233 from lbryio/python-requirements-tweak
Update Twisted version. Remove pycrypto recipe.
2018-08-15 17:02:21 +01:00
Akinwale Ariwodola
0db7e51d69 bumpversion 0.1.9 --> 0.1.10 2018-08-14 18:23:59 +01:00
Akinwale Ariwodola
cdf7f75058
Merge pull request #231 from lbryio/notification-channel-hotfix
Fix service notification channel for older Android versions (prior to Oreo)
2018-08-14 18:19:32 +01:00
Akinwale Ariwodola
84e4151f42 use new libgmp mirror for builds 2018-08-14 17:45:54 +01:00
Akinwale Ariwodola
3a9729de06 Fix service notification channel for older Android versions (prior to Oreo) 2018-08-14 16:15:04 +01:00
Akinwale Ariwodola
93e8882433 bumpversion 0.1.8 --> 0.1.9 2018-08-14 08:13:38 +01:00
Akinwale Ariwodola
56a49e323a
Merge pull request #229 from lbryio/uri-encode-paths
Uri encode filenames with spaces for the media player
2018-08-14 07:51:05 +01:00
Akinwale Ariwodola
de97703128
Merge pull request #230 from lbryio/daemon-status-tweaks
update status call on About page and some style tweaks
2018-08-13 22:04:37 +01:00
Akinwale Ariwodola
f820d19f55 search results style tweak 2018-08-13 21:51:17 +01:00
Akinwale Ariwodola
a2094e9953 update status call on About page and some style tweaks 2018-08-13 21:40:46 +01:00
Akinwale Ariwodola
e5000f6502 splash screen downloading_headers flag tweak 2018-08-13 15:49:12 +01:00
Akinwale Ariwodola
9d63c50a2d Uri encode filenames with spaces for the media player 2018-08-13 10:04:02 +01:00
Akinwale Ariwodola
ee90951945
Use redux-persist-filesystem-storage engine due to AsyncStorage size limitation on Android (#227) 2018-08-13 10:00:02 +01:00
Akinwale Ariwodola
8ed87d0739
Merge pull request #228 from lbryio/media-aspect-ratio
improved aspect ratio for videos on the file page
2018-08-13 09:59:32 +01:00
Akinwale Ariwodola
1ebac0df21 improved aspect ratio for videos on the file page 2018-08-13 08:48:06 +01:00
Akinwale Ariwodola
a4e6025607
Daemon 0.21 updates (#223) 2018-08-13 07:12:13 +01:00
Akinwale Ariwodola
6ef03b8921
Merge pull request #226 from lbryio/animated-gifs
ImageView animated gif support
2018-08-12 23:33:06 +01:00
Akinwale Ariwodola
fdd6c87a31 ImageView animated gif support 2018-08-12 14:45:38 +01:00
Akinwale Ariwodola
89bfc845f6
Build and package modifications for react-native-video module updates (#225)
* Build and package modifications for react-native-video module updates
* change Android appcompat v7 lib version to 27.1.1
2018-08-11 20:48:54 +01:00
Akinwale Ariwodola
9af5c0e0f4
Merge pull request #224 from lbryio/download-notification-icon
change download notification icon
2018-08-09 22:44:58 +01:00
Akinwale Ariwodola
8e92b21d60 change download notification icon 2018-08-09 21:42:17 +01:00
Akinwale Ariwodola
9882d9d1c9 FontAwesome 5 everywhere 2018-08-08 18:11:25 +01:00
Akinwale Ariwodola
55275e48de
Update react-native-vector-icons package to 5.0.0 for FontAwesome 5 (#222) 2018-08-08 17:52:26 +01:00
Akinwale Ariwodola
3da896d369
Merge pull request #221 from lbryio/delete-button
Delete and Stop download button tweaks
2018-08-08 17:27:07 +01:00
Akinwale Ariwodola
745aa61466 Delete and Stop download button tweaks 2018-08-08 16:22:56 +01:00
Akinwale Ariwodola
2672144dbe
Merge pull request #220 from lbryio/play-icon
Add play icon to the Play button for media
2018-08-08 15:53:09 +01:00
Akinwale Ariwodola
ccbad4be1b
Merge pull request #219 from lbryio/desc-divider
add visual break before file description (if present)
2018-08-08 15:39:43 +01:00
Akinwale Ariwodola
dad3b86ba7 Add play icon to the Play button for media 2018-08-08 15:29:01 +01:00
Akinwale Ariwodola
cfb81fc530 add visual break before file description (if present) 2018-08-08 15:12:33 +01:00
Akinwale Ariwodola
56afde24db update service description 2018-08-06 18:16:50 +01:00
Akinwale Ariwodola
88fdc1b503
Android Oreo tweaks (#217)
* display notifications on Android 8.0 Oreo and higher using required notification channels
* fix daemon background service implementation for Android Oreo
2018-08-06 11:51:55 +01:00
Akinwale Ariwodola
338cd20132
Merge pull request #215 from lbryio/social-drivers
added Discord and social media links to the About page
2018-07-31 19:10:04 +01:00
Akinwale Ariwodola
ad38a09052 added Discord and social media links to the About page 2018-07-31 15:45:33 +01:00
Akinwale Ariwodola
078e010c54
Merge pull request #212 from lbryio/splash-screen-back
prevent an error upon pressing the back button on the splash screen
2018-07-31 15:39:30 +01:00
Akinwale Ariwodola
4ae4a7366a
Merge pull request #214 from lbryio/fullscreen-navigation-bar
hide navigation bar in fullscreen playback mode
2018-07-31 15:27:11 +01:00
Akinwale Ariwodola
bfefc53040 hide navigation bar in fullscreen playback mode 2018-07-29 09:12:45 +01:00
Akinwale Ariwodola
f8af04ba4b prevent an error upon pressing the back button on the splash screen 2018-07-24 14:37:31 +01:00
Akinwale Ariwodola
e8a572032a
Fullscreen scrubber (#205)
* fix problems with fullscreen scrubber adjustments
2018-07-24 14:28:45 +01:00
Shawn Khameneh
5ef300b4a4 Add Vagrantfile for easier development environments (#138)
* Add Vagrantfile for easier development envrionments
* Adjust Vagrantfile and create buildozer.spec.vagrant, sucessful builds
* Fix permissions
2018-07-23 15:16:55 +01:00
Akinwale Ariwodola
5e3275e547
Merge pull request #204 from lbryio/keep-awake 2018-07-18 13:23:16 +01:00
Akinwale Ariwodola
5a55beee7b Merge remote-tracking branch 'origin/master' into keep-awake 2018-07-18 13:00:08 +01:00
Akinwale Ariwodola
b8e52e2117
tweaks to media display in landscape mode (#197)
* tweaks to media display in landscape mode
2018-07-17 17:59:58 +01:00
Akinwale Ariwodola
541f824909
Merge pull request #198 from lbryio/media-player-scrubber
added a delay to seeking state reset
2018-07-17 17:18:10 +01:00
Daniel Dominguez
4e763be6ec Add Java module to keep the screen awake when needed. 2018-07-11 23:15:40 -03:00
Akinwale Ariwodola
afaa00d635
Link effect (#199)
* Add style to link on video file on tap. Adds a timeout to set it to false as Linking has a weird behavior when chrome vs youtube page is open.
* Add link to be semi-transparent onPress instead of green background.
2018-07-06 02:00:24 +01:00
Akinwale Ariwodola
1aa03edf6e added a delay to seeking state reset 2018-07-05 17:45:55 +01:00
Akinwale Ariwodola
cafada6ede Use HTML for screenshot in README 2018-06-30 12:30:48 +01:00
Akinwale Ariwodola
36e0127e2b changed image width 2018-06-30 12:28:49 +01:00
Akinwale Ariwodola
0af369bf23 added screenshot to README 2018-06-30 12:25:57 +01:00
Akinwale Ariwodola
a133f7d82d
Merge pull request #190 from lbryio/media-play-button
Use Play as button text on the file page for audio/video
2018-06-28 09:15:55 +01:00
Akinwale Ariwodola
f66b8affb1 Use Play as button text on the file page for audio/video 2018-06-24 09:33:02 +01:00
Akinwale Ariwodola
45ab233d01
Merge pull request #188 from lbryio/headers-download-progress
add blockchain_headers download progress bar to splash screen
2018-06-22 18:54:37 +01:00
Akinwale Ariwodola
676617ef19
Merge pull request #186 from lbryio/discover-resolve
display activity indicator for discover and trending items while resolving
2018-06-22 18:43:34 +01:00
Akinwale Ariwodola
af3baa99b8
Merge pull request #189 from lbryio/phone-state-permission-fix
request for READ_PHONE_STATE permission after storage permission is granted
2018-06-22 02:27:34 +01:00
Akinwale Ariwodola
33abefdd14 request for READ_PHONE_STATE permission after storage permission is granted 2018-06-22 02:18:38 +01:00
Akinwale Ariwodola
1cbebd0c9e add blockchain_headers download progress bar to splash screen 2018-06-22 02:06:21 +01:00
Akinwale Ariwodola
245942ff14
added method to MainActivity to obtain a device ID (#182) 2018-06-20 19:07:20 +01:00
Akinwale Ariwodola
608a08d2e8 display activity indicator for discover and trending items while resolving 2018-06-20 05:52:04 +01:00
Akinwale Ariwodola
fbb0d7090b
Merge pull request #185 from lbryio/link-styling
make all links green
2018-06-19 22:46:34 +01:00
Akinwale Ariwodola
40c890e644 make all links green 2018-06-19 21:58:26 +01:00
Akinwale Ariwodola
35cf4255a6
Merge pull request #183 from lbryio/start-blockchain-dl
Start daemon service immediately app starts (even for first run)
2018-06-18 15:01:09 +01:00
Akinwale Ariwodola
0da47c409f Start daemon service immediately app starts (even for first run) 2018-06-18 14:20:37 +01:00
Akinwale Ariwodola
541f582ac1
Build on commit (#181)
* Build release APK on every commit
2018-06-14 21:12:44 +01:00
Akinwale Ariwodola
191bc33fa3 bumpversion 0.1.7 --> 0.1.8 2018-06-11 19:24:26 +01:00
Akinwale Ariwodola
31168d9ed8
Merge pull request #166 from lbryio/first-run-improvements
implement extendable first run experience starting with welcome page
2018-06-11 04:41:55 +01:00
Akinwale Ariwodola
468c41c526 implement extendable first run experience starting with welcome page 2018-06-08 09:13:45 +01:00
Akinwale Ariwodola
bc684b6ae3
Merge pull request #158 from lbryio/about-page-text
add a paragraph and links to the About page
2018-06-08 06:30:10 +01:00
Akinwale Ariwodola
399ec8d108
Make channel names displayed on file items and the file page touchable (#165) 2018-06-07 06:57:41 +01:00
Akinwale Ariwodola
1820710f06
Merge pull request #160 from lbryio/linkify-description
make links in file descriptions clickable
2018-06-07 05:00:33 +01:00
Akinwale Ariwodola
51d86148e8
Merge pull request #164 from lbryio/navigation-tweaks
set the unique navigation keys for the file pages to the URIs.
2018-06-06 09:29:24 +01:00
Akinwale Ariwodola
e8f973531b set the unique navigation keys for the file pages to the URIs. 2018-06-06 09:25:51 +01:00
Akinwale Ariwodola
4a01cf0608
Merge pull request #162 from lbryio/trending-page
add trending page
2018-06-06 01:25:16 +01:00
Akinwale Ariwodola
929a057e1e add trending page 2018-06-05 19:52:10 +01:00
Akinwale Ariwodola
d24a18023d make links in file descriptions clickable 2018-06-05 19:03:40 +01:00
Akinwale Ariwodola
4d8085a0db add a paragraph and links to the About page 2018-06-05 15:53:10 +01:00
Akinwale Ariwodola
8c3ca2161d
Merge pull request #156 from lbryio/search-result-urls
Add URI to search result items. Update omnibar URI suggestions display.
2018-06-04 17:34:38 +01:00
Akinwale Ariwodola
26720dead0
Wallet page improvements (#155)
* wallet page send form improvements
* style tweaks for the send form input fields
2018-06-04 17:34:03 +01:00
Akinwale Ariwodola
cda7e81485
Merge pull request #157 from lbryio/omnibar-file-suggestion
change icon for URIs linking to actual file claims
2018-06-03 13:53:10 +01:00
Akinwale Ariwodola
0cffb26dfc change icon for URIs linking to actual file claims 2018-06-03 13:51:02 +01:00
Akinwale Ariwodola
d21e4aa830 Add URI to search result items. Update omnibar URI suggestions display. 2018-06-03 13:46:43 +01:00
Akinwale Ariwodola
a5dfe0c586 Update Twisted version. Remove pycrypto recipe. 2018-06-03 12:20:15 +01:00
1311 changed files with 63004 additions and 52718 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. -->

View file

@ -5,7 +5,7 @@ To make it possible for us to help you, please fill out below information carefu
Before reporting any issues, please make sure that you're using the latest version.
We are also available on live chat at https://chat.lbry.io
We are also available on live chat at https://chat.lbry.com
-->
@ -34,3 +34,22 @@ Tell us what happens instead
## Screenshots
<!-- If a screenshot would help explain the bug, please include one or two here -->
## Internal Use
### Acceptance Criteria
1.
2.
3.
### Definition of Done
- [ ] Tested against acceptance criteria
- [ ] Tested against the assumptions of the user story
- [ ] The project builds without errors
- [ ] Unit tests are written and passing
- [ ] Tests on devices/browsers listed in the issue have passed
- [ ] QA performed & issues resolved
- [ ] Refactoring completed
- [ ] Any configuration or build changes documented
- [ ] Documentation updated
- [ ] Peer Code Review performed

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

@ -0,0 +1 @@

76
.gitignore vendored
View file

@ -1,9 +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
*.hprof
app/build
bin
app/debuglib

75
.gitlab-ci.yml Normal file
View file

@ -0,0 +1,75 @@
stages:
- build
- deploy
- release
build apk:
stage: build
image: lbry/android-base:platform-28
before_script:
- 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__arm.apk
- bin/browser-*-release__arm64.apk
expire_in: 1 week
script:
- export PATH=/usr/bin:$PATH
- 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: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
- 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__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: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
- 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__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 @@

BIN
.gitsecret/keys/pubring.kbx Normal file

Binary file not shown.

Binary file not shown.

BIN
.gitsecret/keys/random_seed Normal file

Binary file not shown.

BIN
.gitsecret/keys/trustdb.gpg Normal file

Binary file not shown.

View file

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

View file

@ -1,77 +0,0 @@
sudo: required
dist: trusty
language: python
python:
- '2.7'
install:
- deactivate
- export PATH=/usr/bin:$PATH
- sudo dpkg --add-architecture i386
- sudo apt-get -qq update
- sudo apt-get -qq install 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
- sudo pip install --upgrade cython==0.25.2 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://dl.google.com/android/repository/android-ndk-r13b-linux-x86_64.zip' -P ~/.buildozer/android/platform/
- wget -q 'https://dl.google.com/android/android-sdk_r23-linux.tgz' -P ~/.buildozer/android/platform/
- wget -q 'https://dl.google.com/android/repository/android-23_r02.zip' -P ~/.buildozer/android/platform/
- wget -q 'https://dl.google.com/android/repository/build-tools_r26.0.1-linux.zip' -P ~/.buildozer/android/platform/
- unzip -qq ~/.buildozer/android/platform/android-ndk-r13b-linux-x86_64.zip -d ~/.buildozer/android/platform/
- 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/android-23_r02.zip -d ~/.buildozer/android/platform/android-sdk-23/platforms
- mv ~/.buildozer/android/platform/android-sdk-23/platforms/android-6.0 ~/.buildozer/android/platform/android-sdk-23/platforms/android-23
- mkdir -p ~/.buildozer/android/platform/android-sdk-23/build-tools
- unzip -qq ~/.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
- mkdir -p ~/.buildozer/android/platform/android-sdk-23/licenses
- echo $'\nd56f5187479451eabf01fb78af6dfcb131a6481e' > ~/.buildozer/android/platform/android-sdk-23/licenses/android-sdk-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
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

View file

@ -1,76 +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
* Android NDK
* Buildozer
* Node.js
* npm
#### Apt Packages
Based on the quickstart instructions at http://buildozer.readthedocs.io/en/latest/installation.html
```
sudo dpkg --add-architecture i386
sudo apt-get update
sudo apt-get install 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
```
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
```
sudo pip install --upgrade cython==0.25.2 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 (eg. browser) |
| package.domain | package domain (eg. 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 (13b has been tested to result in a successful build) |
| android.ndk_path | Android NDK path. buildozer will automatically download this if not set |
| android.sdk_path | Android SDK path. buildozer will automatically download this if not set |
| 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 |
#### 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,19 +1,36 @@
# LBRY Android
[![Build Status](https://travis-ci.org/lbryio/lbry-android.svg?branch=master)](https://travis-ci.org/lbryio/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.
<img src="https://spee.ch/@lbry:3f/android-08-homepage.gif" alt="LBRY Android GIF" width="384px" />
An Android browser and wallet for the [LBRY](https://lbry.io) 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.
## Installation
The minimum supported Android version is 5.0 Lollipop. There are two ways to install:
1. Via the Google Play Store. While in alpha, it will not show in the Play Store unless you sign up [here](https://lbry.io/android-alpha).
1. Via the Google Play Store. Anyone can join the [open beta](https://play.google.com/apps/testing/io.lbry.browser) in order to install the app from the Play Store.
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 homescreen if that was created upon install.
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
@ -22,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.io 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.io)
The primary contact for this project is [@akinwale](https://github.com/akinwale) (akinwale@lbry.com)

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;

6829
app/package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,31 +0,0 @@
{
"name": "LBRYApp",
"version": "0.0.1",
"private": "true",
"scripts": {
"start": "node node_modules/react-native/local-cli/cli.js start"
},
"dependencies": {
"lbry-redux": "lbryio/lbry-redux",
"moment": "^2.22.1",
"react": "16.2.0",
"react-native": "0.55.3",
"react-native-image-zoom-viewer": "^2.2.5",
"react-native-vector-icons": "^4.5.0",
"react-native-video": "2.0.0",
"react-navigation": "^1.5.12",
"react-navigation-redux-helpers": "^1.0.1",
"react-redux": "^5.0.3",
"redux": "^3.6.0",
"redux-logger": "3.0.6",
"redux-persist": "^4.8.0",
"redux-persist-transform-compress": "^4.2.0",
"redux-persist-transform-filter": "0.0.10",
"redux-thunk": "^2.2.0"
},
"devDependencies": {
"babel-preset-env": "^1.6.1",
"babel-preset-stage-2": "^6.18.0",
"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 {
}

View file

@ -1,212 +0,0 @@
import React from 'react';
import AboutPage from '../page/about';
import DiscoverPage from '../page/discover';
import FilePage from '../page/file';
import SearchPage from '../page/search';
import SettingsPage from '../page/settings';
import SplashScreen from '../page/splash';
import TransactionHistoryPage from '../page/transactionHistory';
import WalletPage from '../page/wallet';
import SearchInput from '../component/searchInput';
import {
addNavigationHelpers,
DrawerNavigator,
StackNavigator,
NavigationActions
} from 'react-navigation';
import { connect } from 'react-redux';
import { addListener } from '../utils/redux';
import {
AppState,
AsyncStorage,
BackHandler,
Linking,
NativeModules,
TextInput,
ToastAndroid
} from 'react-native';
import { SETTINGS, doHideNotification, selectNotification } from 'lbry-redux';
import { makeSelectClientSetting } from '../redux/selectors/settings';
import Feather from 'react-native-vector-icons/Feather';
import discoverStyle from '../styles/discover';
import searchStyle from '../styles/search';
import SearchRightHeaderIcon from "../component/searchRightHeaderIcon";
const discoverStack = StackNavigator({
Discover: {
screen: DiscoverPage,
navigationOptions: ({ navigation }) => ({
title: 'Discover',
headerLeft: <Feather name="menu" size={24} style={discoverStyle.drawerHamburger} onPress={() => navigation.navigate('DrawerOpen')} />,
})
},
File: {
screen: FilePage,
navigationOptions: {
header: null,
drawerLockMode: 'locked-closed'
}
},
Search: {
screen: SearchPage,
navigationOptions: ({ navigation }) => ({
drawerLockMode: 'locked-closed'
})
}
}, {
headerMode: 'screen',
});
const walletStack = StackNavigator({
Wallet: {
screen: WalletPage,
navigationOptions: ({ navigation }) => ({
title: 'Wallet',
headerLeft: <Feather name="menu" size={24} style={discoverStyle.drawerHamburger} onPress={() => navigation.navigate('DrawerOpen')} />,
})
},
TransactionHistory: {
screen: TransactionHistoryPage,
navigationOptions: {
title: 'Transaction History',
drawerLockMode: 'locked-closed'
}
}
}, {
headerMode: 'screen'
});
const drawer = DrawerNavigator({
DiscoverStack: { screen: discoverStack },
WalletStack: { screen: walletStack },
Settings: { screen: SettingsPage, navigationOptions: { drawerLockMode: 'locked-closed' } },
About: { screen: AboutPage, navigationOptions: { drawerLockMode: 'locked-closed' } }
}, {
drawerWidth: 300,
headerMode: 'none'
});
export const AppNavigator = new StackNavigator({
Splash: {
screen: SplashScreen,
navigationOptions: {
drawerLockMode: 'locked-closed'
}
},
Main: {
screen: drawer
}
}, {
headerMode: 'none'
});
class AppWithNavigationState extends React.Component {
static supportedDisplayTypes = ['toast'];
componentWillMount() {
AppState.addEventListener('change', this._handleAppStateChange);
BackHandler.addEventListener('hardwareBackPress', function() {
const { dispatch, nav } = this.props;
// There should be a better way to check this
if (nav.routes.length > 0) {
const subRoutes = nav.routes[0].routes[0].routes;
const lastRoute = subRoutes[subRoutes.length - 1];
if (nav.routes[0].routes[0].index > 0 &&
['About', 'Settings'].indexOf(lastRoute.key) > -1) {
dispatch(NavigationActions.back());
return true;
}
if (nav.routes[0].routeName === 'Main') {
if (nav.routes[0].routes[0].routes[0].index > 0) {
dispatch(NavigationActions.back());
return true;
}
}
}
return false;
}.bind(this));
}
componentDidMount() {
Linking.addEventListener('url', this._handleUrl);
}
componentWillUnmount() {
AppState.removeEventListener('change', this._handleAppStateChange);
BackHandler.removeEventListener('hardwareBackPress');
Linking.removeEventListener('url', this._handleUrl);
}
componentWillUpdate(nextProps) {
const { dispatch } = this.props;
const { notification } = nextProps;
if (notification) {
const { displayType, message } = notification;
let currentDisplayType;
if (displayType.length) {
for (let i = 0; i < displayType.length; i++) {
const type = displayType[i];
if (AppWithNavigationState.supportedDisplayTypes.indexOf(type) > -1) {
currentDisplayType = type;
break;
}
}
} else if (AppWithNavigationState.supportedDisplayTypes.indexOf(displayType) > -1) {
currentDisplayType = displayType;
}
if ('toast' === currentDisplayType) {
ToastAndroid.show(message, ToastAndroid.SHORT);
}
dispatch(doHideNotification());
}
}
_handleAppStateChange = (nextAppState) => {
// 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');
}
});
}
}
_handleUrl = (evt) => {
const { dispatch } = this.props;
if (evt.url) {
const navigateAction = NavigationActions.navigate({
routeName: 'File',
key: 'filePage',
params: { uri: evt.url }
});
dispatch(navigateAction);
}
}
render() {
const { dispatch, nav } = this.props;
return (
<AppNavigator
navigation={addNavigationHelpers({
dispatch,
state: nav,
addListener,
})}
/>
);
}
}
const mapStateToProps = state => ({
nav: state.nav,
notification: selectNotification(state),
keepDaemonRunning: makeSelectClientSetting(SETTINGS.KEEP_DAEMON_RUNNING)(state),
showNsfw: makeSelectClientSetting(SETTINGS.SHOW_NSFW)(state)
});
export default connect(mapStateToProps)(AppWithNavigationState);

View file

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

View file

@ -1,29 +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,
doNotify: ({ message: string, displayType: Array<string> }) => void,
};
export default class Address extends React.PureComponent<Props> {
render() {
const { address, doNotify, 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);
doNotify({
message: 'Address copied',
displayType: ['toast'],
});
}} />
</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,41 +0,0 @@
import React from 'react';
import { Text, TouchableOpacity } from 'react-native';
import buttonStyle from '../../styles/button';
import Icon from 'react-native-vector-icons/FontAwesome';
export default class Button extends React.PureComponent {
render() {
const {
disabled,
style,
text,
icon,
onPress
} = 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);
}
return (
<TouchableOpacity disabled={disabled} style={styles} onPress={onPress}>
{icon && <Icon name={icon} size={18} color='#ffffff' class={buttonStyle.icon} /> }
{text && (text.trim().length > 0) && <Text style={textStyles}>{text}</Text>}
</TouchableOpacity>
);
}
};

View file

@ -1,25 +0,0 @@
import { connect } from 'react-redux';
import {
doFetchCostInfoForUri,
makeSelectFileInfoForUri,
makeSelectDownloadingForUri,
makeSelectLoadingForUri,
makeSelectCostInfoForUri
} from 'lbry-redux';
import { doPurchaseUri, 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 => dispatch(doPurchaseUri(uri)),
restartDownload: (uri, outpoint) => dispatch(doStartDownload(uri, outpoint)),
fetchCostInfo: uri => dispatch(doFetchCostInfoForUri(uri)),
});
export default connect(select, perform)(FileDownloadButton);

View file

@ -1,86 +0,0 @@
import React from 'react';
import { NativeModules, Text, View, TouchableOpacity } from 'react-native';
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,
loading,
doPause,
style,
openFile
} = this.props;
if (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 === null && !downloading) {
if (!costInfo) {
return (
<View style={[style, fileDownloadButtonStyle.container]}>
<Text style={fileDownloadButtonStyle.text}>Fetching cost info...</Text>
</View>
);
}
return (
<TouchableOpacity style={[style, fileDownloadButtonStyle.container]} onPress={() => {
if (NativeModules.Mixpanel) {
NativeModules.Mixpanel.track('Purchase Uri', { Uri: uri });
}
purchaseUri(uri);
}}>
<Text style={fileDownloadButtonStyle.text}>Download</Text>
</TouchableOpacity>
);
} else if (fileInfo && fileInfo.download_path) {
return (
<TouchableOpacity style={[style, fileDownloadButtonStyle.container]} onPress={openFile}>
<Text style={fileDownloadButtonStyle.text}>Open</Text>
</TouchableOpacity>
);
}
return null;
}
}
export default FileDownloadButton;

View file

@ -1,26 +0,0 @@
import { connect } from 'react-redux';
import {
doResolveUri,
makeSelectClaimForUri,
makeSelectMetadataForUri,
makeSelectFileInfoForUri,
makeSelectIsUriResolving,
selectRewardContentClaimIds
} from 'lbry-redux';
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)
});
const perform = dispatch => ({
resolveUri: uri => dispatch(doResolveUri(uri)),
});
export default connect(select, perform)(FileItem);

View file

@ -1,79 +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 FileItemMedia from '../fileItemMedia';
import FilePrice from '../filePrice';
import NsfwOverlay from '../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);
}
}
render() {
const {
claim,
fileInfo,
metadata,
isResolvingUri,
rewardedContentClaimIds,
style,
navigation
} = this.props;
const uri = normalizeURI(this.props.uri);
const title = metadata && metadata.title ? metadata.title : uri;
const thumbnail = metadata && metadata.thumbnail ? metadata.thumbnail : null;
const obscureNsfw = this.props.obscureNsfw && metadata && metadata.nsfw;
const isRewardContent = claim && rewardedContentClaimIds.includes(claim.claim_id);
const channelName = claim ? claim.channel_name : null;
let description = '';
if (isResolvingUri && !claim) {
description = 'Loading...';
} else if (metadata && metadata.description) {
description = metadata.description;
} else if (claim === null) {
description = 'This address contains no content.';
}
return (
<View style={style}>
<TouchableOpacity style={discoverStyle.container} onPress={() => {
if (NativeModules.Mixpanel) {
NativeModules.Mixpanel.track('Discover Tap', { Uri: uri });
}
navigation.navigate({ routeName: 'File', key: 'filePage', params: { uri } });
}
}>
<FileItemMedia title={title} thumbnail={thumbnail} blurRadius={obscureNsfw ? 15 : 0} resizeMode="cover" />
<FilePrice uri={uri} style={discoverStyle.filePriceContainer} textStyle={discoverStyle.filePriceText} />
<Text style={discoverStyle.fileItemName}>{title}</Text>
{channelName &&
<Text style={discoverStyle.channelName}>{channelName}</Text>}
</TouchableOpacity>
{obscureNsfw && <NsfwOverlay onPress={() => navigation.navigate('Settings')} />}
</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,59 +0,0 @@
import React from 'react';
import { Text, Image, View } from 'react-native';
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,
];
componentWillMount() {
this.setState({
autoThumbStyle:
FileItemMedia.AUTO_THUMB_STYLES[
Math.floor(Math.random() * FileItemMedia.AUTO_THUMB_STYLES.length)
],
});
}
render() {
let style = this.props.style;
const { title, thumbnail, blurRadius, resizeMode } = this.props;
const atStyle = this.state.autoThumbStyle;
if (thumbnail && ((typeof thumbnail) === 'string')) {
if (style == null) {
style = fileItemMediaStyle.thumbnail;
}
return (
<Image source={{uri: thumbnail}}
blurRadius={blurRadius}
resizeMode={resizeMode ? resizeMode : "cover"}
style={style} />
);
}
return (
<View style={[style ? style : fileItemMediaStyle.autothumb, atStyle]}>
<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,184 +0,0 @@
// @flow
import * as React from 'react';
import { buildURI } from 'lbry-redux';
import { FlatList } from 'react-native';
import FileItem from '../fileItem';
import discoverStyle from '../../styles/discover';
// 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 { fileInfos, hideFilter, checkPending, navigation, 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}
data={items}
keyExtractor={(item, index) => item}
renderItem={({item}) => (
<FileItem style={discoverStyle.fileItem}
uri={item}
navigation={navigation} />
)} />
);
}
}
export default FileList;

View file

@ -1,20 +0,0 @@
import { connect } from 'react-redux';
import {
doFetchCostInfoForUri,
makeSelectCostInfoForUri,
makeSelectFetchingCostInfoForUri,
makeSelectClaimForUri
} from 'lbry-redux';
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={costInfo.cost}
isEstimate={isEstimate}
showFree
showFullPrice={showFullPrice}>???</CreditAmount>
</View>
);
}
}
export default FilePrice;

View file

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

View file

@ -1,38 +0,0 @@
import React from 'react';
import { Linking, Text, TouchableOpacity } from 'react-native';
export default class Link extends React.PureComponent {
handlePress = () => {
const { error, href, navigation, notify } = this.props;
if (navigation && href.startsWith('#')) {
navigation.navigate(href.substring(1));
} else {
Linking.openURL(href).catch(err => notify({
message: error,
displayType: ['toast']
}));
}
}
render() {
const {
onPress,
style,
text
} = this.props;
let styles = [];
if (style.length) {
styles = styles.concat(style);
} else {
styles.push(style);
}
return (
<TouchableOpacity onPress={onPress ? onPress : this.handlePress}>
<Text style={styles}>{text}</Text>
</TouchableOpacity>
);
}
};

View file

@ -1,11 +0,0 @@
import { connect } from 'react-redux';
import { SETTINGS } from 'lbry-redux';
import { makeSelectClientSetting } from '../../redux/selectors/settings';
import MediaPlayer from './view';
const select = state => ({
backgroundPlayEnabled: makeSelectClientSetting(SETTINGS.BACKGROUND_PLAY_ENABLED)(state),
});
const perform = dispatch => ({});
export default connect(select, perform)(MediaPlayer);

View file

@ -1,319 +0,0 @@
import React from 'react';
import { Lbry } from 'lbry-redux';
import {
NativeModules,
PanResponder,
Text,
View,
ScrollView,
TouchableOpacity
} from 'react-native';
import Video from 'react-native-video';
import Icon from 'react-native-vector-icons/FontAwesome';
import FileItemMedia from '../fileItemMedia';
import mediaPlayerStyle from '../../styles/mediaPlayer';
class MediaPlayer extends React.PureComponent {
static ControlsTimeout = 3000;
seekResponder = null;
seekerWidth = 0;
trackingOffset = 0;
tracking = null;
video = null;
constructor(props) {
super(props);
this.state = {
rate: 1,
volume: 1,
muted: false,
resizeMode: 'stretch',
duration: 0.0,
currentTime: 0.0,
paused: true,
fullscreenMode: false,
areControlsVisible: true,
controlsTimeout: -1,
seekerOffset: 0,
seekerPosition: 0,
firstPlay: true
};
}
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
});
if (this.props.onMediaLoaded) {
this.props.onMediaLoaded();
}
}
onProgress = (data) => {
this.setState({ currentTime: data.currentTime });
if (!this.state.seeking) {
this.setSeekerPosition(this.calculateSeekerPosition());
}
if (this.state.firstPlay) {
if (NativeModules.Mixpanel) {
const { uri } = this.props;
NativeModules.Mixpanel.track('Play', { Uri: uri });
}
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();
}
hidePlayerControls() {
const player = this;
let timeout = setTimeout(() => {
player.setState({ areControlsVisible: false });
}, MediaPlayer.ControlsTimeout);
player.setState({ controlsTimeout: timeout });
}
togglePlay = () => {
this.showPlayerControls();
this.setState({ paused: !this.state.paused });
}
toggleFullscreenMode = () => {
this.showPlayerControls();
const { onFullscreenToggled } = this.props;
this.setState({ fullscreenMode: !this.state.fullscreenMode }, () => {
this.setState({ resizeMode: this.state.fullscreenMode ? 'contain' : 'stretch' });
if (onFullscreenToggled) {
onFullscreenToggled(this.state.fullscreenMode);
}
});
}
onEnd = () => {
this.setState({ paused: true });
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) {
const offset = this.getTrackingOffset();
if (val < offset) {
val = offset;
} else if (val >= (offset + this.seekerWidth)) {
return offset + 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();
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.onEnd();
} else {
this.seekTo(time);
this.setState({ seeking: false });
}
this.hidePlayerControls();
}
});
}
getTrackingOffset() {
return this.state.fullscreenMode ? this.trackingOffset : 0;
}
getCurrentTimeForSeekerPosition() {
return this.state.duration * (this.state.seekerPosition / this.seekerWidth);
}
calculateSeekerPosition() {
if (this.state.fullscreenMode) {
return this.getTrackingOffset() + (this.seekerWidth * this.getCurrentTimePercentage());
}
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();
}
componentDidMount() {
}
componentWillUnmount() {
this.clearControlsTimeout();
this.setState({ paused: true, fullscreenMode: false });
const { onFullscreenToggled } = this.props;
if (onFullscreenToggled) {
onFullscreenToggled(false);
}
}
renderPlayerControls() {
if (this.state.areControlsVisible) {
return (
<View style={mediaPlayerStyle.playerControlsContainer}>
<TouchableOpacity style={mediaPlayerStyle.playPauseButton}
onPress={this.togglePlay}>
{this.state.paused && <Icon name="play" size={32} color="#ffffff" />}
{!this.state.paused && <Icon name="pause" size={32} 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;
}
render() {
const { backgroundPlayEnabled, fileInfo, thumbnail, style } = this.props;
const flexCompleted = this.getCurrentTimePercentage() * 100;
const flexRemaining = (1 - this.getCurrentTimePercentage()) * 100;
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}>
<Video source={{ uri: 'file:///' + fileInfo.download_path }}
ref={(ref: Video) => { this.video = ref }}
resizeMode={this.state.resizeMode}
playInBackground={backgroundPlayEnabled}
style={mediaPlayerStyle.player}
rate={this.state.rate}
volume={this.state.volume}
paused={this.state.paused}
onLoad={this.onLoad}
onProgress={this.onProgress}
onEnd={this.onEnd}
/>
<TouchableOpacity style={mediaPlayerStyle.playerControls} onPress={this.showPlayerControls}>
{this.renderPlayerControls()}
</TouchableOpacity>
{(!this.state.fullscreenMode || (this.state.fullscreenMode && this.state.areControlsVisible)) &&
<View style={trackingStyle} onLayout={(evt) => {
this.trackingOffset = evt.nativeEvent.layout.x;
this.seekerWidth = evt.nativeEvent.layout.width;
}}>
<View style={mediaPlayerStyle.progress}>
<View style={[mediaPlayerStyle.innerProgressCompleted, { flex: flexCompleted }]} />
<View style={[mediaPlayerStyle.innerProgressRemaining, { flex: flexRemaining }]} />
</View>
</View>}
{this.state.areControlsVisible &&
<View style={[mediaPlayerStyle.seekerHandle, { left: this.state.seekerPosition }]} { ...this.seekResponder.panHandlers }>
<View style={this.state.seeking ? mediaPlayerStyle.bigSeekerCircle : mediaPlayerStyle.seekerCircle} />
</View>}
</View>
);
}
}
export default MediaPlayer;

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,47 +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 Feather from 'react-native-vector-icons/Feather';
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>
<TouchableOpacity style={pageHeaderStyle.left}>
<Feather name="arrow-left" size={24} onPress={onBackPressed} style={pageHeaderStyle.backIcon} />
</TouchableOpacity>
</View>
</View>
</View>
);
}
}
export default PageHeader;

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.Mixpanel) {
NativeModules.Mixpanel.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,24 +0,0 @@
import { connect } from 'react-redux';
import {
doResolveUri,
makeSelectClaimForUri,
makeSelectMetadataForUri,
makeSelectFileInfoForUri,
makeSelectIsUriResolving,
} from 'lbry-redux';
import { selectShowNsfw } from '../../redux/selectors/settings';
import SearchResultItem from './view';
const select = (state, props) => ({
claim: makeSelectClaimForUri(props.uri)(state),
isDownloaded: !!makeSelectFileInfoForUri(props.uri)(state),
metadata: makeSelectMetadataForUri(props.uri)(state),
isResolvingUri: makeSelectIsUriResolving(props.uri)(state),
obscureNsfw: !selectShowNsfw(state)
});
const perform = dispatch => ({
resolveUri: uri => dispatch(doResolveUri(uri))
});
export default connect(select, perform)(SearchResultItem);

View file

@ -1,53 +0,0 @@
import React from 'react';
import { normalizeURI, parseURI } from 'lbry-redux';
import { Text, TouchableOpacity, View } from 'react-native';
import FileItemMedia from '../fileItemMedia';
import NsfwOverlay from '../../component/nsfwOverlay';
import searchStyle from '../../styles/search';
class SearchResultItem extends React.PureComponent {
render() {
const {
claim,
metadata,
isResolvingUri,
showUri,
isDownloaded,
style,
onPress,
navigation
} = this.props;
const uri = normalizeURI(this.props.uri);
const obscureNsfw = this.props.obscureNsfw && metadata && metadata.nsfw;
const title = metadata && metadata.title ? metadata.title : parseURI(uri).contentName;
let name;
let channel;
if (claim) {
name = claim.name;
channel = claim.channel_name;
}
return (
<View style={style}>
<TouchableOpacity style={style} onPress={onPress}>
<View style={searchStyle.thumbnailContainer}>
<FileItemMedia style={searchStyle.thumbnail}
blurRadius={obscureNsfw ? 15 : 0}
title={title}
thumbnail={metadata ? metadata.thumbnail : null} />
</View>
<View style={searchStyle.detailsContainer}>
{isResolvingUri && <Text style={searchStyle.loading}>Loading...</Text>}
{!isResolvingUri && <Text style={searchStyle.title}>{title || name}</Text>}
{!isResolvingUri && channel && <Text style={searchStyle.publisher}>{channel}</Text>}
</View>
</TouchableOpacity>
{obscureNsfw && <NsfwOverlay onPress={() => navigation.navigate('Settings')} />}
</View>
);
}
}
export default SearchResultItem;

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,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,59 +0,0 @@
// @flow
import React from 'react';
import { Text, View, Linking } from 'react-native';
import { buildURI, formatCredits } from 'lbry-redux';
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={() => navigation && navigation.navigate({
routeName: 'File',
key: 'filePage',
params: { uri: 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.io/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,17 +0,0 @@
import { connect } from 'react-redux';
import { doUpdateSearchQuery, selectSearchState as selectSearch } from 'lbry-redux';
import UriBar from './view';
const select = state => {
const { ...searchState } = selectSearch(state);
return {
...searchState
};
};
const perform = dispatch => ({
updateSearchQuery: query => dispatch(doUpdateSearchQuery(query)),
});
export default connect(select, perform)(UriBar);

View file

@ -1,38 +0,0 @@
// @flow
import React from 'react';
import { SEARCH_TYPES, normalizeURI } from 'lbry-redux';
import { Text, TouchableOpacity, View } from 'react-native';
import Feather from 'react-native-vector-icons/Feather';
import uriBarStyle from '../../../styles/uriBar';
class UriBarItem extends React.PureComponent {
render() {
const { item, onPress } = this.props;
const { type, value } = item;
let icon;
switch (type) {
case SEARCH_TYPES.CHANNEL:
icon = <Feather name="at-sign" size={18} />
break;
case SEARCH_TYPES.SEARCH:
icon = <Feather name="search" size={18} />
break;
case SEARCH_TYPES.FILE:
default:
icon = <Feather name="compass" size={18} />
break;
}
return (
<TouchableOpacity style={uriBarStyle.item} onPress={onPress}>
{icon}
<Text style={uriBarStyle.itemText} numberOfLines={1}>{value}</Text>
</TouchableOpacity>
)
}
}
export default UriBarItem;

View file

@ -1,121 +0,0 @@
// @flow
import React from 'react';
import { SEARCH_TYPES, isNameValid, normalizeURI } from 'lbry-redux';
import { FlatList, Keyboard, TextInput, View } from 'react-native';
import UriBarItem from './internal/uri-bar-item';
import uriBarStyle from '../../styles/uriBar';
class UriBar extends React.PureComponent {
static INPUT_TIMEOUT = 500;
textInput = null;
keyboardDidHideListener = null;
componentDidMount () {
this.keyboardDidHideListener = Keyboard.addListener('keyboardDidHide', this._keyboardDidHide);
}
componentWillUnmount() {
if (this.keyboardDidHideListener) {
this.keyboardDidHideListener.remove();
}
}
constructor(props) {
super(props);
this.state = {
changeTextTimeout: null,
currentValue: null,
inputText: null,
focused: false
};
}
handleChangeText = text => {
const newValue = text ? text : '';
clearTimeout(this.state.changeTextTimeout);
const { updateSearchQuery } = this.props;
let timeout = setTimeout(() => {
updateSearchQuery(text);
}, UriBar.INPUT_TIMEOUT);
this.setState({ inputText: newValue, currentValue: newValue, changeTextTimeout: timeout });
}
handleItemPress = (item) => {
const { navigation, updateSearchQuery } = this.props;
const { type, value } = item;
Keyboard.dismiss();
if (SEARCH_TYPES.SEARCH === type) {
navigation.navigate({ routeName: 'Search', key: 'searchPage', params: { searchQuery: value }});
} else {
navigation.navigate({ routeName: 'File', key: 'filePage', params: { uri: normalizeURI(value) }});
}
}
_keyboardDidHide = () => {
if (this.textInput) {
this.textInput.blur();
}
this.setState({ focused: false });
}
render() {
const { navigation, suggestions, updateSearchQuery, value } = this.props;
if (this.state.currentValue === null) {
this.setState({ currentValue: value });
}
let style = [uriBarStyle.overlay];
if (this.state.focused) {
style.push(uriBarStyle.inFocus);
}
return (
<View style={style}>
{this.state.focused && (
<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 style={uriBarStyle.uriContainer}>
<TextInput ref={(ref) => { this.textInput = ref }}
style={uriBarStyle.uriText}
selectTextOnFocus={true}
placeholder={'Search for videos, music, games 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 })}
onChangeText={this.handleChangeText}
onSubmitEditing={() => {
if (this.state.inputText) {
let inputText = this.state.inputText;
if (isNameValid(inputText)) {
navigation.navigate({ routeName: 'File', key: 'filePage', params: { uri: normalizeURI(inputText) }});
} else {
// Open the search page with the query populated
navigation.navigate({ routeName: 'Search', key: 'searchPage', params: { searchQuery: inputText }});
}
}
}}/>
</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);

View file

@ -1,47 +0,0 @@
// @flow
import React from 'react';
import { Text, View } from 'react-native';
import Address from '../address';
import Button from '../button';
import walletStyle from '../../styles/wallet';
type Props = {
checkAddressIsMine: string => void,
receiveAddress: string,
getNewAddress: () => void,
gettingNewAddress: boolean,
};
class WalletAddress extends React.PureComponent<Props> {
componentWillMount() {
const { checkAddressIsMine, receiveAddress, getNewAddress } = this.props;
if (!receiveAddress) {
getNewAddress();
} else {
checkAddressIsMine(receiveAddress);
}
}
render() {
const { receiveAddress, getNewAddress, gettingNewAddress } = this.props;
return (
<View style={walletStyle.card}>
<Text style={walletStyle.title}>Receive Credits</Text>
<Text style={[walletStyle.text, walletStyle.bottomMarginMedium]}>Use this wallet address to receive credits sent by another user (or yourself).</Text>
<Address address={receiveAddress} style={walletStyle.bottomMarginSmall} />
<Button style={[walletStyle.button, walletStyle.bottomMarginLarge]}
icon={'refresh'}
text={'Get New Address'}
onPress={getNewAddress}
disabled={gettingNewAddress}
/>
<Text style={walletStyle.smallText}>
You can generate a new address at any time, and any previous addresses will continue to work. Using multiple addresses can be helpful for keeping track of incoming payments from multiple sources.
</Text>
</View>
);
}
}
export default WalletAddress;

View file

@ -1,9 +0,0 @@
import { connect } from 'react-redux';
import { selectBalance } from 'lbry-redux';
import WalletBalance from './view';
const select = state => ({
balance: selectBalance(state),
});
export default connect(select, null)(WalletBalance);

View file

@ -1,29 +0,0 @@
// @flow
import React from 'react';
import { Image, Text, View } from 'react-native';
import { formatCredits } from 'lbry-redux'
import Address from '../address';
import Button from '../button';
import walletStyle from '../../styles/wallet';
type Props = {
balance: number,
};
class WalletBalance extends React.PureComponent<Props> {
render() {
const { balance } = this.props;
return (
<View style={walletStyle.balanceCard}>
<Image style={walletStyle.balanceBackground} resizeMode={'cover'} source={require('../../assets/stripe.png')} />
<Text style={walletStyle.balanceTitle}>Balance</Text>
<Text style={walletStyle.balanceCaption}>You currently have</Text>
<Text style={walletStyle.balance}>
{(balance || balance === 0) && (formatCredits(balance, 2) + ' LBC')}
</Text>
</View>
);
}
}
export default WalletBalance;

View file

@ -1,22 +0,0 @@
import { connect } from 'react-redux';
import {
doNotify,
doSendDraftTransaction,
selectDraftTransaction,
selectDraftTransactionError,
selectBalance
} from 'lbry-redux';
import WalletSend from './view';
const perform = dispatch => ({
sendToAddress: (address, amount) => dispatch(doSendDraftTransaction(address, amount)),
notify: (data) => dispatch(doNotify(data))
});
const select = state => ({
balance: selectBalance(state),
draftTransaction: selectDraftTransaction(state),
transactionError: selectDraftTransactionError(state),
});
export default connect(select, perform)(WalletSend);

View file

@ -1,89 +0,0 @@
// @flow
import React from 'react';
import { regexAddress } from 'lbry-redux';
import { TextInput, Text, View } from 'react-native';
import Button from '../button';
import walletStyle from '../../styles/wallet';
type DraftTransaction = {
address: string,
amount: ?number, // So we can use a placeholder in the input
};
type Props = {
sendToAddress: (string, number) => void,
balance: number,
};
class WalletSend extends React.PureComponent<Props> {
state = {
amount: null,
address: null
};
componentWillUpdate(nextProps) {
const { draftTransaction, transactionError } = nextProps;
if (transactionError && transactionError.trim().length > 0) {
this.setState({ address: draftTransaction.address, amount: draftTransaction.amount });
}
}
handleSend = () => {
const { balance, sendToAddress, notify } = this.props;
const { address, amount } = this.state;
if (address && !regexAddress.test(address)) {
notify({
message: 'The recipient address is not a valid LBRY address.',
displayType: ['toast']
});
return;
}
if (amount > balance) {
notify({
message: 'Insufficient credits',
displayType: ['toast']
});
return;
}
if (amount && address) {
sendToAddress(address, parseFloat(amount));
this.setState({ address: null, amount: null });
}
}
render() {
const { balance } = this.props;
const canSend = this.state.address &&
this.state.amount > 0 &&
this.state.address.trim().length > 0;
return (
<View style={walletStyle.card}>
<Text style={walletStyle.title}>Send Credits</Text>
<Text style={walletStyle.text}>Amount</Text>
<View style={[walletStyle.amountRow, walletStyle.bottomMarginMedium]}>
<TextInput onChangeText={value => this.setState({amount: value})}
keyboardType={'numeric'}
value={this.state.amount}
style={[walletStyle.input, walletStyle.amountInput]} />
<Text style={[walletStyle.text, walletStyle.currency]}>LBC</Text>
</View>
<Text style={walletStyle.text}>Recipient address</Text>
<View style={walletStyle.row}>
<TextInput onChangeText={value => this.setState({address: value})}
placeholder={'bbFxRyXXXXXXXXXXXZD8nE7XTLUxYnddTs'}
value={this.state.address}
style={[walletStyle.input, walletStyle.addressInput, walletStyle.bottomMarginMedium]} />
<Button text={'Send'}
style={[walletStyle.button, walletStyle.sendButton]}
disabled={!canSend}
onPress={this.handleSend} />
</View>
</View>
);
}
}
export default WalletSend;

View file

@ -1,5 +0,0 @@
const Constants = {
SETTING_ALPHA_UNDERSTANDS_RISKS: "ALPHA_UNDERSTANDS_RISKS"
};
export default Constants;

View file

@ -1,140 +0,0 @@
import React from 'react';
import { Provider, connect } from 'react-redux';
import DiscoverPage from './page/discover';
import {
AppRegistry,
AppState,
AsyncStorage,
Text,
View,
NativeModules
} from 'react-native';
import { createStore, applyMiddleware, compose, combineReducers } from 'redux';
import {
StackNavigator, addNavigationHelpers
} from 'react-navigation';
import { AppNavigator } from './component/AppNavigator';
import AppWithNavigationState from './component/AppNavigator';
import { persistStore, autoRehydrate } from 'redux-persist';
import createCompressor from 'redux-persist-transform-compress';
import createFilter from 'redux-persist-transform-filter';
import thunk from 'redux-thunk';
import {
Lbry,
claimsReducer,
costInfoReducer,
fileInfoReducer,
notificationsReducer,
searchReducer,
walletReducer
} from 'lbry-redux';
import settingsReducer from './redux/reducers/settings';
import moment from 'moment';
import { reactNavigationMiddleware } from './utils/redux';
function isFunction(object) {
return typeof object === 'function';
}
function isNotFunction(object) {
return !isFunction(object);
}
function createBulkThunkMiddleware() {
return ({ dispatch, getState }) => next => action => {
if (action.type === 'BATCH_ACTIONS') {
action.actions.filter(isFunction).map(actionFn => actionFn(dispatch, getState));
}
return next(action);
};
}
function enableBatching(reducer) {
return function batchingReducer(state, action) {
switch (action.type) {
case 'BATCH_ACTIONS':
return action.actions.filter(isNotFunction).reduce(batchingReducer, state);
default:
return reducer(state, action);
}
};
}
const router = AppNavigator.router;
const navAction = router.getActionForPathAndParams('Splash');
const initialNavState = router.getStateForAction(navAction);
const navigatorReducer = (state = initialNavState, action) => {
const nextState = AppNavigator.router.getStateForAction(action, state);
return nextState || state;
};
const reducers = combineReducers({
claims: claimsReducer,
costInfo: costInfoReducer,
fileInfo: fileInfoReducer,
notifications: notificationsReducer,
search: searchReducer,
wallet: walletReducer,
nav: navigatorReducer,
settings: settingsReducer
});
const bulkThunk = createBulkThunkMiddleware();
const middleware = [thunk, bulkThunk, reactNavigationMiddleware];
// eslint-disable-next-line no-underscore-dangle
const composeEnhancers = compose;
const store = createStore(
enableBatching(reducers),
{}, // initial state,
composeEnhancers(
autoRehydrate(),
applyMiddleware(...middleware)
)
);
const compressor = createCompressor();
const saveClaimsFilter = createFilter('claims', ['byId', 'claimsByUri']);
const subscriptionsFilter = createFilter('subscriptions', ['subscriptions']);
const settingsFilter = createFilter('settings', ['clientSettings']);
const walletFilter = createFilter('wallet', ['receiveAddress']);
const persistOptions = {
whitelist: ['claims', 'subscriptions', 'settings', 'wallet'],
// Order is important. Needs to be compressed last or other transforms can't
// read the data
transforms: [saveClaimsFilter, subscriptionsFilter, settingsFilter, walletFilter, compressor],
debounce: 10000,
storage: AsyncStorage
};
persistStore(store, persistOptions, err => {
if (err) {
console.log('Unable to load saved SETTINGS');
}
});
class LBRYApp extends React.Component {
componentDidMount() {
AsyncStorage.getItem('hasLaunched').then(value => {
if (value == null || value !== 'true') {
AsyncStorage.setItem('hasLaunched', 'true');
// only set firstLaunchTime since we've determined that this is the first app launch ever
AsyncStorage.setItem('firstLaunchTime', String(moment().unix()));
}
});
}
render() {
return (
<Provider store={store}>
<AppWithNavigationState />
</Provider>
);
}
}
AppRegistry.registerComponent('LBRYApp', () => LBRYApp);
export default LBRYApp;

View file

@ -0,0 +1,127 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="io.lbry.browser"
android:installLocation="auto">
<uses-feature android:name="android.hardware.camera" android:required="false" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="com.android.vending.BILLING" />
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-sdk tools:overrideLibrary="com.google.zxing.client.android" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:largeHeap="true"
android:requestLegacyExternalStorage="true"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme"
android:usesCleartextTraffic="true">
<meta-data android:name="com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME"
android:value="com.google.android.exoplayer2.ext.cast.DefaultCastOptionsProvider"/>
<meta-data
android:name="com.google.firebase.messaging.default_notification_icon"
android:resource="@drawable/ic_lbry" />
<meta-data
android:name="com.google.firebase.messaging.default_notification_color"
android:resource="@color/lbryGreen" />
<meta-data
android:name="com.google.firebase.messaging.default_notification_channel_id"
android:value="@string/default_notification_channel_id"/>
<meta-data android:name="wakelock" android:value="0"/>
<activity
android:configChanges="orientation|keyboardHidden|screenSize|smallestScreenSize|screenLayout"
android:name=".MainActivity"
android:label="@string/app_name"
android:supportsPictureInPicture="true"
android:theme="@style/AppTheme.NoActionBar"
android:launchMode="singleTask"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="video/*" />
<data android:mimeType="image/*" />
<data android:mimeType="text/*" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="lbry" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="https" android:host="open.lbry.com"/>
<data android:scheme="https" android:host="lbry.tv" android:pathPattern="/..*/*" />
<data android:scheme="https" android:host="lbry.tv" android:pathPattern="/.*:.*" />
<data android:scheme="https" android:host="lbry.tv" android:pathPattern="/.*#.*" />
<data android:scheme="https" android:host="lbry.lat" android:pathPattern="/..*/*" />
<data android:scheme="https" android:host="lbry.lat" android:pathPattern="/.*:.*" />
<data android:scheme="https" android:host="lbry.lat" android:pathPattern="/.*#.*" />
<data android:scheme="https" android:host="lbry.fr" android:pathPattern="/..*/*" />
<data android:scheme="https" android:host="lbry.fr" android:pathPattern="/.*:.*" />
<data android:scheme="https" android:host="lbry.fr" android:pathPattern="/.*#.*" />
<data android:scheme="https" android:host="lbry.in" android:pathPattern="/..*/*" />
<data android:scheme="https" android:host="lbry.in" android:pathPattern="/.*:.*" />
<data android:scheme="https" android:host="lbry.in" android:pathPattern="/.*#.*" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity
android:name=".FirstRunActivity"
android:launchMode="singleTask"
android:parentActivityName=".MainActivity"
android:theme="@style/AppTheme.NoActionBarTranslucent" />
<activity
android:name=".VerificationActivity"
android:launchMode="singleTask"
android:parentActivityName=".MainActivity"
android:theme="@style/AppTheme.NoActionBarTranslucent"
android:windowSoftInputMode="adjustResize" />
<activity
android:name="com.journeyapps.barcodescanner.CaptureActivity"
android:screenOrientation="fullSensor"
tools:replace="screenOrientation" />
<service
android:name="io.lbry.browser.LbrynetMessagingService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
<provider
android:name="io.lbry.browser.LocalFileProvider"
android:authorities="io.lbry.browser.fileprovider"
android:grantUriPermissions="true"
android:exported="false">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepaths" />
</provider>
</application>
</manifest>

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View file

@ -0,0 +1,252 @@
package io.lbry.browser;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.method.LinkMovementMethod;
import android.view.View;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.text.HtmlCompat;
import androidx.preference.PreferenceManager;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import io.lbry.browser.exceptions.AuthTokenInvalidatedException;
import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.Lbry;
import io.lbry.browser.utils.LbryAnalytics;
import io.lbry.browser.utils.Lbryio;
import io.lbry.lbrysdk.LbrynetService;
import io.lbry.lbrysdk.ServiceHelper;
import io.lbry.lbrysdk.Utils;
public class FirstRunActivity extends AppCompatActivity {
private BroadcastReceiver sdkReceiver;
private BroadcastReceiver authReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_first_run);
TextView welcomeTos = findViewById(R.id.welcome_text_view_tos);
welcomeTos.setMovementMethod(LinkMovementMethod.getInstance());
welcomeTos.setText(HtmlCompat.fromHtml(getString(R.string.welcome_tos), HtmlCompat.FROM_HTML_MODE_LEGACY));
findViewById(R.id.welcome_link_use_lbry).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
finishFirstRun();
}
});
registerAuthReceiver();
findViewById(R.id.welcome_wait_container).setVisibility(View.VISIBLE);
IntentFilter filter = new IntentFilter();
filter.addAction(MainActivity.ACTION_SDK_READY);
filter.addAction(LbrynetService.ACTION_STOP_SERVICE);
sdkReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (MainActivity.ACTION_SDK_READY.equals(action)) {
// authenticate after we receive the sdk ready event
authenticate();
} else if (LbrynetService.ACTION_STOP_SERVICE.equals(action)) {
finish();
if (MainActivity.instance != null) {
MainActivity.instance.finish();
}
}
}
};
registerReceiver(sdkReceiver, filter);
CheckInstallIdTask task = new CheckInstallIdTask(this, new CheckInstallIdTask.InstallIdHandler() {
@Override
public void onInstallIdChecked(boolean result) {
// start the sdk from FirstRun
boolean serviceRunning = MainActivity.isServiceRunning(MainActivity.instance, LbrynetService.class);
if (!serviceRunning) {
Lbry.SDK_READY = false;
ServiceHelper.start(MainActivity.instance, "", LbrynetService.class, "lbrynetservice");
}
if (result) {
// install_id generated and validated, authenticate now
authenticate();
return;
}
// we weren't able to generate the install_id ourselves, depend on the sdk for that
if (Lbry.SDK_READY) {
authenticate();
return;
}
}
});
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
public void onResume() {
super.onResume();
LbryAnalytics.setCurrentScreen(this, "First Run", "FirstRun");
}
private void registerAuthReceiver() {
IntentFilter filter = new IntentFilter();
filter.addAction(MainActivity.ACTION_USER_AUTHENTICATION_SUCCESS);
filter.addAction(MainActivity.ACTION_USER_AUTHENTICATION_FAILED);
authReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (MainActivity.ACTION_USER_AUTHENTICATION_SUCCESS.equals(intent.getAction())) {
handleAuthenticationSuccess();
} else {
handleAuthenticationFailed();
}
}
};
registerReceiver(authReceiver, filter);
}
private void handleAuthenticationSuccess() {
// first_auth completed event
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
boolean firstAuthCompleted = sp.getBoolean(MainActivity.PREFERENCE_KEY_INTERNAL_FIRST_AUTH_COMPLETED, false);
if (!firstAuthCompleted) {
LbryAnalytics.logEvent(LbryAnalytics.EVENT_FIRST_USER_AUTH);
sp.edit().putBoolean(MainActivity.PREFERENCE_KEY_INTERNAL_FIRST_AUTH_COMPLETED, true).apply();
}
findViewById(R.id.welcome_wait_container).setVisibility(View.GONE);
findViewById(R.id.welcome_display).setVisibility(View.VISIBLE);
findViewById(R.id.welcome_link_use_lbry).setVisibility(View.VISIBLE);
}
private void handleAuthenticationFailed() {
findViewById(R.id.welcome_progress_bar).setVisibility(View.GONE);
((TextView) findViewById(R.id.welcome_wait_text)).setText(R.string.startup_failed);
}
private void authenticate() {
new AuthenticateTask(this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
private void finishFirstRun() {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
sp.edit().putBoolean(MainActivity.PREFERENCE_KEY_INTERNAL_FIRST_RUN_COMPLETED, true).apply();
// first_run_completed event
LbryAnalytics.logEvent(LbryAnalytics.EVENT_FIRST_RUN_COMPLETED);
finish();
}
@Override
public void onBackPressed() {
return;
}
@Override
protected void onDestroy() {
Helper.unregisterReceiver(authReceiver, this);
Helper.unregisterReceiver(sdkReceiver, this);
super.onDestroy();
}
private void generateIdAndAuthenticate() {
}
private static class CheckInstallIdTask extends AsyncTask<Void, Void, Boolean> {
private final Context context;
private final InstallIdHandler handler;
public CheckInstallIdTask(Context context, InstallIdHandler handler) {
this.context = context;
this.handler = handler;
}
protected Boolean doInBackground(Void... params) {
// Load the installation id from the file system
String lbrynetDir = String.format("%s/%s", Utils.getAppInternalStorageDir(context), "lbrynet");
File dir = new File(lbrynetDir);
boolean dirExists = dir.isDirectory();
if (!dirExists) {
dirExists = dir.mkdirs();
}
if (!dirExists) {
return false;
}
String installIdPath = String.format("%s/install_id", lbrynetDir);
File file = new File(installIdPath);
String installId = null;
if (!file.exists()) {
// generate the install_id
installId = Lbry.generateId();
BufferedWriter writer = null;
try {
writer = new BufferedWriter(new FileWriter(file));
writer.write(installId);
} catch (IOException ex) {
return false;
} finally {
Helper.closeCloseable(writer);
}
} else {
// read the installation id from the file
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(new FileInputStream(installIdPath)));
installId = reader.readLine();
} catch (IOException ex) {
return false;
} finally {
Helper.closeCloseable(reader);
}
}
if (!Helper.isNullOrEmpty(installId)) {
Lbry.INSTALLATION_ID = installId;
}
return !Helper.isNullOrEmpty(installId);
}
protected void onPostExecute(Boolean result) {
if (handler != null) {
handler.onInstallIdChecked(result);
}
}
public interface InstallIdHandler {
void onInstallIdChecked(boolean result);
}
}
private static class AuthenticateTask extends AsyncTask<Void, Void, Void> {
private final Context context;
public AuthenticateTask(Context context) {
this.context = context;
}
protected Void doInBackground(Void... params) {
try {
Lbryio.authenticate(context);
} catch (AuthTokenInvalidatedException ex) {
// pass
}
return null;
}
}
}

View file

@ -0,0 +1,191 @@
package io.lbry.browser;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.sqlite.SQLiteDatabase;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import androidx.core.app.NotificationCompat;
import androidx.core.content.ContextCompat;
import androidx.preference.PreferenceManager;
import android.util.Log;
import com.google.firebase.analytics.FirebaseAnalytics;
import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;
import io.lbry.browser.data.DatabaseHelper;
import io.lbry.browser.model.lbryinc.LbryNotification;
import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.LbryAnalytics;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
public class LbrynetMessagingService extends FirebaseMessagingService {
public static final String ACTION_NOTIFICATION_RECEIVED = "io.lbry.browser.Broadcast.NotificationReceived";
private static final String TAG = "LbrynetMessagingService";
private static final String NOTIFICATION_CHANNEL_ID = "io.lbry.browser.LBRY_ENGAGEMENT_CHANNEL";
private static final String TYPE_COMMENT = "comment";
private static final String TYPE_SUBSCRIPTION = "subscription";
private static final String TYPE_REWARD = "reward";
private static final String TYPE_INTERESTS = "interests";
private static final String TYPE_CREATOR = "creator";
private FirebaseAnalytics firebaseAnalytics;
@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
if (firebaseAnalytics == null) {
firebaseAnalytics = FirebaseAnalytics.getInstance(this);
}
Map<String, String> payload = remoteMessage.getData();
if (payload != null) {
String type = payload.get("type");
String url = payload.get("target");
String title = payload.get("title");
String body = payload.get("body");
String name = payload.get("name"); // notification name
String hash = payload.get("hash"); // comment hash
if (type != null && getEnabledTypes().contains(type) && body != null && body.trim().length() > 0) {
// only log the receive event for valid notifications received
if (firebaseAnalytics != null) {
Bundle bundle = new Bundle();
bundle.putString("name", name);
firebaseAnalytics.logEvent(LbryAnalytics.EVENT_LBRY_NOTIFICATION_RECEIVE, bundle);
}
if (!Helper.isNullOrEmpty(hash)) {
url = String.format("%s?comment_hash=%s", url, hash);
}
sendNotification(title, body, type, url, name);
}
// persist the notification data
try {
DatabaseHelper helper = DatabaseHelper.getInstance();
SQLiteDatabase db = helper.getWritableDatabase();
LbryNotification lnotification = new LbryNotification();
lnotification.setTitle(title);
lnotification.setDescription(body);
lnotification.setTargetUrl(url);
lnotification.setTimestamp(new Date());
DatabaseHelper.createOrUpdateNotification(lnotification, db);
// send a broadcast
Intent intent = new Intent(ACTION_NOTIFICATION_RECEIVED);
intent.putExtra("title", title);
intent.putExtra("body", body);
intent.putExtra("url", url);
intent.putExtra("timestamp", lnotification.getTimestamp().getTime());
sendBroadcast(intent);
} catch (Exception ex) {
// don't fail if any error occurs while saving a notification
Log.e(TAG, "could not save notification", ex);
}
}
}
@Override
public void onNewToken(String token) {
//Log.d(TAG, "Refreshed token: " + token);
// If you want to send messages to this application instance or
// manage this apps subscriptions on the server side, send the
// Instance ID token to your app server.
sendRegistrationToServer(token);
}
/**
* Persist token to third-party servers.
*
* Modify this method to associate the user's FCM InstanceID token with any server-side account
* maintained by your application.
*
* @param token The new token.
*/
private void sendRegistrationToServer(String token) {
// TODO: Implement this method to send token to your app server.
}
/**
* Create and show a simple notification containing the received FCM message.
*
* @param messageBody FCM message body received.
*/
private void sendNotification(String title, String messageBody, String type, String url, String name) {
//Intent intent = new Intent(this, MainActivity.class);
//intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
if (url == null) {
if (TYPE_REWARD.equals(type)) {
url = "lbry://?rewards";
} else {
// default to home page
url = "lbry://?discover";
}
}
Intent launchIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
launchIntent.putExtra("notification_name", name);
launchIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, launchIntent, PendingIntent.FLAG_ONE_SHOT);
Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder notificationBuilder =
new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID)
.setColor(ContextCompat.getColor(this, R.color.lbryGreen))
.setSmallIcon(R.drawable.ic_lbry)
.setContentTitle(title)
.setContentText(messageBody)
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent);
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
// Since android Oreo notification channel is needed.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(
NOTIFICATION_CHANNEL_ID, "LBRY Engagement", NotificationManager.IMPORTANCE_DEFAULT);
notificationManager.createNotificationChannel(channel);
}
notificationManager.notify(3, notificationBuilder.build());
}
public List<String> getEnabledTypes() {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
List<String> enabledTypes = new ArrayList<String>();
if (sp.getBoolean(MainActivity.PREFERENCE_KEY_NOTIFICATION_COMMENTS, true)) {
enabledTypes.add(TYPE_COMMENT);
}
if (sp.getBoolean(MainActivity.PREFERENCE_KEY_NOTIFICATION_SUBSCRIPTIONS, true)) {
enabledTypes.add(TYPE_SUBSCRIPTION);
}
if (sp.getBoolean(MainActivity.PREFERENCE_KEY_NOTIFICATION_REWARDS, true)) {
enabledTypes.add(TYPE_REWARD);
}
if (sp.getBoolean(MainActivity.PREFERENCE_KEY_NOTIFICATION_CONTENT_INTERESTS, true)) {
enabledTypes.add(TYPE_INTERESTS);
}
if (sp.getBoolean(MainActivity.PREFERENCE_KEY_NOTIFICATION_CREATOR, true)) {
enabledTypes.add(TYPE_CREATOR);
}
return enabledTypes;
}
}

View file

@ -0,0 +1,7 @@
package io.lbry.browser;
import androidx.core.content.FileProvider;
public class LocalFileProvider extends FileProvider {
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,469 @@
package io.lbry.browser;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Color;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.FragmentActivity;
import androidx.viewpager2.widget.ViewPager2;
import com.android.billingclient.api.BillingClient;
import com.android.billingclient.api.BillingClientStateListener;
import com.android.billingclient.api.BillingFlowParams;
import com.android.billingclient.api.BillingResult;
import com.android.billingclient.api.Purchase;
import com.android.billingclient.api.PurchasesUpdatedListener;
import com.android.billingclient.api.SkuDetails;
import com.android.billingclient.api.SkuDetailsParams;
import com.android.billingclient.api.SkuDetailsResponseListener;
import com.google.android.material.snackbar.Snackbar;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import io.lbry.browser.adapter.VerificationPagerAdapter;
import io.lbry.browser.listener.SdkStatusListener;
import io.lbry.browser.listener.SignInListener;
import io.lbry.browser.listener.WalletSyncListener;
import io.lbry.browser.model.lbryinc.RewardVerified;
import io.lbry.browser.model.lbryinc.User;
import io.lbry.browser.tasks.RewardVerifiedHandler;
import io.lbry.browser.tasks.lbryinc.FetchCurrentUserTask;
import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.LbryAnalytics;
import io.lbry.browser.utils.Lbryio;
import io.lbry.lbrysdk.LbrynetService;
public class VerificationActivity extends FragmentActivity implements SignInListener, WalletSyncListener {
public static final int VERIFICATION_FLOW_SIGN_IN = 1;
public static final int VERIFICATION_FLOW_REWARDS = 2;
public static final int VERIFICATION_FLOW_WALLET = 3;
private List<SdkStatusListener> sdkStatusListeners;
private BillingClient billingClient;
private BroadcastReceiver sdkReceiver;
private String email;
private boolean signedIn;
private int flow;
private final PurchasesUpdatedListener purchasesUpdatedListener = new PurchasesUpdatedListener() {
@Override
public void onPurchasesUpdated(@NonNull BillingResult billingResult, @Nullable List<Purchase> purchases) {
int responseCode = billingResult.getResponseCode();
if (responseCode == BillingClient.BillingResponseCode.OK && purchases != null)
{
for (Purchase purchase : purchases) {
if (MainActivity.SKU_SKIP.equalsIgnoreCase(purchase.getSku())) {
showLoading();
MainActivity.handleBillingPurchase(
purchase,
billingClient,
VerificationActivity.this, null, new RewardVerifiedHandler() {
@Override
public void onSuccess(RewardVerified rewardVerified) {
if (Lbryio.currentUser != null) {
Lbryio.currentUser.setRewardApproved(rewardVerified.isRewardApproved());
}
if (!rewardVerified.isRewardApproved()) {
// show pending purchase message (possible slow card tx)
Snackbar.make(findViewById(R.id.verification_pager), R.string.purchase_request_pending, Snackbar.LENGTH_LONG).show();
} else {
Snackbar.make(findViewById(R.id.verification_pager), R.string.reward_verification_successful, Snackbar.LENGTH_LONG).show();
}
setResult(RESULT_OK);
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
finish();
}
}, 3000);
}
@Override
public void onError(Exception error) {
showFetchUserError(getString(R.string.purchase_request_failed_error));
hideLoading();
}
});
}
}
}
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
sdkStatusListeners = new ArrayList<>();
signedIn = Lbryio.isSignedIn();
Intent intent = getIntent();
if (intent != null) {
flow = intent.getIntExtra("flow", -1);
if (flow == -1 || (flow == VERIFICATION_FLOW_SIGN_IN && signedIn)) {
// no flow specified (or user is already signed in), just exit
setResult(signedIn ? RESULT_OK : RESULT_CANCELED);
finish();
return;
}
}
if (!Arrays.asList(VERIFICATION_FLOW_SIGN_IN, VERIFICATION_FLOW_REWARDS, VERIFICATION_FLOW_WALLET).contains(flow)) {
// invalid flow specified
setResult(RESULT_CANCELED);
finish();
return;
}
IntentFilter filter = new IntentFilter();
filter.addAction(LbrynetService.ACTION_STOP_SERVICE);
filter.addAction(MainActivity.ACTION_SDK_READY);
sdkReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (MainActivity.ACTION_SDK_READY.equals(action)) {
for (SdkStatusListener listener : sdkStatusListeners) {
if (listener != null) {
listener.onSdkReady();
}
}
} else if (LbrynetService.ACTION_STOP_SERVICE.equals(action)) {
finish();
}
}
};
registerReceiver(sdkReceiver, filter);
billingClient = BillingClient.newBuilder(this)
.setListener(purchasesUpdatedListener)
.enablePendingPurchases()
.build();
establishBillingClientConnection();
setContentView(R.layout.activity_verification);
ViewPager2 viewPager = findViewById(R.id.verification_pager);
viewPager.setUserInputEnabled(false);
viewPager.setSaveEnabled(false);
viewPager.setAdapter(new VerificationPagerAdapter(this));
findViewById(R.id.verification_close_button).setVisibility(View.VISIBLE);
findViewById(R.id.verification_close_button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
setResult(RESULT_CANCELED);
finish();
}
});
}
private void establishBillingClientConnection() {
if (billingClient != null) {
billingClient.startConnection(new BillingClientStateListener() {
@Override
public void onBillingSetupFinished(@NonNull BillingResult billingResult) {
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
// no need to do anything here. purchases are always checked server-side
}
}
@Override
public void onBillingServiceDisconnected() {
establishBillingClientConnection();
}
});
}
}
public void onResume() {
super.onResume();
LbryAnalytics.setCurrentScreen(this, "Verification", "Verification");
checkFlow();
}
public void checkFlow() {
ViewPager2 viewPager = findViewById(R.id.verification_pager);
if (Lbryio.isSignedIn()) {
boolean flowHandled = false;
if (flow == VERIFICATION_FLOW_WALLET) {
viewPager.setCurrentItem(VerificationPagerAdapter.PAGE_VERIFICATION_WALLET, false);
flowHandled = true;
} else if (flow == VERIFICATION_FLOW_REWARDS) {
User user = Lbryio.currentUser;
// disable phone verification for now
if (!user.isIdentityVerified()) {
// phone number verification required
viewPager.setCurrentItem(VerificationPagerAdapter.PAGE_VERIFICATION_PHONE, false);
flowHandled = true;
} else {
if (!user.isRewardApproved()) {
// manual verification required
viewPager.setCurrentItem(VerificationPagerAdapter.PAGE_VERIFICATION_MANUAL, false);
flowHandled = true;
}
}
}
if (!flowHandled) {
// user has already been verified and or reward approved
setResult(RESULT_CANCELED);
finish();
return;
}
}
}
public void showPhoneVerification() {
ViewPager2 viewPager = findViewById(R.id.verification_pager);
viewPager.setCurrentItem(VerificationPagerAdapter.PAGE_VERIFICATION_PHONE, false);
}
public void showLoading() {
findViewById(R.id.verification_loading_progress).setVisibility(View.VISIBLE);
findViewById(R.id.verification_pager).setVisibility(View.INVISIBLE);
findViewById(R.id.verification_close_button).setVisibility(View.GONE);
}
public void hideLoading() {
findViewById(R.id.verification_loading_progress).setVisibility(View.GONE);
findViewById(R.id.verification_pager).setVisibility(View.VISIBLE);
}
@Override
public void onBackPressed() {
ViewPager2 viewPager = findViewById(R.id.verification_pager);
if (viewPager.getCurrentItem() != VerificationPagerAdapter.PAGE_VERIFICATION_MANUAL)
viewPager.setCurrentItem(VerificationPagerAdapter.PAGE_VERIFICATION_MANUAL);
else
super.onBackPressed();
}
public void onEmailAdded(String email) {
this.email = email;
findViewById(R.id.verification_close_button).setVisibility(View.GONE);
Bundle bundle = new Bundle();
bundle.putString("email", email);
LbryAnalytics.logEvent(LbryAnalytics.EVENT_EMAIL_ADDED, bundle);
}
public void onEmailEdit() {
findViewById(R.id.verification_close_button).setVisibility(View.VISIBLE);
}
public void onEmailVerified() {
Snackbar.make(findViewById(R.id.verification_pager), R.string.sign_in_successful, Snackbar.LENGTH_LONG).show();
sendBroadcast(new Intent(MainActivity.ACTION_USER_SIGN_IN_SUCCESS));
Bundle bundle = new Bundle();
bundle.putString("email", email);
LbryAnalytics.logEvent(LbryAnalytics.EVENT_EMAIL_VERIFIED, bundle);
if (flow == VERIFICATION_FLOW_SIGN_IN) {
final Intent resultIntent = new Intent();
resultIntent.putExtra("flow", VERIFICATION_FLOW_SIGN_IN);
resultIntent.putExtra("email", email);
// only sign in required, don't do anything else
showLoading();
FetchCurrentUserTask task = new FetchCurrentUserTask(this, new FetchCurrentUserTask.FetchUserTaskHandler() {
@Override
public void onSuccess(User user) {
Lbryio.currentUser = user;
setResult(RESULT_OK, resultIntent);
finish();
}
@Override
public void onError(Exception error) {
showFetchUserError(error != null ? error.getMessage() : getString(R.string.fetch_current_user_error));
hideLoading();
}
});
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
} else {
// change pager view depending on flow
showLoading();
FetchCurrentUserTask task = new FetchCurrentUserTask(this, new FetchCurrentUserTask.FetchUserTaskHandler() {
@Override
public void onSuccess(User user) {
hideLoading();
findViewById(R.id.verification_close_button).setVisibility(View.VISIBLE);
Lbryio.currentUser = user;
ViewPager2 viewPager = findViewById(R.id.verification_pager);
// for rewards, (show phone verification if not done, or manual verification if required)
if (flow == VERIFICATION_FLOW_REWARDS) {
if (!user.isIdentityVerified()) {
// phone number verification required
viewPager.setCurrentItem(VerificationPagerAdapter.PAGE_VERIFICATION_PHONE, false);
} else {
if (!user.isRewardApproved()) {
// manual verification required
viewPager.setCurrentItem(VerificationPagerAdapter.PAGE_VERIFICATION_MANUAL, false);
} else {
// fully verified
setResult(RESULT_OK);
finish();
}
}
} else if (flow == VERIFICATION_FLOW_WALLET) {
// for wallet sync, if password unlock is required, show password entry page
viewPager.setCurrentItem(VerificationPagerAdapter.PAGE_VERIFICATION_WALLET, false);
}
}
@Override
public void onError(Exception error) {
showFetchUserError(error != null ? error.getMessage() : getString(R.string.fetch_current_user_error));
hideLoading();
}
});
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
}
@Override
public void onPhoneAdded(String countryCode, String phoneNumber) {
}
@Override
public void onPhoneVerified() {
showLoading();
FetchCurrentUserTask task = new FetchCurrentUserTask(this, new FetchCurrentUserTask.FetchUserTaskHandler() {
@Override
public void onSuccess(User user) {
Lbryio.currentUser = user;
if (user.isIdentityVerified() && user.isRewardApproved()) {
// verified for rewards
LbryAnalytics.logEvent(LbryAnalytics.EVENT_REWARD_ELIGIBILITY_COMPLETED);
setResult(RESULT_OK);
finish();
return;
}
findViewById(R.id.verification_close_button).setVisibility(View.VISIBLE);
// show manual verification page if the user is still not reward approved
ViewPager2 viewPager = findViewById(R.id.verification_pager);
viewPager.setCurrentItem(VerificationPagerAdapter.PAGE_VERIFICATION_MANUAL, false);
hideLoading();
}
@Override
public void onError(Exception error) {
showFetchUserError(error != null ? error.getMessage() : getString(R.string.fetch_current_user_error));
hideLoading();
}
});
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
private void showFetchUserError(String message) {
Snackbar.make(findViewById(R.id.verification_pager), message, Snackbar.LENGTH_LONG).
setBackgroundTint(Color.RED).setTextColor(Color.WHITE).show();
}
@Override
public void onManualVerifyContinue() {
setResult(RESULT_OK);
finish();
}
@Override
public void onWalletSyncProcessing() {
findViewById(R.id.verification_close_button).setVisibility(View.GONE);
}
@Override
public void onWalletSyncWaitingForInput() {
findViewById(R.id.verification_close_button).setVisibility(View.VISIBLE);
}
@Override
public void onWalletSyncEnabled() {
findViewById(R.id.verification_close_button).setVisibility(View.VISIBLE);
setResult(RESULT_OK);
finish();
}
@Override
public void onWalletSyncFailed(Exception error) {
findViewById(R.id.verification_close_button).setVisibility(View.VISIBLE);
}
@Override
public void onSkipQueueAction() {
if (billingClient != null) {
List<String> skuList = new ArrayList<>();
skuList.add(MainActivity.SKU_SKIP);
SkuDetailsParams detailsParams = SkuDetailsParams.newBuilder().
setType(BillingClient.SkuType.INAPP).
setSkusList(skuList).build();
billingClient.querySkuDetailsAsync(detailsParams, new SkuDetailsResponseListener() {
@Override
public void onSkuDetailsResponse(@NonNull BillingResult billingResult, @Nullable List<SkuDetails> list) {
if (list != null && list.size() > 0) {
// we only queried one product, so it should be the first item in the list
SkuDetails skuDetails = list.get(0);
// launch the billing flow for skip queue
BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder().
setSkuDetails(skuDetails).build();
billingClient.launchBillingFlow(VerificationActivity.this, billingFlowParams);
}
}
});
}
}
@Override
public void onTwitterVerified() {
Snackbar.make(findViewById(R.id.verification_pager), R.string.reward_verification_successful, Snackbar.LENGTH_LONG).show();
setResult(RESULT_OK);
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
finish();
}
}, 3000);
}
@Override
public void onManualProgress(boolean progress) {
if (progress) {
findViewById(R.id.verification_close_button).setVisibility(View.GONE);
} else {
findViewById(R.id.verification_close_button).setVisibility(View.VISIBLE);
}
}
@Override
public void onDestroy() {
Helper.unregisterReceiver(sdkReceiver, this);
super.onDestroy();
}
public void addSdkStatusListener(SdkStatusListener listener) {
if (!sdkStatusListeners.contains(listener)) {
sdkStatusListeners.add(listener);
}
}
public void removeSdkStatusListener(SdkStatusListener listener) {
sdkStatusListeners.remove(listener);
}
}

View file

@ -0,0 +1,125 @@
package io.lbry.browser.adapter;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
import java.util.ArrayList;
import java.util.List;
import io.lbry.browser.R;
import io.lbry.browser.model.Claim;
import io.lbry.browser.listener.ChannelItemSelectionListener;
import io.lbry.browser.utils.Helper;
import lombok.Getter;
import lombok.Setter;
public class ChannelFilterListAdapter extends RecyclerView.Adapter<ChannelFilterListAdapter.ViewHolder> {
private final Context context;
private List<Claim> items;
@Getter
@Setter
private Claim selectedItem;
@Setter
private ChannelItemSelectionListener listener;
public ChannelFilterListAdapter(Context context) {
this.context = context;
this.items = new ArrayList<>();
// Always list the placeholder as the first item
Claim claim = new Claim();
claim.setPlaceholder(true);
items.add(claim);
}
public static class ViewHolder extends RecyclerView.ViewHolder {
protected final View mediaContainer;
protected final View alphaContainer;
protected final View allView;
protected final ImageView thumbnailView;
protected final TextView alphaView;
protected final TextView titleView;
public ViewHolder(View v) {
super(v);
mediaContainer = v.findViewById(R.id.channel_filter_media_container);
alphaContainer = v.findViewById(R.id.channel_filter_no_thumbnail);
alphaView = v.findViewById(R.id.channel_filter_alpha_view);
thumbnailView = v.findViewById(R.id.channel_filter_thumbnail);
titleView = v.findViewById(R.id.channel_filter_title);
allView = v.findViewById(R.id.channel_filter_all_container);
}
}
public int getItemCount() {
return items != null ? items.size() : 0;
}
public boolean isClaimSelected(Claim claim) {
return claim.equals(selectedItem);
}
public void clearClaims() {
items = new ArrayList<>(items.subList(0, 1));
notifyDataSetChanged();
}
public void addClaims(List<Claim> claims) {
for (Claim claim : claims) {
if (!items.contains(claim)) {
items.add(claim);
}
}
notifyDataSetChanged();
}
@Override
public ChannelFilterListAdapter.ViewHolder onCreateViewHolder(ViewGroup root, int viewType) {
View v = LayoutInflater.from(context).inflate(R.layout.list_item_channel_filter, root, false);
return new ChannelFilterListAdapter.ViewHolder(v);
}
@Override
public void onBindViewHolder(ChannelFilterListAdapter.ViewHolder vh, int position) {
Claim claim = items.get(position);
vh.alphaView.setVisibility(claim.isPlaceholder() ? View.GONE : View.VISIBLE);
vh.titleView.setVisibility(claim.isPlaceholder() ? View.INVISIBLE : View.VISIBLE);
vh.allView.setVisibility(claim.isPlaceholder() ? View.VISIBLE : View.GONE);
vh.titleView.setText(Helper.isNullOrEmpty(claim.getTitle()) ? claim.getName() : claim.getTitle());
String thumbnailUrl = claim.getThumbnailUrl(vh.thumbnailView.getLayoutParams().width, vh.thumbnailView.getLayoutParams().height, 85);
if (!Helper.isNullOrEmpty(thumbnailUrl) && context != null) {
Glide.with(context.getApplicationContext()).load(thumbnailUrl).apply(RequestOptions.circleCropTransform()).into(vh.thumbnailView);
}
vh.alphaContainer.setVisibility(claim.isPlaceholder() || Helper.isNullOrEmpty(thumbnailUrl) ? View.VISIBLE : View.GONE);
vh.thumbnailView.setVisibility(claim.isPlaceholder() || Helper.isNullOrEmpty(thumbnailUrl) ? View.GONE : View.VISIBLE);
vh.alphaView.setText(claim.isPlaceholder() ? null : claim.getName() != null ? claim.getName().substring(1, 2).toUpperCase() : "");
int bgColor = Helper.generateRandomColorForValue(claim.getClaimId());
Helper.setIconViewBackgroundColor(vh.alphaContainer, bgColor, claim.isPlaceholder(), context);
vh.itemView.setSelected(isClaimSelected(claim));
vh.itemView.setOnClickListener(view -> {
if (claim.isPlaceholder()) {
selectedItem = null;
if (listener != null) {
listener.onChannelSelectionCleared();
}
} else if (!claim.equals(selectedItem)) {
selectedItem = claim;
if (listener != null) {
listener.onChannelItemSelected(claim);
}
}
notifyDataSetChanged();
});
}
}

View file

@ -0,0 +1,525 @@
package io.lbry.browser.adapter;
import android.content.Context;
import android.text.format.DateUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
import com.google.android.material.snackbar.Snackbar;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import io.lbry.browser.R;
import io.lbry.browser.listener.SelectionModeListener;
import io.lbry.browser.model.Claim;
import io.lbry.browser.model.LbryFile;
import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.LbryUri;
import io.lbry.browser.utils.Lbryio;
import lombok.Getter;
import lombok.Setter;
public class ClaimListAdapter extends RecyclerView.Adapter<ClaimListAdapter.ViewHolder> {
private static final int VIEW_TYPE_STREAM = 1;
private static final int VIEW_TYPE_CHANNEL = 2;
private static final int VIEW_TYPE_FEATURED = 3; // featured search result
private final Map<String, Claim> quickClaimIdMap;
private final Map<String, Claim> quickClaimUrlMap;
private final Map<String, Boolean> notFoundClaimIdMap;
private final Map<String, Boolean> notFoundClaimUrlMap;
@Setter
private boolean hideFee;
@Setter
private boolean canEnterSelectionMode;
private final Context context;
private List<Claim> items;
private final List<Claim> selectedItems;
@Setter
private ClaimListItemListener listener;
@Getter
@Setter
private boolean inSelectionMode;
@Setter
private SelectionModeListener selectionModeListener;
private float scale;
public ClaimListAdapter(List<Claim> items, Context context) {
this.context = context;
this.items = new ArrayList<>();
for (Claim item : items) {
if (item != null) {
this.items.add(item);
}
}
this.selectedItems = new ArrayList<>();
quickClaimIdMap = new HashMap<>();
quickClaimUrlMap = new HashMap<>();
notFoundClaimIdMap = new HashMap<>();
notFoundClaimUrlMap = new HashMap<>();
if (context != null) {
scale = context.getResources().getDisplayMetrics().density;
}
}
public List<Claim> getSelectedItems() {
return this.selectedItems;
}
public int getSelectedCount() {
return selectedItems != null ? selectedItems.size() : 0;
}
public void clearSelectedItems() {
this.selectedItems.clear();
}
public boolean isClaimSelected(Claim claim) {
return selectedItems.contains(claim);
}
public Claim getFeaturedItem() {
for (Claim claim : items) {
if (claim.isFeatured()) {
return claim;
}
}
return null;
}
public void removeFeaturedItem() {
int featuredIndex = -1;
for (int i = 0; i < items.size(); i++) {
if (items.get(i).isFeatured()) {
featuredIndex = i;
break;
}
}
if (featuredIndex > -1) {
items.remove(featuredIndex);
}
}
public List<Claim> getItems() {
return new ArrayList<>(this.items);
}
public void updateSigningChannelForClaim(Claim resolvedClaim) {
for (Claim claim : items) {
if (claim.getClaimId().equalsIgnoreCase(resolvedClaim.getClaimId())) {
claim.setSigningChannel(resolvedClaim.getSigningChannel());
}
}
}
public void clearItems() {
clearSelectedItems();
this.items.clear();
quickClaimIdMap.clear();
quickClaimUrlMap.clear();
notFoundClaimIdMap.clear();
notFoundClaimUrlMap.clear();
notifyDataSetChanged();
}
public Claim getLastItem() {
return items.size() > 0 ? items.get(items.size() - 1) : null;
}
public void addFeaturedItem(Claim claim) {
items.add(0, claim);
notifyDataSetChanged();
}
public void addItems(List<Claim> claims) {
for (Claim claim : claims) {
if (claim != null && !items.contains(claim)) {
items.add(claim);
}
}
notFoundClaimUrlMap.clear();
notFoundClaimIdMap.clear();
notifyDataSetChanged();
}
public void setItems(List<Claim> claims) {
items = new ArrayList<>();
for (Claim claim : claims) {
if (claim != null) {
items.add(claim);
}
}
notifyDataSetChanged();
}
public void removeItems(List<Claim> claims) {
items.removeAll(claims);
notifyDataSetChanged();
}
public void removeItem(Claim claim) {
items.remove(claim);
selectedItems.remove(claim);
notifyDataSetChanged();
}
public static class ViewHolder extends RecyclerView.ViewHolder {
protected final View feeContainer;
protected final TextView feeView;
protected final ImageView thumbnailView;
protected final View noThumbnailView;
protected final TextView alphaView;
protected final TextView vanityUrlView;
protected final TextView durationView;
protected final TextView titleView;
protected final TextView publisherView;
protected final TextView publishTimeView;
protected final TextView pendingTextView;
protected final View repostInfoView;
protected final TextView repostChannelView;
protected final View selectedOverlayView;
protected final TextView fileSizeView;
protected final ProgressBar downloadProgressView;
protected final TextView deviceView;
protected final View loadingImagePlaceholder;
protected final View loadingTextPlaceholder1;
protected final View loadingTextPlaceholder2;
public ViewHolder(View v) {
super(v);
feeContainer = v.findViewById(R.id.claim_fee_container);
feeView = v.findViewById(R.id.claim_fee);
alphaView = v.findViewById(R.id.claim_thumbnail_alpha);
noThumbnailView = v.findViewById(R.id.claim_no_thumbnail);
thumbnailView = v.findViewById(R.id.claim_thumbnail);
vanityUrlView = v.findViewById(R.id.claim_vanity_url);
durationView = v.findViewById(R.id.claim_duration);
titleView = v.findViewById(R.id.claim_title);
publisherView = v.findViewById(R.id.claim_publisher);
publishTimeView = v.findViewById(R.id.claim_publish_time);
pendingTextView = v.findViewById(R.id.claim_pending_text);
repostInfoView = v.findViewById(R.id.claim_repost_info);
repostChannelView = v.findViewById(R.id.claim_repost_channel);
selectedOverlayView = v.findViewById(R.id.claim_selected_overlay);
fileSizeView = v.findViewById(R.id.claim_file_size);
downloadProgressView = v.findViewById(R.id.claim_download_progress);
deviceView = v.findViewById(R.id.claim_view_device);
loadingImagePlaceholder = v.findViewById(R.id.claim_thumbnail_placeholder);
loadingTextPlaceholder1 = v.findViewById(R.id.claim_text_loading_placeholder_1);
loadingTextPlaceholder2 = v.findViewById(R.id.claim_text_loading_placeholder_2);
}
}
@Override
public int getItemCount() {
return items != null ? items.size() : 0;
}
@Override
public int getItemViewType(int position) {
if (items.get(position).isFeatured()) {
return VIEW_TYPE_FEATURED;
}
Claim claim = items.get(position);
String valueType = items.get(position).getValueType();
Claim actualClaim = Claim.TYPE_REPOST.equalsIgnoreCase(valueType) ? claim.getRepostedClaim() : claim;
return Claim.TYPE_CHANNEL.equalsIgnoreCase(actualClaim.getValueType()) ? VIEW_TYPE_CHANNEL : VIEW_TYPE_STREAM;
}
public void updateFileForClaimByIdOrUrl(LbryFile file, String claimId, String url) {
updateFileForClaimByIdOrUrl(file, claimId, url, false);
}
public void updateFileForClaimByIdOrUrl(LbryFile file, String claimId, String url, boolean skipNotFound) {
if (!skipNotFound) {
if (notFoundClaimIdMap.containsKey(claimId) && notFoundClaimUrlMap.containsKey(url)) {
return;
}
}
if (quickClaimIdMap.containsKey(claimId)) {
quickClaimIdMap.get(claimId).setFile(file);
notifyDataSetChanged();
return;
}
if (quickClaimUrlMap.containsKey(claimId)) {
quickClaimUrlMap.get(claimId).setFile(file);
notifyDataSetChanged();
return;
}
boolean claimFound = false;
for (int i = 0; i < items.size(); i++) {
Claim claim = items.get(i);
if (claimId.equalsIgnoreCase(claim.getClaimId()) || url.equalsIgnoreCase(claim.getPermanentUrl())) {
quickClaimIdMap.put(claimId, claim);
quickClaimUrlMap.put(url, claim);
claim.setFile(file);
notifyDataSetChanged();
claimFound = true;
break;
}
}
if (!claimFound) {
notFoundClaimIdMap.put(claimId, true);
notFoundClaimUrlMap.put(url, true);
}
}
public void clearFileForClaimOrUrl(String outpoint, String url) {
clearFileForClaimOrUrl(outpoint, url, false);
notifyDataSetChanged();
}
public void clearFileForClaimOrUrl(String outpoint, String url, boolean remove) {
int claimIndex = -1;
for (int i = 0; i < items.size(); i++) {
Claim claim = items.get(i);
if (outpoint.equalsIgnoreCase(claim.getOutpoint()) || url.equalsIgnoreCase(claim.getPermanentUrl())) {
claimIndex = i;
claim.setFile(null);
break;
}
}
if (remove && claimIndex > -1) {
Claim removed = items.remove(claimIndex);
selectedItems.remove(removed);
}
notifyDataSetChanged();
}
@Override
public ClaimListAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
int viewResourceId = -1;
switch (viewType) {
case VIEW_TYPE_FEATURED: viewResourceId = R.layout.list_item_featured_search_result; break;
case VIEW_TYPE_CHANNEL: viewResourceId = R.layout.list_item_channel; break;
case VIEW_TYPE_STREAM: default: viewResourceId = R.layout.list_item_stream; break;
}
View v = LayoutInflater.from(context).inflate(viewResourceId, parent, false);
return new ClaimListAdapter.ViewHolder(v);
}
@Override
public void onBindViewHolder(ClaimListAdapter.ViewHolder vh, int position) {
int type = getItemViewType(position);
int paddingTop = position == 0 ? 16 : 8;
int paddingBottom = position == getItemCount() - 1 ? 16 : 8;
int paddingTopScaled = Helper.getScaledValue(paddingTop, scale);
int paddingBottomScaled = Helper.getScaledValue(paddingBottom, scale);
vh.itemView.setPadding(vh.itemView.getPaddingStart(), paddingTopScaled, vh.itemView.getPaddingEnd(), paddingBottomScaled);
Claim original = items.get(position);
boolean isRepost = Claim.TYPE_REPOST.equalsIgnoreCase(original.getValueType());
final Claim item = Claim.TYPE_REPOST.equalsIgnoreCase(original.getValueType()) ?
(original.getRepostedClaim() != null ? original.getRepostedClaim() : original): original;
Claim.GenericMetadata metadata = item.getValue();
Claim signingChannel = item.getSigningChannel();
Claim.StreamMetadata streamMetadata = null;
if (metadata instanceof Claim.StreamMetadata) {
streamMetadata = (Claim.StreamMetadata) metadata;
}
String thumbnailUrl = item.getThumbnailUrl(vh.thumbnailView.getLayoutParams().width, vh.thumbnailView.getLayoutParams().height, 85);
long publishTime = (streamMetadata != null && streamMetadata.getReleaseTime() > 0) ? streamMetadata.getReleaseTime() * 1000 : item.getTimestamp() * 1000;
int bgColor = Helper.generateRandomColorForValue(item.getClaimId());
if (bgColor == 0) {
bgColor = Helper.generateRandomColorForValue(item.getName());
}
boolean isPending = item.getConfirmations() == 0;
boolean isSelected = isClaimSelected(original);
vh.itemView.setSelected(isSelected);
vh.selectedOverlayView.setVisibility(isSelected ? View.VISIBLE : View.GONE);
vh.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (isPending) {
Snackbar snackbar = Snackbar.make(vh.itemView, R.string.item_pending_blockchain, Snackbar.LENGTH_LONG);
TextView snackbarText = snackbar.getView().findViewById(com.google.android.material.R.id.snackbar_text);
snackbarText.setMaxLines(5);
snackbar.show();
return;
}
if (inSelectionMode) {
toggleSelectedClaim(original);
} else {
if (listener != null) {
listener.onClaimClicked(item);
}
}
}
});
vh.itemView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
if (!canEnterSelectionMode) {
return false;
}
if (isPending) {
Snackbar snackbar = Snackbar.make(vh.itemView, R.string.item_pending_blockchain, Snackbar.LENGTH_LONG);
TextView snackbarText = snackbar.getView().findViewById(com.google.android.material.R.id.snackbar_text);
snackbarText.setMaxLines(5);
snackbar.show();
return false;
}
if (!inSelectionMode) {
inSelectionMode = true;
if (selectionModeListener != null) {
selectionModeListener.onEnterSelectionMode();
}
}
toggleSelectedClaim(original);
return true;
}
});
vh.publisherView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (listener != null && signingChannel != null) {
listener.onClaimClicked(signingChannel);
}
}
});
vh.publishTimeView.setVisibility(!isPending ? View.VISIBLE : View.GONE);
vh.pendingTextView.setVisibility(isPending && !item.isLoadingPlaceholder() ? View.VISIBLE : View.GONE);
vh.repostInfoView.setVisibility(isRepost && type != VIEW_TYPE_FEATURED ? View.VISIBLE : View.GONE);
vh.repostChannelView.setText(isRepost && original.getSigningChannel() != null ? original.getSigningChannel().getName() : null);
vh.repostChannelView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (listener != null) {
listener.onClaimClicked(original.getSigningChannel());
}
}
});
vh.titleView.setText(Helper.isNullOrEmpty(item.getTitle()) ? item.getName() : item.getTitle());
if (type == VIEW_TYPE_FEATURED) {
LbryUri vanityUrl = new LbryUri();
vanityUrl.setClaimName(item.getName());
vh.vanityUrlView.setText(vanityUrl.toString());
}
vh.feeContainer.setVisibility(item.isUnresolved() || !Claim.TYPE_STREAM.equalsIgnoreCase(item.getValueType()) ? View.GONE : View.VISIBLE);
vh.noThumbnailView.setVisibility(Helper.isNullOrEmpty(thumbnailUrl) ? View.VISIBLE : View.GONE);
Helper.setIconViewBackgroundColor(vh.noThumbnailView, bgColor, false, context);
Helper.setViewVisibility(vh.loadingImagePlaceholder, item.isLoadingPlaceholder() ? View.VISIBLE : View.GONE);
Helper.setViewVisibility(vh.loadingTextPlaceholder1, item.isLoadingPlaceholder() ? View.VISIBLE : View.GONE);
Helper.setViewVisibility(vh.loadingTextPlaceholder2, item.isLoadingPlaceholder() ? View.VISIBLE : View.GONE);
Helper.setViewVisibility(vh.titleView, !item.isLoadingPlaceholder() ? View.VISIBLE : View.GONE);
Helper.setViewVisibility(vh.publisherView, !item.isLoadingPlaceholder() ? View.VISIBLE : View.GONE);
Helper.setViewVisibility(vh.publishTimeView, !item.isLoadingPlaceholder() && !isPending ? View.VISIBLE : View.GONE);
if (type == VIEW_TYPE_FEATURED && item.isUnresolved()) {
vh.durationView.setVisibility(View.GONE);
vh.titleView.setText("Nothing here. Publish something!");
vh.alphaView.setText(item.getName().substring(0, Math.min(5, item.getName().length() - 1)));
} else {
if (Claim.TYPE_STREAM.equalsIgnoreCase(item.getValueType())) {
long duration = item.getDuration();
if (!Helper.isNullOrEmpty(thumbnailUrl)) {
Glide.with(context.getApplicationContext()).
asBitmap().
load(thumbnailUrl).
centerCrop().
placeholder(R.drawable.bg_thumbnail_placeholder).
into(vh.thumbnailView);
vh.thumbnailView.setVisibility(View.VISIBLE);
} else {
vh.thumbnailView.setVisibility(View.GONE);
}
BigDecimal cost = item.getActualCost(Lbryio.LBCUSDRate);
vh.feeContainer.setVisibility(cost.doubleValue() > 0 && !hideFee ? View.VISIBLE : View.GONE);
vh.feeView.setText(cost.doubleValue() > 0 ? Helper.shortCurrencyFormat(cost.doubleValue()) : "Paid");
vh.alphaView.setText(item.getName().substring(0, Math.min(5, item.getName().length() - 1)));
vh.publisherView.setText(signingChannel != null ? signingChannel.getName() : context.getString(R.string.anonymous));
vh.publishTimeView.setText(DateUtils.getRelativeTimeSpanString(
publishTime, System.currentTimeMillis(), 0, DateUtils.FORMAT_ABBREV_RELATIVE));
vh.durationView.setVisibility(duration > 0 ? View.VISIBLE : View.GONE);
vh.durationView.setText(Helper.formatDuration(duration));
LbryFile claimFile = item.getFile();
boolean isDownloading = false;
int progress = 0;
String fileSizeString = claimFile == null ? null : Helper.formatBytes(claimFile.getTotalBytes(), false);
if (claimFile != null &&
!Helper.isNullOrEmpty(claimFile.getDownloadPath()) &&
!claimFile.isCompleted() &&
claimFile.getWrittenBytes() < claimFile.getTotalBytes()) {
isDownloading = true;
progress = claimFile.getTotalBytes() > 0 ?
Double.valueOf(((double) claimFile.getWrittenBytes() / (double) claimFile.getTotalBytes()) * 100.0).intValue() : 0;
fileSizeString = String.format("%s / %s",
Helper.formatBytes(claimFile.getWrittenBytes(), false),
Helper.formatBytes(claimFile.getTotalBytes(), false));
}
Helper.setViewText(vh.fileSizeView, claimFile != null && !Helper.isNullOrEmpty(claimFile.getDownloadPath()) ? fileSizeString : null);
Helper.setViewVisibility(vh.downloadProgressView, isDownloading ? View.VISIBLE : View.INVISIBLE);
Helper.setViewProgress(vh.downloadProgressView, progress);
Helper.setViewText(vh.deviceView, item.getDevice());
} else if (Claim.TYPE_CHANNEL.equalsIgnoreCase(item.getValueType())) {
if (!Helper.isNullOrEmpty(thumbnailUrl)) {
Glide.with(context.getApplicationContext()).
load(thumbnailUrl).
centerCrop().
placeholder(R.drawable.bg_thumbnail_placeholder).
apply(RequestOptions.circleCropTransform()).
into(vh.thumbnailView);
}
vh.alphaView.setText(item.getName().substring(1, 2).toUpperCase());
vh.publisherView.setText(item.getName());
vh.publishTimeView.setText(DateUtils.getRelativeTimeSpanString(
publishTime, System.currentTimeMillis(), 0, DateUtils.FORMAT_ABBREV_RELATIVE));
}
}
}
private void toggleSelectedClaim(Claim claim) {
if (selectedItems.contains(claim)) {
selectedItems.remove(claim);
} else {
selectedItems.add(claim);
}
if (selectionModeListener != null) {
selectionModeListener.onItemSelectionToggled();
}
if (selectedItems.size() == 0) {
inSelectionMode = false;
if (selectionModeListener != null) {
selectionModeListener.onExitSelectionMode();
}
}
notifyDataSetChanged();
}
public interface ClaimListItemListener {
void onClaimClicked(Claim claim);
}
}

View file

@ -0,0 +1,228 @@
package io.lbry.browser.adapter;
import android.content.Context;
import android.text.format.DateUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
import io.lbry.browser.R;
import io.lbry.browser.model.Claim;
import io.lbry.browser.model.ClaimCacheKey;
import io.lbry.browser.model.Comment;
import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.Lbry;
import io.lbry.browser.utils.LbryUri;
import lombok.Setter;
public class CommentListAdapter extends RecyclerView.Adapter<CommentListAdapter.ViewHolder> {
private final List<Comment> items;
private final Context context;
private final boolean nested;
private float scale;
@Setter
private ClaimListAdapter.ClaimListItemListener listener;
@Setter
private ReplyClickListener replyListener;
public CommentListAdapter(List<Comment> items, Context context) {
this(items, context, false);
}
public CommentListAdapter(List<Comment> items, Context context, boolean nested) {
this.items = new ArrayList<>(items);
this.context = context;
this.nested = nested;
if (context != null) {
scale = context.getResources().getDisplayMetrics().density;
}
for (Comment item : this.items) {
ClaimCacheKey key = new ClaimCacheKey();
key.setClaimId(item.getChannelId());
if (Lbry.claimCache.containsKey(key)) {
item.setPoster(Lbry.claimCache.get(key));
}
}
}
public void clearItems() {
items.clear();
notifyDataSetChanged();
}
public int getPositionForComment(String commentHash) {
for (int i = 0; i < items.size(); i++) {
if (commentHash.equalsIgnoreCase(items.get(i).getId())) {
return i;
}
}
return -1;
}
@Override
public int getItemCount() {
return items != null ? items.size() : 0;
}
public List<String> getClaimUrlsToResolve() {
List<String> urls = new ArrayList<>();
for (int i = 0; i < items.size(); i++) {
Comment item = items.get(i);
if (item.getPoster() == null) {
LbryUri url = LbryUri.tryParse(String.format("%s#%s", item.getChannelName(), item.getChannelId()));
if (url != null && !urls.contains(url.toString())) {
urls.add(url.toString());
}
}
if (item.getReplies().size() > 0) {
for (int j = 0; j < item.getReplies().size(); j++) {
Comment reply = item.getReplies().get(j);
if (reply.getPoster() == null) {
LbryUri url = LbryUri.tryParse(String.format("%s#%s", reply.getChannelName(), reply.getChannelId()));
if (url != null && !urls.contains(url.toString())) {
urls.add(url.toString());
}
}
}
}
}
return urls;
}
public static class ViewHolder extends RecyclerView.ViewHolder {
protected final TextView channelName;
protected final TextView commentText;
protected final ImageView thumbnailView;
protected final View noThumbnailView;
protected final TextView alphaView;
protected final TextView commentTimeView;
protected final View replyLink;
protected final RecyclerView repliesList;
public ViewHolder (View v) {
super(v);
channelName = v.findViewById(R.id.comment_channel_name);
commentTimeView = v.findViewById(R.id.comment_time);
commentText = v.findViewById(R.id.comment_text);
replyLink = v.findViewById(R.id.comment_reply_link);
thumbnailView = v.findViewById(R.id.comment_thumbnail);
noThumbnailView = v.findViewById(R.id.comment_no_thumbnail);
alphaView = v.findViewById(R.id.comment_thumbnail_alpha);
repliesList = v.findViewById(R.id.comment_replies);
}
}
public void insert(int index, Comment comment) {
if (!items.contains(comment)) {
items.add(index, comment);
notifyDataSetChanged();
}
}
public void addReply(Comment comment) {
for (int i = 0; i < items.size(); i++) {
Comment parent = items.get(i);
if (parent.getId().equalsIgnoreCase(comment.getParentId())) {
parent.addReply(comment);
notifyDataSetChanged();
break;
}
}
}
public void updatePosterForComment(String channelId, Claim channel) {
for (int i = 0 ; i < items.size(); i++) {
Comment item = items.get(i);
List<Comment> replies = item.getReplies();
if (replies != null && replies.size() > 0) {
for (int j = 0; j < replies.size(); j++) {
Comment reply = item.getReplies().get(j);
if (channelId.equalsIgnoreCase(reply.getChannelId())) {
reply.setPoster(channel);
break;
}
}
}
if (channelId.equalsIgnoreCase(item.getChannelId())) {
item.setPoster(channel);
break;
}
}
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(context).inflate(R.layout.list_item_comment, parent, false);
return new CommentListAdapter.ViewHolder(v);
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
Comment comment = items.get(position);
holder.itemView.setPadding(
nested ? Helper.getScaledValue(56, scale) : holder.itemView.getPaddingStart(),
holder.itemView.getPaddingTop(),
nested ? 0 : holder.itemView.getPaddingEnd(),
holder.itemView.getPaddingBottom());
holder.channelName.setText(comment.getChannelName());
holder.commentTimeView.setText(DateUtils.getRelativeTimeSpanString(
(comment.getTimestamp() * 1000), System.currentTimeMillis(), 0, DateUtils.FORMAT_ABBREV_RELATIVE));
holder.commentText.setText(comment.getText());
holder.replyLink.setVisibility(!nested ? View.VISIBLE : View.GONE);
boolean hasThumbnail = comment.getPoster() != null && !Helper.isNullOrEmpty(comment.getPoster().getThumbnailUrl());
holder.thumbnailView.setVisibility(hasThumbnail ? View.VISIBLE : View.INVISIBLE);
holder.noThumbnailView.setVisibility(!hasThumbnail ? View.VISIBLE : View.INVISIBLE);
int bgColor = Helper.generateRandomColorForValue(comment.getChannelId());
Helper.setIconViewBackgroundColor(holder.noThumbnailView, bgColor, false, context);
if (hasThumbnail) {
Glide.with(context.getApplicationContext()).asBitmap().load(comment.getPoster().getThumbnailUrl(holder.thumbnailView.getLayoutParams().width, holder.thumbnailView.getLayoutParams().height, 85)).
apply(RequestOptions.circleCropTransform()).into(holder.thumbnailView);
}
holder.alphaView.setText(comment.getChannelName() != null ? comment.getChannelName().substring(1, 2).toUpperCase() : null);
List<Comment> replies = comment.getReplies();
boolean hasReplies = replies != null && replies.size() > 0;
if (hasReplies) {
holder.repliesList.setLayoutManager(new LinearLayoutManager(context));
holder.repliesList.setAdapter(new CommentListAdapter(replies, context, true));
} else {
holder.repliesList.setAdapter(null);
}
holder.channelName.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (listener != null && comment.getPoster() != null) {
listener.onClaimClicked(comment.getPoster());
}
}
});
holder.replyLink.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (replyListener != null) {
replyListener.onReplyClicked(comment);
}
}
});
}
public interface ReplyClickListener {
void onReplyClicked(Comment comment);
}
}

View file

@ -0,0 +1,118 @@
package io.lbry.browser.adapter;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import java.util.ArrayList;
import java.util.List;
import io.lbry.browser.R;
import io.lbry.browser.model.EditorsChoiceItem;
import io.lbry.browser.utils.Helper;
import lombok.Setter;
public class EditorsChoiceItemAdapter extends RecyclerView.Adapter<EditorsChoiceItemAdapter.ViewHolder> {
private static final int VIEW_TYPE_HEADER = 1;
private static final int VIEW_TYPE_CONTENT = 2;
private final Context context;
private final List<EditorsChoiceItem> items;
@Setter
private EditorsChoiceItemListener listener;
public EditorsChoiceItemAdapter(List<EditorsChoiceItem> items, Context context) {
this.context = context;
this.items = new ArrayList<>(items);
}
public void addFeaturedItem(EditorsChoiceItem item) {
items.add(0, item);
notifyDataSetChanged();
}
public void addItems(List<EditorsChoiceItem> items) {
for (EditorsChoiceItem item : items) {
if (!this.items.contains(item)) {
this.items.add(item);
}
}
notifyDataSetChanged();
}
public static class ViewHolder extends RecyclerView.ViewHolder {
protected final ImageView thumbnailView;
protected final TextView descriptionView;
protected final TextView headerView;
protected final TextView titleView;
protected final View cardView;
public ViewHolder(View v) {
super(v);
cardView = v.findViewById(R.id.editors_choice_content_card);
descriptionView = v.findViewById(R.id.editors_choice_content_description);
titleView = v.findViewById(R.id.editors_choice_content_title);
thumbnailView = v.findViewById(R.id.editors_choice_content_thumbnail);
headerView = v.findViewById(R.id.editors_choice_header_title);
}
}
@Override
public int getItemCount() {
return items != null ? items.size() : 0;
}
@Override
public int getItemViewType(int position) {
return items.get(position).isHeader() ? VIEW_TYPE_HEADER : VIEW_TYPE_CONTENT;
}
@Override
public EditorsChoiceItemAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(context).inflate(R.layout.list_item_editors_choice, parent, false);
return new EditorsChoiceItemAdapter.ViewHolder(v);
}
@Override
public void onBindViewHolder(EditorsChoiceItemAdapter.ViewHolder vh, int position) {
int type = getItemViewType(position);
EditorsChoiceItem item = items.get(position);
vh.headerView.setVisibility(type == VIEW_TYPE_HEADER ? View.VISIBLE : View.GONE);
vh.cardView.setVisibility(type == VIEW_TYPE_CONTENT ? View.VISIBLE : View.GONE);
vh.headerView.setText(item.getTitle());
vh.titleView.setText(item.getTitle());
vh.descriptionView.setText(item.getDescription());
if (!Helper.isNullOrEmpty(item.getThumbnailUrl())) {
Glide.with(context.getApplicationContext()).
asBitmap().
load(item.getThumbnailUrl()).
centerCrop().
placeholder(R.drawable.bg_thumbnail_placeholder).
into(vh.thumbnailView);
}
vh.cardView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (listener != null) {
listener.onEditorsChoiceItemClicked(item);
}
}
});
}
public interface EditorsChoiceItemListener {
void onEditorsChoiceItemClicked(EditorsChoiceItem item);
}
}

View file

@ -0,0 +1,119 @@
package io.lbry.browser.adapter;
import android.content.Context;
import android.graphics.Rect;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import java.util.ArrayList;
import java.util.List;
import io.lbry.browser.R;
import io.lbry.browser.model.GalleryItem;
import io.lbry.browser.utils.Helper;
import lombok.Setter;
public class GalleryGridAdapter extends RecyclerView.Adapter<GalleryGridAdapter.ViewHolder> {
private final Context context;
private final List<GalleryItem> items;
@Setter
private GalleryItemClickListener listener;
public GalleryGridAdapter(List<GalleryItem> items, Context context) {
this.items = new ArrayList<>(items);
this.context = context;
}
public static class ViewHolder extends RecyclerView.ViewHolder {
protected final ImageView thumbnailView;
protected final TextView durationView;
public ViewHolder(View v) {
super(v);
thumbnailView = v.findViewById(R.id.gallery_item_thumbnail);
durationView = v.findViewById(R.id.gallery_item_duration);
}
}
public int getItemCount() {
return items != null ? items.size() : 0;
}
public void addItem(GalleryItem item) {
if (!items.contains(item)) {
items.add(item);
notifyDataSetChanged();
}
}
public void addItems(List<GalleryItem> items) {
for (GalleryItem item : items) {
if (!this.items.contains(item)) {
this.items.add(item);
notifyDataSetChanged();
}
}
}
public void clearItems() {
items.clear();
notifyDataSetChanged();
}
@Override
public GalleryGridAdapter.ViewHolder onCreateViewHolder(ViewGroup root, int viewType) {
View v = LayoutInflater.from(context).inflate(R.layout.list_item_gallery, root, false);
return new GalleryGridAdapter.ViewHolder(v);
}
@Override
public void onBindViewHolder(GalleryGridAdapter.ViewHolder vh, int position) {
GalleryItem item = items.get(position);
String thumbnailUrl = item.getThumbnailPath();
Glide.with(context.getApplicationContext()).load(thumbnailUrl).centerCrop().into(vh.thumbnailView);
vh.durationView.setVisibility(item.getDuration() > 0 ? View.VISIBLE : View.INVISIBLE);
vh.durationView.setText(item.getDuration() > 0 ? Helper.formatDuration(Double.valueOf(item.getDuration() / 1000.0).longValue()) : null);
vh.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (listener != null) {
listener.onGalleryItemClicked(item);
}
}
});
}
public interface GalleryItemClickListener {
void onGalleryItemClicked(GalleryItem item);
}
public static class GalleryGridItemDecoration extends RecyclerView.ItemDecoration {
private final int spanCount;
private final int spacing;
public GalleryGridItemDecoration(int spanCount, int spacing) {
this.spanCount = spanCount;
this.spacing = spacing;
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
int position = parent.getChildAdapterPosition(view); // item position
int column = position % spanCount; // item column
outRect.left = column * spacing / spanCount; // column * ((1f / spanCount) * spacing)
outRect.right = spacing - (column + 1) * spacing / spanCount; // spacing - (column + 1) * ((1f / spanCount) * spacing)
if (position >= spanCount) {
outRect.top = spacing; // item top
}
}
}
}

View file

@ -0,0 +1,98 @@
package io.lbry.browser.adapter;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import io.lbry.browser.R;
import io.lbry.browser.model.Claim;
public class InlineChannelSpinnerAdapter extends ArrayAdapter<Claim> {
private final List<Claim> channels;
private final int layoutResourceId;
private final LayoutInflater inflater;
public InlineChannelSpinnerAdapter(Context context, int resource, List<Claim> channels) {
super(context, resource, 0, channels);
inflater = LayoutInflater.from(context);
layoutResourceId = resource;
this.channels = new ArrayList<>(channels);
}
public void addPlaceholder(boolean includeAnonymous) {
Claim placeholder = new Claim();
placeholder.setPlaceholder(true);
insert(placeholder, 0);
channels.add(0, placeholder);
if (includeAnonymous) {
Claim anonymous = new Claim();
anonymous.setPlaceholderAnonymous(true);
insert(anonymous, 1);
channels.add(1, anonymous);
}
}
public void addAnonymousPlaceholder() {
Claim anonymous = new Claim();
anonymous.setPlaceholderAnonymous(true);
insert(anonymous, 0);
channels.add(0, anonymous);
}
public void addAll(Collection<? extends Claim> collection) {
for (Claim claim : collection) {
if (!channels.contains(claim)) {
channels.add(claim);
}
}
super.addAll(collection);
}
public void clear() {
channels.clear();
super.clear();
}
public int getItemPosition(Claim item) {
for (int i = 0; i < channels.size(); i++) {
Claim channel = channels.get(i);
if (item.getClaimId() != null && item.getClaimId().equalsIgnoreCase(channel.getClaimId())) {
return i;
}
}
return -1;
}
@Override
public View getDropDownView(int position, View view, ViewGroup parent) {
return createView(position, view, parent);
}
@Override
public View getView(int position, View view, ViewGroup parent) {
return createView(position, view, parent);
}
private View createView(int position, View convertView, ViewGroup parent){
View view = inflater.inflate(layoutResourceId, parent, false);
Context context = getContext();
Claim channel = getItem(position);
String name = channel.getName();
if (channel.isPlaceholder()) {
name = context.getString(R.string.create_a_channel);
} else if (channel.isPlaceholderAnonymous()) {
name = context.getString(R.string.anonymous);
}
TextView label = view.findViewById(R.id.channel_item_name);
label.setText(name);
return view;
}
}

View file

@ -0,0 +1,85 @@
package io.lbry.browser.adapter;
import android.content.Context;
import android.graphics.Typeface;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import java.util.List;
import io.lbry.browser.R;
import io.lbry.browser.model.lbryinc.Invitee;
public class InviteeListAdapter extends RecyclerView.Adapter<InviteeListAdapter.ViewHolder> {
private final Context context;
private final List<Invitee> items;
public InviteeListAdapter(List<Invitee> invitees, Context context) {
this.context = context;
this.items = new ArrayList<>(invitees);
}
public void clear() {
items.clear();
notifyDataSetChanged();
}
public List<Invitee> getItems() {
return new ArrayList<>(items);
}
public void addHeader() {
Invitee header = new Invitee();
header.setHeader(true);
items.add(0, header);
}
public void addInvitees(List<Invitee> Invitees) {
for (Invitee tx : Invitees) {
if (!items.contains(tx)) {
items.add(tx);
}
}
notifyDataSetChanged();
}
public int getItemCount() {
return items != null ? items.size() : 0;
}
@Override
public InviteeListAdapter.ViewHolder onCreateViewHolder(ViewGroup root, int viewType) {
View v = LayoutInflater.from(context).inflate(R.layout.list_item_invitee, root, false);
return new InviteeListAdapter.ViewHolder(v);
}
@Override
public void onBindViewHolder(InviteeListAdapter.ViewHolder vh, int position) {
Invitee item = items.get(position);
vh.emailView.setText(item.isHeader() ? context.getString(R.string.email) : item.getEmail());
vh.emailView.setTypeface(null, item.isHeader() ? Typeface.BOLD : Typeface.NORMAL);
String rewardText = context.getString(
item.isInviteRewardClaimed() ? R.string.claimed :
(item.isInviteRewardClaimable() ? R.string.claimable : R.string.unclaimable));
vh.rewardView.setText(item.isHeader() ? context.getString(R.string.reward) : rewardText);
vh.rewardView.setTypeface(null, item.isHeader() ? Typeface.BOLD : Typeface.NORMAL);
}
public static class ViewHolder extends RecyclerView.ViewHolder {
protected final TextView emailView;
protected final TextView rewardView;
public ViewHolder(View v) {
super(v);
emailView = v.findViewById(R.id.invitee_email);
rewardView = v.findViewById(R.id.invitee_reward);
}
}
}

View file

@ -0,0 +1,52 @@
package io.lbry.browser.adapter;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
import androidx.annotation.NonNull;
import io.lbry.browser.R;
import io.lbry.browser.model.Language;
import io.lbry.browser.utils.Predefined;
public class LanguageSpinnerAdapter extends ArrayAdapter<Language> {
private final int layoutResourceId;
private final LayoutInflater inflater;
public LanguageSpinnerAdapter(Context context, int resource) {
super(context, resource, 0, Predefined.PUBLISH_LANGUAGES);
inflater = LayoutInflater.from(context);
layoutResourceId = resource;
}
public int getItemPosition(String languageCode) {
for (int i = 0; i < Predefined.PUBLISH_LANGUAGES.size(); i++) {
Language lang = Predefined.PUBLISH_LANGUAGES.get(i);
if (lang.getCode().equalsIgnoreCase(languageCode)) {
return i;
}
}
return -1;
}
@Override
public View getDropDownView(int position, View view, @NonNull ViewGroup parent) {
return createView(position, view, parent);
}
@Override
public View getView(int position, View view, @NonNull ViewGroup parent) {
return createView(position, view, parent);
}
private View createView(int position, View convertView, ViewGroup parent) {
Language item = getItem(position);
View view = inflater.inflate(layoutResourceId, parent, false);
TextView label = view.findViewById(R.id.item_display_name);
label.setText(item != null ? item.getStringResourceId() : 0);
return view;
}
}

View file

@ -0,0 +1,51 @@
package io.lbry.browser.adapter;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
import androidx.annotation.NonNull;
import io.lbry.browser.R;
import io.lbry.browser.model.License;
import io.lbry.browser.utils.Predefined;
public class LicenseSpinnerAdapter extends ArrayAdapter<License> {
private final int layoutResourceId;
private final LayoutInflater inflater;
public LicenseSpinnerAdapter(Context context, int resource) {
super(context, resource, 0, Predefined.LICENSES);
inflater = LayoutInflater.from(context);
layoutResourceId = resource;
}
public int getItemPosition(String name) {
for (int i = 0; i < Predefined.LICENSES.size(); i++) {
License lic = Predefined.LICENSES.get(i);
if (lic.getName().equalsIgnoreCase(name)) {
return i;
}
}
return -1;
}
@Override
public View getDropDownView(int position, View view, @NonNull ViewGroup parent) {
return createView(position, view, parent);
}
@Override
public View getView(int position, View view, @NonNull ViewGroup parent) {
return createView(position, view, parent);
}
private View createView(int position, View convertView, ViewGroup parent) {
License item = getItem(position);
View view = inflater.inflate(layoutResourceId, parent, false);
TextView label = view.findViewById(R.id.item_display_name);
label.setText(item != null ? item.getStringResourceId() : 0);
return view;
}
}

View file

@ -0,0 +1,114 @@
package io.lbry.browser.adapter;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import java.util.List;
import io.lbry.browser.R;
import io.lbry.browser.model.NavMenuItem;
import io.lbry.browser.ui.controls.SolidIconView;
import io.lbry.browser.utils.Helper;
import lombok.Setter;
public class NavigationMenuAdapter extends RecyclerView.Adapter<NavigationMenuAdapter.ViewHolder> {
private static final int TYPE_GROUP = 1;
private static final int TYPE_ITEM = 2;
private final Context context;
private final List<NavMenuItem> menuItems;
private NavMenuItem currentItem;
@Setter
private NavigationMenuItemClickListener listener;
public NavigationMenuAdapter(List<NavMenuItem> menuItems, Context context) {
this.menuItems = new ArrayList<>(menuItems);
this.context = context;
}
public void setCurrentItem(int id) {
for (NavMenuItem item : menuItems) {
if (item.getId() == id) {
this.currentItem = item;
break;
}
}
notifyDataSetChanged();
}
public void setExtraLabelForItem(int id, String extraLabel) {
for (NavMenuItem item : menuItems) {
if (item.getId() == id) {
item.setExtraLabel(extraLabel);
break;
}
}
notifyDataSetChanged();
}
public void setCurrentItem(NavMenuItem currentItem) {
this.currentItem = currentItem;
notifyDataSetChanged();
}
public int getCurrentItemId() {
return currentItem != null ? currentItem.getId() : -1;
}
public static class ViewHolder extends RecyclerView.ViewHolder {
protected final SolidIconView iconView;
protected final TextView titleView;
public ViewHolder(View v) {
super(v);
titleView = v.findViewById(R.id.nav_menu_title);
iconView = v.findViewById(R.id.nav_menu_item_icon);
}
}
@Override
public int getItemCount() {
return menuItems != null ? menuItems.size() : 0;
}
@Override
public int getItemViewType(int position) {
return menuItems.get(position).isGroup() ? TYPE_GROUP : TYPE_ITEM;
}
@Override
public NavigationMenuAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(context).inflate(viewType == TYPE_GROUP ?
R.layout.list_item_nav_menu_group : R.layout.list_item_nav_menu_item, parent, false);
return new NavigationMenuAdapter.ViewHolder(v);
}
@Override
public void onBindViewHolder(ViewHolder vh, int position) {
int type = getItemViewType(position);
NavMenuItem item = menuItems.get(position);
String displayTitle = !Helper.isNullOrEmpty(item.getExtraLabel()) ? String.format("%s (%s)", item.getTitle(), item.getExtraLabel()) : item.getTitle();
vh.titleView.setText(displayTitle);
if (type == TYPE_ITEM && vh.iconView != null) {
vh.iconView.setText(item.getIcon());
}
vh.itemView.setSelected(item.equals(currentItem));
vh.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (listener != null) {
listener.onNavigationMenuItemClicked(item);
}
}
});
}
public interface NavigationMenuItemClickListener {
void onNavigationMenuItemClicked(NavMenuItem menuItem);
}
}

View file

@ -0,0 +1,265 @@
package io.lbry.browser.adapter;
import android.content.Context;
import android.graphics.Color;
import android.text.format.DateUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.TimeZone;
import io.lbry.browser.R;
import io.lbry.browser.listener.SelectionModeListener;
import io.lbry.browser.model.Claim;
import io.lbry.browser.model.lbryinc.LbryNotification;
import io.lbry.browser.ui.controls.SolidIconView;
import io.lbry.browser.utils.Helper;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
@Data
@EqualsAndHashCode(callSuper = false)
public class NotificationListAdapter extends RecyclerView.Adapter<NotificationListAdapter.ViewHolder> {
private static final String RULE_CREATOR_SUBSCRIBER = "creator_subscriber";
private static final String RULE_COMMENT = "comment";
private final Context context;
private final List<LbryNotification> items;
private final List<LbryNotification> selectedItems;
@Setter
private NotificationClickListener clickListener;
@Getter
@Setter
private boolean inSelectionMode;
@Setter
private SelectionModeListener selectionModeListener;
public NotificationListAdapter(List<LbryNotification> notifications, Context context) {
this.context = context;
this.items = new ArrayList<>(notifications);
this.selectedItems = new ArrayList<>();
Collections.sort(items, Collections.reverseOrder(new LbryNotification()));
}
public static class ViewHolder extends RecyclerView.ViewHolder {
protected final View layoutView;
protected final TextView titleView;
protected final TextView bodyView;
protected final TextView timeView;
protected final SolidIconView iconView;
protected final ImageView thumbnailView;
protected final View selectedOverlayView;
public ViewHolder(View v) {
super(v);
layoutView = v.findViewById(R.id.notification_layout);
titleView = v.findViewById(R.id.notification_title);
bodyView = v.findViewById(R.id.notification_body);
timeView = v.findViewById(R.id.notification_time);
iconView = v.findViewById(R.id.notification_icon);
thumbnailView = v.findViewById(R.id.notification_author_thumbnail);
selectedOverlayView = v.findViewById(R.id.notification_selected_overlay);
}
}
public int getItemCount() {
return items != null ? items.size() : 0;
}
public List<LbryNotification> getSelectedItems() {
return this.selectedItems;
}
public int getSelectedCount() {
return selectedItems != null ? selectedItems.size() : 0;
}
public void clearSelectedItems() {
this.selectedItems.clear();
}
public boolean isNotificationSelected(LbryNotification notification) {
return selectedItems.contains(notification);
}
public void insertNotification(LbryNotification notification, int index) {
if (!items.contains(notification)) {
items.add(index, notification);
}
notifyDataSetChanged();
}
public void addNotification(LbryNotification notification) {
if (!items.contains(notification)) {
items.add(notification);
}
notifyDataSetChanged();
}
public void removeNotifications(List<LbryNotification> notifications) {
for (LbryNotification notification : notifications) {
items.remove(notification);
}
notifyDataSetChanged();
}
public List<String> getAuthorUrls() {
List<String> urls = new ArrayList<>();
for (LbryNotification item : items) {
if (!Helper.isNullOrEmpty(item.getAuthorUrl())) {
urls.add(item.getAuthorUrl());
}
}
return urls;
}
public void updateAuthorClaims(List<Claim> claims) {
for (Claim claim : claims) {
if (claim != null && claim.getThumbnailUrl() != null) {
updateClaimForAuthorUrl(claim);
}
}
notifyDataSetChanged();
}
private void updateClaimForAuthorUrl(Claim claim) {
for (LbryNotification item : items) {
if (claim.getPermanentUrl().equalsIgnoreCase(item.getAuthorUrl())) {
item.setCommentAuthor(claim);
}
}
}
public void addNotifications(List<LbryNotification> notifications) {
for (LbryNotification notification : notifications) {
if (!items.contains(notification)) {
items.add(notification);
}
}
Collections.sort(items, Collections.reverseOrder(new LbryNotification()));
notifyDataSetChanged();
}
@Override
public NotificationListAdapter.ViewHolder onCreateViewHolder(ViewGroup root, int viewType) {
View v = LayoutInflater.from(context).inflate(R.layout.list_item_notification, root, false);
return new NotificationListAdapter.ViewHolder(v);
}
private int getStringIdForRule(String rule) {
if (RULE_CREATOR_SUBSCRIBER.equalsIgnoreCase(rule)) {
return R.string.fa_heart;
}
if (RULE_COMMENT.equalsIgnoreCase(rule)) {
return R.string.fa_comment_alt;
}
return R.string.fa_asterisk;
}
private int getColorForRule(String rule) {
if (RULE_CREATOR_SUBSCRIBER.equalsIgnoreCase(rule)) {
return Color.RED;
}
if (RULE_COMMENT.equalsIgnoreCase(rule)) {
return ContextCompat.getColor(context, R.color.nextLbryGreen);
}
return ContextCompat.getColor(context, R.color.lbryGreen);
}
@Override
public void onBindViewHolder(NotificationListAdapter.ViewHolder vh, int position) {
LbryNotification notification = items.get(position);
vh.layoutView.setBackgroundColor(ContextCompat.getColor(context, notification.isSeen() ? android.R.color.transparent : R.color.nextLbryGreenSemiTransparent));
vh.selectedOverlayView.setVisibility(isNotificationSelected(notification) ? View.VISIBLE : View.GONE);
vh.titleView.setVisibility(!Helper.isNullOrEmpty(notification.getTitle()) ? View.VISIBLE : View.GONE);
vh.titleView.setText(notification.getTitle());
vh.bodyView.setText(notification.getDescription());
vh.timeView.setText(DateUtils.getRelativeTimeSpanString(
getLocalNotificationTime(notification), System.currentTimeMillis(), 0, DateUtils.FORMAT_ABBREV_RELATIVE));
vh.thumbnailView.setVisibility(notification.getCommentAuthor() == null ? View.INVISIBLE : View.VISIBLE);
if (notification.getCommentAuthor() != null) {
Glide.with(context.getApplicationContext()).load(
notification.getCommentAuthor().getThumbnailUrl(vh.thumbnailView.getLayoutParams().width, vh.thumbnailView.getLayoutParams().height, 85)).apply(RequestOptions.circleCropTransform()).into(vh.thumbnailView);
}
vh.iconView.setVisibility(notification.getCommentAuthor() != null ? View.INVISIBLE : View.VISIBLE);
vh.iconView.setText(getStringIdForRule(notification.getRule()));
vh.iconView.setTextColor(getColorForRule(notification.getRule()));
vh.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (inSelectionMode) {
toggleSelectedNotification(notification);
} else {
if (clickListener != null) {
clickListener.onNotificationClicked(notification);
}
}
}
});
vh.itemView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
if (!inSelectionMode) {
inSelectionMode = true;
if (selectionModeListener != null) {
selectionModeListener.onEnterSelectionMode();
}
}
toggleSelectedNotification(notification);
return true;
}
});
}
private void toggleSelectedNotification(LbryNotification notification) {
if (selectedItems.contains(notification)) {
selectedItems.remove(notification);
} else {
selectedItems.add(notification);
}
if (selectionModeListener != null) {
selectionModeListener.onItemSelectionToggled();
}
if (selectedItems.size() == 0) {
inSelectionMode = false;
if (selectionModeListener != null) {
selectionModeListener.onExitSelectionMode();
}
}
notifyDataSetChanged();
}
private long getLocalNotificationTime(LbryNotification notification) {
TimeZone utcTZ = TimeZone.getTimeZone("UTC");
TimeZone targetTZ = TimeZone.getDefault();
Calendar cal = new GregorianCalendar(utcTZ);
cal.setTimeInMillis(notification.getTimestamp().getTime());
cal.add(Calendar.MILLISECOND, utcTZ.getRawOffset() * -1);
cal.add(Calendar.MILLISECOND, targetTZ.getRawOffset());
return cal.getTimeInMillis();
}
public interface NotificationClickListener {
void onNotificationClicked(LbryNotification notification);
}
}

View file

@ -0,0 +1,220 @@
package io.lbry.browser.adapter;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.net.Uri;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.button.MaterialButton;
import com.google.android.material.snackbar.Snackbar;
import java.util.ArrayList;
import java.util.List;
import io.lbry.browser.R;
import io.lbry.browser.model.lbryinc.Reward;
import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.Lbryio;
import lombok.Getter;
import lombok.Setter;
public class RewardListAdapter extends RecyclerView.Adapter<RewardListAdapter.ViewHolder> {
public static final int DISPLAY_MODE_ALL = 1;
public static final int DISPLAY_MODE_UNCLAIMED = 2;
private final Context context;
@Setter
private List<Reward> all;
private List<Reward> items;
@Setter
private RewardClickListener clickListener;
@Getter
private int displayMode;
public RewardListAdapter(List<Reward> all, Context context) {
this.all = new ArrayList<>(all);
this.items = new ArrayList<>(all);
this.context = context;
this.displayMode = DISPLAY_MODE_ALL;
addCustomReward();
}
public void setRewards(List<Reward> rewards) {
this.all = new ArrayList<>(rewards);
updateItemsForDisplayMode();
notifyDataSetChanged();
}
public void setDisplayMode(int displayMode) {
this.displayMode = displayMode;
updateItemsForDisplayMode();
notifyDataSetChanged();
}
private void updateItemsForDisplayMode() {
if (displayMode == DISPLAY_MODE_ALL) {
items = new ArrayList<>(all);
} else if (displayMode == DISPLAY_MODE_UNCLAIMED) {
items = new ArrayList<>();
for (Reward reward : all) {
if (!reward.isClaimed()) {
items.add(reward);
}
}
}
addCustomReward();
}
private void addCustomReward() {
Reward custom = new Reward();
custom.setCustom(true);
custom.setRewardTitle(context.getString(R.string.custom_reward_title));
custom.setRewardDescription(context.getString(R.string.custom_reward_description));
items.add(custom);
}
public static class ViewHolder extends RecyclerView.ViewHolder {
protected final View iconClaimed;
protected final View loading;
protected final View upTo;
protected final TextView textTitle;
protected final TextView textDescription;
protected final TextView textLbcValue;
protected final TextView textUsdValue;
protected final TextView textLinkTransaction;
protected final EditText inputCustomCode;
protected final MaterialButton buttonClaimCustom;
public ViewHolder(View v) {
super(v);
iconClaimed = v.findViewById(R.id.reward_item_claimed_icon);
upTo = v.findViewById(R.id.reward_item_up_to);
loading = v.findViewById(R.id.reward_item_loading);
textTitle = v.findViewById(R.id.reward_item_title);
textDescription = v.findViewById(R.id.reward_item_description);
textLbcValue = v.findViewById(R.id.reward_item_lbc_value);
textLinkTransaction = v.findViewById(R.id.reward_item_tx_link);
textUsdValue = v.findViewById(R.id.reward_item_usd_value);
inputCustomCode = v.findViewById(R.id.reward_item_custom_code_input);
buttonClaimCustom = v.findViewById(R.id.reward_item_custom_claim_button);
}
}
public int getItemCount() {
return items != null ? items.size() : 0;
}
public void addReward(Reward reward) {
if (!items.contains(reward)) {
items.add(reward);
}
notifyDataSetChanged();
}
public List<Reward> getRewards() {
return new ArrayList<>(items);
}
@Override
public RewardListAdapter.ViewHolder onCreateViewHolder(ViewGroup root, int viewType) {
View v = LayoutInflater.from(context).inflate(R.layout.list_item_reward, root, false);
return new RewardListAdapter.ViewHolder(v);
}
@Override
public void onBindViewHolder(RewardListAdapter.ViewHolder vh, int position) {
Reward reward = items.get(position);
String displayAmount = reward.getDisplayAmount();
double rewardAmount = 0;
if (!"?".equals(displayAmount)) {
rewardAmount = Double.valueOf(displayAmount);
}
boolean hasTransaction = !Helper.isNullOrEmpty(reward.getTransactionId()) && reward.getTransactionId().length() > 7;
vh.iconClaimed.setVisibility(reward.isClaimed() ? View.VISIBLE : View.INVISIBLE);
vh.inputCustomCode.setVisibility(reward.isCustom() ? View.VISIBLE : View.GONE);
vh.buttonClaimCustom.setVisibility(reward.isCustom() ? View.VISIBLE : View.GONE);
vh.textTitle.setText(reward.getRewardTitle());
vh.textDescription.setText(reward.getRewardDescription());
vh.upTo.setVisibility(reward.shouldDisplayRange() ? View.VISIBLE : View.GONE);
vh.textLbcValue.setText(reward.isCustom() ? "?" : Helper.LBC_CURRENCY_FORMAT.format(Helper.parseDouble(reward.getDisplayAmount(), 0)));
vh.textLinkTransaction.setVisibility(hasTransaction ? View.VISIBLE : View.GONE);
vh.textLinkTransaction.setText(hasTransaction ? reward.getTransactionId().substring(0, 7) : null);
vh.textLinkTransaction.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (context != null) {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(String.format("%s/%s", Helper.EXPLORER_TX_PREFIX, reward.getTransactionId())));
context.startActivity(intent);
}
}
});
vh.textUsdValue.setText(reward.isCustom() || Lbryio.LBCUSDRate == 0 ? null :
String.format("≈$%s", Helper.SIMPLE_CURRENCY_FORMAT.format(rewardAmount * Lbryio.LBCUSDRate)));
vh.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (reward.isClaimed()) {
return;
}
if (vh.inputCustomCode != null && !vh.inputCustomCode.hasFocus()) {
vh.inputCustomCode.requestFocus();
}
if (clickListener != null) {
clickListener.onRewardClicked(reward, vh.loading);
}
}
});
vh.inputCustomCode.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
String value = charSequence.toString().trim();
vh.buttonClaimCustom.setEnabled(value.length() > 0);
}
@Override
public void afterTextChanged(Editable editable) {
}
});
vh.buttonClaimCustom.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String claimCode = Helper.getValue(vh.inputCustomCode.getText());
if (Helper.isNullOrEmpty(claimCode)) {
Snackbar.make(view, R.string.please_enter_claim_code, Snackbar.LENGTH_LONG).
setBackgroundTint(Color.RED).setTextColor(Color.WHITE).show();
return;
}
if (clickListener != null) {
clickListener.onCustomClaimButtonClicked(claimCode, vh.inputCustomCode, vh.buttonClaimCustom, vh.loading);
}
}
});
}
public interface RewardClickListener {
void onRewardClicked(Reward reward, View loadingView);
void onCustomClaimButtonClicked(String code, EditText inputCustomCode, MaterialButton buttonClaim, View loadingView);
}
}

View file

@ -0,0 +1,70 @@
package io.lbry.browser.adapter;
import android.content.Context;
import android.graphics.Color;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.List;
import io.lbry.browser.R;
import io.lbry.browser.model.StartupStage;
public class StartupStageAdapter extends BaseAdapter {
private final List<StartupStage> list;
private final LayoutInflater inflater;
private final String[] stagesString;
public StartupStageAdapter(Context ctx, List<StartupStage> rows) {
this.list = rows;
this.inflater = LayoutInflater.from(ctx);
stagesString = new String[9];
stagesString[0] = ctx.getResources().getString(R.string.installation_id_loaded);
stagesString[1] = ctx.getResources().getString(R.string.known_tags_loaded);
stagesString[2] = ctx.getResources().getString(R.string.exchange_rate_loaded);
stagesString[3] = ctx.getResources().getString(R.string.user_authenticated);
stagesString[4] = ctx.getResources().getString(R.string.installation_registered);
stagesString[5] = ctx.getResources().getString(R.string.subscriptions_loaded);
stagesString[6] = ctx.getResources().getString(R.string.subscriptions_resolved);
stagesString[7] = ctx.getResources().getString(R.string.block_list_loaded);
stagesString[8] = ctx.getResources().getString(R.string.filter_list_loaded);
}
@Override
public int getCount() {
return list.size();
}
@Override
public Object getItem(int i) {
return list.get(i);
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
if (view == null) {
view = inflater.inflate(R.layout.list_item_startupstage, viewGroup, false);
ImageView iconView = view.findViewById(R.id.startup_stage_icon);
TextView textView = view.findViewById(R.id.startup_stage_text);
StartupStage item = (StartupStage) getItem(i);
iconView.setImageResource(item.stageDone ? R.drawable.ic_check : R.drawable.ic_close);
iconView.setColorFilter(item.stageDone ? Color.WHITE : Color.RED);
textView.setText(stagesString[item.stage - 1]);
}
return view;
}
}

View file

@ -0,0 +1,128 @@
package io.lbry.browser.adapter;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
import java.util.ArrayList;
import java.util.List;
import io.lbry.browser.R;
import io.lbry.browser.model.Claim;
import io.lbry.browser.listener.ChannelItemSelectionListener;
import io.lbry.browser.utils.Helper;
import lombok.Setter;
public class SuggestedChannelGridAdapter extends RecyclerView.Adapter<SuggestedChannelGridAdapter.ViewHolder> {
private final Context context;
private final List<Claim> items;
private final List<Claim> selectedItems;
@Setter
private ChannelItemSelectionListener listener;
public SuggestedChannelGridAdapter(List<Claim> items, Context context) {
this.items = new ArrayList<>(items);
this.selectedItems = new ArrayList<>();
this.context = context;
}
public static class ViewHolder extends RecyclerView.ViewHolder {
protected final View noThumbnailView;
protected final ImageView thumbnailView;
protected final TextView alphaView;
protected final TextView titleView;
protected final TextView tagView;
public ViewHolder(View v) {
super(v);
noThumbnailView = v.findViewById(R.id.suggested_channel_no_thumbnail);
alphaView = v.findViewById(R.id.suggested_channel_alpha_view);
thumbnailView = v.findViewById(R.id.suggested_channel_thumbnail);
titleView = v.findViewById(R.id.suggested_channel_title);
tagView = v.findViewById(R.id.suggested_channel_tag);
}
}
public int getItemCount() {
return items != null ? items.size() : 0;
}
public int getSelectedCount() { return selectedItems.size(); }
public void clearItems() {
items.clear();
notifyDataSetChanged();
}
public List<Claim> getSelectedItems() {
return this.selectedItems;
}
public void clearSelectedItems() {
this.selectedItems.clear();
}
public boolean isClaimSelected(Claim claim) {
return selectedItems.contains(claim);
}
public void addClaims(List<Claim> claims) {
for (Claim claim : claims) {
if (!items.contains(claim)) {
items.add(claim);
}
}
notifyDataSetChanged();
}
@Override
public SuggestedChannelGridAdapter.ViewHolder onCreateViewHolder(ViewGroup root, int viewType) {
View v = LayoutInflater.from(context).inflate(R.layout.list_item_suggested_channel, root, false);
return new SuggestedChannelGridAdapter.ViewHolder(v);
}
@Override
public void onBindViewHolder(SuggestedChannelGridAdapter.ViewHolder vh, int position) {
Claim claim = items.get(position);
ViewGroup.LayoutParams lp = vh.thumbnailView.getLayoutParams();
String thumbnailUrl = claim.getThumbnailUrl(lp.width, lp.height, 85);
int bgColor = Helper.generateRandomColorForValue(claim.getClaimId());
Helper.setIconViewBackgroundColor(vh.noThumbnailView, bgColor, false, context);
vh.noThumbnailView.setVisibility(Helper.isNullOrEmpty(thumbnailUrl) ? View.INVISIBLE : View.VISIBLE);
vh.alphaView.setText(claim.getName().substring(1, 2));
if (!Helper.isNullOrEmpty(thumbnailUrl)) {
vh.thumbnailView.setVisibility(View.VISIBLE);
Glide.with(context.getApplicationContext()).load(thumbnailUrl).apply(RequestOptions.circleCropTransform()).into(vh.thumbnailView);
} else {
vh.thumbnailView.setVisibility(View.GONE);
}
vh.titleView.setText(Helper.isNullOrEmpty(claim.getTitle()) ? claim.getName() : claim.getTitle());
String firstTag = claim.getFirstTag();
vh.tagView.setVisibility(Helper.isNullOrEmpty(firstTag) ? View.INVISIBLE : View.VISIBLE);
vh.tagView.setBackgroundResource(R.drawable.bg_tag);
vh.tagView.setText(firstTag);
vh.itemView.setSelected(isClaimSelected(claim));
vh.itemView.setOnClickListener(view -> {
if (selectedItems.contains(claim)) {
selectedItems.remove(claim);
if (listener != null) {
listener.onChannelItemDeselected(claim);
}
} else {
selectedItems.add(claim);
if (listener != null) {
listener.onChannelItemSelected(claim);
}
}
notifyDataSetChanged();
});
}
}

View file

@ -0,0 +1,109 @@
package io.lbry.browser.adapter;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import java.util.List;
import io.lbry.browser.R;
import io.lbry.browser.model.Tag;
import lombok.Getter;
import lombok.Setter;
public class TagListAdapter extends RecyclerView.Adapter<TagListAdapter.ViewHolder> {
public static final int CUSTOMIZE_MODE_NONE = 0;
public static final int CUSTOMIZE_MODE_ADD = 1;
public static final int CUSTOMIZE_MODE_REMOVE = 2;
private final Context context;
private List<Tag> items;
@Setter
private TagClickListener clickListener;
@Setter
@Getter
private int customizeMode;
public TagListAdapter(List<Tag> tags, Context context) {
this.context = context;
this.items = new ArrayList<>(tags);
this.customizeMode = CUSTOMIZE_MODE_NONE;
}
public static class ViewHolder extends RecyclerView.ViewHolder {
protected final ImageView iconView;
protected final TextView nameView;
public ViewHolder(View v) {
super(v);
iconView = v.findViewById(R.id.tag_action);
nameView = v.findViewById(R.id.tag_name);
}
}
public int getItemCount() {
return items != null ? items.size() : 0;
}
public void addTag(Tag tag) {
if (!items.contains(tag)) {
items.add(tag);
}
notifyDataSetChanged();
}
public List<Tag> getTags() {
return new ArrayList<>(items);
}
public void setTags(List<Tag> tags) {
items = new ArrayList<>(tags);
notifyDataSetChanged();
}
public void addTags(List<Tag> tags) {
for (Tag tag : tags) {
if (!items.contains(tag)) {
items.add(tag);
}
}
notifyDataSetChanged();
}
public void removeTag(Tag tag) {
items.remove(tag);
notifyDataSetChanged();
}
@Override
public TagListAdapter.ViewHolder onCreateViewHolder(ViewGroup root, int viewType) {
View v = LayoutInflater.from(context).inflate(R.layout.list_item_tag, root, false);
return new TagListAdapter.ViewHolder(v);
}
@Override
public void onBindViewHolder(TagListAdapter.ViewHolder vh, int position) {
Tag tag = items.get(position);
vh.nameView.setText(tag.getName().toLowerCase());
vh.iconView.setVisibility(customizeMode == CUSTOMIZE_MODE_NONE ? View.GONE : View.VISIBLE);
vh.iconView.setImageResource(customizeMode == CUSTOMIZE_MODE_REMOVE ? R.drawable.ic_close : R.drawable.ic_add);
vh.itemView.setBackgroundResource(tag.isMature() ? R.drawable.bg_tag_mature : R.drawable.bg_tag);
vh.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (clickListener != null) {
clickListener.onTagClicked(tag, customizeMode);
}
}
});
}
public interface TagClickListener {
void onTagClicked(Tag tag, int customizeMode);
}
}

View file

@ -0,0 +1,136 @@
package io.lbry.browser.adapter;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import io.lbry.browser.R;
import io.lbry.browser.model.Transaction;
import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.LbryUri;
import lombok.Setter;
public class TransactionListAdapter extends RecyclerView.Adapter<TransactionListAdapter.ViewHolder> {
private static final DecimalFormat TX_LIST_AMOUNT_FORMAT = new DecimalFormat("#,##0.0000");
private static final SimpleDateFormat TX_LIST_DATE_FORMAT = new SimpleDateFormat("MMM d");
private final Context context;
private final List<Transaction> items;
@Setter
private TransactionClickListener listener;
public TransactionListAdapter(List<Transaction> transactions, Context context) {
this.context = context;
this.items = new ArrayList<>(transactions);
}
public void clear() {
items.clear();
notifyDataSetChanged();
}
public List<Transaction> getItems() {
return new ArrayList<>(items);
}
public void addTransactions(List<Transaction> transactions) {
for (Transaction tx : transactions) {
if (!items.contains(tx)) {
items.add(tx);
}
}
notifyDataSetChanged();
}
public int getItemCount() {
return items != null ? items.size() : 0;
}
@Override
public TransactionListAdapter.ViewHolder onCreateViewHolder(ViewGroup root, int viewType) {
View v = LayoutInflater.from(context).inflate(R.layout.list_item_transaction, root, false);
return new TransactionListAdapter.ViewHolder(v);
}
@Override
public void onBindViewHolder(TransactionListAdapter.ViewHolder vh, int position) {
Transaction item = items.get(position);
vh.descView.setText(item.getDescriptionStringId());
vh.amountView.setText(TX_LIST_AMOUNT_FORMAT.format(item.getValue().doubleValue()));
vh.claimView.setText(item.getClaim());
vh.feeView.setText(context.getString(R.string.tx_list_fee, TX_LIST_AMOUNT_FORMAT.format(item.getFee().doubleValue())));
vh.txidLinkView.setText(item.getTxid().substring(0, 7));
vh.dateView.setVisibility(item.getConfirmations() > 0 ? View.VISIBLE : View.GONE);
vh.dateView.setText(item.getConfirmations() > 0 ? TX_LIST_DATE_FORMAT.format(item.getTxDate()) : null);
vh.pendingView.setVisibility(item.getConfirmations() == 0 ? View.VISIBLE : View.GONE);
vh.infoFeeContainer.setVisibility(!Helper.isNullOrEmpty(item.getClaim()) || Math.abs(item.getFee().doubleValue()) > 0 ?
View.VISIBLE : View.GONE);
vh.claimView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
LbryUri claimUrl = item.getClaimUrl();
if (claimUrl != null && listener != null) {
listener.onClaimUrlClicked(claimUrl);
}
}
});
vh.txidLinkView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (context != null) {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(String.format("%s/%s", Helper.EXPLORER_TX_PREFIX, item.getTxid())));
context.startActivity(intent);
}
}
});
vh.itemView.setOnClickListener(view -> {
if (listener != null) {
listener.onTransactionClicked(item);
}
});
}
public static class ViewHolder extends RecyclerView.ViewHolder {
protected final TextView descView;
protected final TextView amountView;
protected final TextView claimView;
protected final TextView feeView;
protected final TextView txidLinkView;
protected final TextView dateView;
protected final TextView pendingView;
protected final View infoFeeContainer;
public ViewHolder(View v) {
super(v);
descView = v.findViewById(R.id.transaction_desc);
amountView = v.findViewById(R.id.transaction_amount);
claimView = v.findViewById(R.id.transaction_claim);
feeView = v.findViewById(R.id.transaction_fee);
txidLinkView = v.findViewById(R.id.transaction_id_link);
dateView = v.findViewById(R.id.transaction_date);
pendingView = v.findViewById(R.id.transaction_pending_text);
infoFeeContainer = v.findViewById(R.id.transaction_info_fee_container);
}
}
public interface TransactionClickListener {
void onTransactionClicked(Transaction transaction);
void onClaimUrlClicked(LbryUri uri);
}
}

View file

@ -0,0 +1,147 @@
package io.lbry.browser.adapter;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import java.util.List;
import io.lbry.browser.R;
import io.lbry.browser.exceptions.LbryUriException;
import io.lbry.browser.model.Claim;
import io.lbry.browser.model.UrlSuggestion;
import io.lbry.browser.ui.controls.SolidIconView;
import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.LbryUri;
import lombok.Setter;
public class UrlSuggestionListAdapter extends RecyclerView.Adapter<UrlSuggestionListAdapter.ViewHolder> {
private final Context context;
private final List<UrlSuggestion> items;
@Setter
private UrlSuggestionClickListener listener;
public UrlSuggestionListAdapter(Context context) {
this.context = context;
this.items = new ArrayList<>();
}
public void clear() {
items.clear();
notifyDataSetChanged();
}
public List<UrlSuggestion> getItems() {
return new ArrayList<>(items);
}
public List<String> getItemUrls() {
List<String> uris = new ArrayList<>();
for (int i = 0; i < items.size(); i++) {
LbryUri uri = items.get(i).getUri();
if (uri != null) {
uris.add(uri.toString());
}
}
return uris;
}
public void setClaimForUrl(LbryUri url, Claim claim) {
for (int i = 0; i < items.size(); i++) {
LbryUri thisUrl = items.get(i).getUri();
try {
if (thisUrl != null) {
LbryUri vanity = LbryUri.parse(thisUrl.toVanityString());
if (thisUrl.equals(url) || vanity.equals(url)) {
items.get(i).setClaim(claim);
}
}
} catch (LbryUriException ex) {
// pass
}
}
}
public void addUrlSuggestions(List<UrlSuggestion> urlSuggestions) {
for (UrlSuggestion urlSuggestion : urlSuggestions) {
if (!items.contains(urlSuggestion)) {
items.add(urlSuggestion);
}
}
notifyDataSetChanged();
}
public int getItemCount() {
return items != null ? items.size() : 0;
}
@Override
public UrlSuggestionListAdapter.ViewHolder onCreateViewHolder(ViewGroup root, int viewType) {
View v = LayoutInflater.from(context).inflate(R.layout.list_item_url_suggestion, root, false);
return new UrlSuggestionListAdapter.ViewHolder(v);
}
@Override
public void onBindViewHolder(UrlSuggestionListAdapter.ViewHolder vh, int position) {
UrlSuggestion item = items.get(position);
String fullTitle, desc;
int iconStringId;
switch (item.getType()) {
case UrlSuggestion.TYPE_CHANNEL:
iconStringId = R.string.fa_at;
fullTitle = item.getTitle();
desc = item.getClaim() != null ? item.getClaim().getTitle() :
((item.isUseTextAsDescription() && !Helper.isNullOrEmpty(item.getText())) ? item.getText() : String.format(context.getString(R.string.view_channel_url_desc), item.getText()));
break;
case UrlSuggestion.TYPE_TAG:
iconStringId = R.string.fa_hashtag;
fullTitle = String.format(context.getString(R.string.tag_url_title), item.getText());
desc = String.format(context.getString(R.string.explore_tag_url_desc), item.getText());
break;
case UrlSuggestion.TYPE_SEARCH:
iconStringId = R.string.fa_search;
fullTitle = String.format(context.getString(R.string.search_url_title), item.getText());
desc = String.format(context.getString(R.string.search_url_desc), item.getText());
break;
case UrlSuggestion.TYPE_FILE:
default:
iconStringId = R.string.fa_file;
fullTitle = item.getTitle();
desc = item.getClaim() != null ? item.getClaim().getTitle() :
((item.isUseTextAsDescription() && !Helper.isNullOrEmpty(item.getText())) ? item.getText() : String.format(context.getString(R.string.view_file_url_desc), item.getText()));
break;
}
vh.iconView.setText(iconStringId);
vh.titleView.setText(fullTitle);
vh.descView.setText(desc);
vh.itemView.setOnClickListener(view -> {
if (listener != null) {
listener.onUrlSuggestionClicked(item);
}
});
}
public static class ViewHolder extends RecyclerView.ViewHolder {
protected final SolidIconView iconView;
protected final TextView titleView;
protected final TextView descView;
public ViewHolder(View v) {
super(v);
iconView = v.findViewById(R.id.url_suggestion_icon);
titleView = v.findViewById(R.id.url_suggestion_title);
descView = v.findViewById(R.id.url_suggestion_description);
}
}
public interface UrlSuggestionClickListener {
void onUrlSuggestionClicked(UrlSuggestion urlSuggestion);
}
}

View file

@ -0,0 +1,71 @@
package io.lbry.browser.adapter;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.viewpager2.adapter.FragmentStateAdapter;
import io.lbry.browser.listener.SignInListener;
import io.lbry.browser.listener.WalletSyncListener;
import io.lbry.browser.ui.verification.EmailVerificationFragment;
import io.lbry.browser.ui.verification.ManualVerificationFragment;
import io.lbry.browser.ui.verification.PhoneVerificationFragment;
import io.lbry.browser.ui.verification.WalletVerificationFragment;
import lombok.SneakyThrows;
/**
* 4 fragments
* - Email collect / verify (sign in)
* - Phone number collect / verify (rewards)
* - Wallet password
* - Manual verification page
*/
public class VerificationPagerAdapter extends FragmentStateAdapter {
public static final int PAGE_VERIFICATION_EMAIL = 0;
public static final int PAGE_VERIFICATION_PHONE = 1;
public static final int PAGE_VERIFICATION_WALLET = 2;
public static final int PAGE_VERIFICATION_MANUAL = 3;
private final FragmentActivity activity;
public VerificationPagerAdapter(FragmentActivity activity) {
super(activity);
this.activity = activity;
}
@SneakyThrows
@Override
public Fragment createFragment(int position) {
switch (position) {
case 0:
default:
EmailVerificationFragment evFragment = EmailVerificationFragment.class.newInstance();
if (activity instanceof SignInListener) {
evFragment.setListener((SignInListener) activity);
}
return evFragment;
case 1:
PhoneVerificationFragment pvFragment = PhoneVerificationFragment.class.newInstance();
if (activity instanceof SignInListener) {
pvFragment.setListener((SignInListener) activity);
}
return pvFragment;
case 2:
WalletVerificationFragment wvFragment = WalletVerificationFragment.class.newInstance();
if (activity instanceof WalletSyncListener) {
wvFragment.setListener((WalletSyncListener) activity);
}
return wvFragment;
case 3:
ManualVerificationFragment mvFragment = ManualVerificationFragment.class.newInstance();
if (activity instanceof SignInListener) {
mvFragment.setListener((SignInListener) activity);
}
return mvFragment;
}
}
@Override
public int getItemCount() {
return 4;
}
}

View file

@ -0,0 +1,100 @@
package io.lbry.browser.adapter;
import android.content.Context;
import android.content.DialogInterface;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageButton;
import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.appcompat.app.AlertDialog;
import java.util.List;
import io.lbry.browser.MainActivity;
import io.lbry.browser.R;
import io.lbry.browser.model.WalletDetailItem;
import io.lbry.browser.utils.Helper;
import io.lbry.browser.views.CreditsBalanceView;
public class WalletDetailAdapter extends BaseAdapter {
private final List<WalletDetailItem> list;
private final LayoutInflater inflater;
public WalletDetailAdapter(Context ctx, List<WalletDetailItem> rows) {
this.list = rows;
this.inflater = LayoutInflater.from(ctx);
}
@Override
public int getCount() {
return list.size();
}
@Override
public Object getItem(int i) {
return list.get(i);
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
if (view == null) {
view = inflater.inflate(R.layout.list_item_boosting_balance, viewGroup, false);
CreditsBalanceView balanceView = view.findViewById(R.id.wallet_supporting_balance);
TextView detailTextView = view.findViewById(R.id.detail);
TextView detailExplanationTextView = view.findViewById(R.id.detail_explanation);
WalletDetailItem item = (WalletDetailItem) getItem(i);
detailTextView.setText(item.detail);
detailExplanationTextView.setText(item.detailDesc);
Helper.setViewText(balanceView, item.detailAmount);
ProgressBar progressUnlockTips = view.findViewById(R.id.wallet_unlock_tips_progress);
progressUnlockTips.setVisibility(item.isInProgress ? View.VISIBLE : View.GONE);
ImageButton buttonLock = view.findViewById(R.id.lock_button);
buttonLock.setVisibility((item.isUnlockable && !item.isInProgress) ? View.VISIBLE : View.GONE);
if (item.isUnlockable) {
buttonLock.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (view.getContext() != null) {
AlertDialog.Builder builder = new AlertDialog.Builder(view.getContext()).
setTitle(R.string.unlock_tips).
setMessage(R.string.confirm_unlock_tips)
.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
unlockTips(view);
}
}).setNegativeButton(R.string.no, null);
builder.show();
}
}
});
}
}
return view;
}
private void unlockTips(View v) {
Context ctx = v.getContext();
if (ctx instanceof MainActivity) {
v.setVisibility(View.GONE);
View progress = v.getRootView().findViewById(R.id.wallet_unlock_tips_progress);
progress.setVisibility(View.VISIBLE);
((MainActivity) ctx).unlockTips();
}
}
}

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