Compare commits

...

212 Commits

Author SHA1 Message Date
5999b8ed4a Release 2.2.2 (#170) 2019-10-25 05:44:53 +00:00
2cba285076 Merge branch 'backport_162' of gitnex/GitNex into release-2.2 2019-10-21 17:31:44 +00:00
24a552f0a9 Fix login with email for my repositories 2019-10-21 18:57:52 +02:00
d9a7fa4e44 Merge branch 'bugfix-release-2.2.1' of gitnex/GitNex into release-2.2 2019-10-18 14:55:15 +00:00
9950d4ea65 prepare release 2.2.1 2019-10-18 19:51:56 +05:00
98054b89cc Merge branch 'fix-empty-repo-bug' of gitnex/GitNex into release-2.2 2019-10-18 13:47:00 +00:00
24d56c625e Fix #154 2019-10-18 18:40:54 +05:00
5970995ef0 added file viewer 2019-10-18 10:28:18 +05:00
cf75c61704 release 2.2.0 2019-10-18 10:10:47 +05:00
8ac92a8b3c Merge branch '121-sub-dir-browsing' of gitnex/GitNex into master 2019-10-17 22:49:49 +00:00
f1f92ba494 make CI work 2019-10-18 00:46:19 +02:00
d7b1a226d0 implemented sub dir view 2019-10-17 22:47:27 +05:00
2bebe1e81d Merge branch 'crowdin_2019-10-17' of gitnex/GitNex into master 2019-10-17 15:54:59 +00:00
f5d560c601 Update Crowdin 2019-10-17 16:09:40 +02:00
d27000d481 Merge branch 'minor-fixes' of gitnex/GitNex into master 2019-10-17 13:57:55 +00:00
9aff1cb42a Minor ui fixes 2019-10-16 18:28:24 +05:00
7fe376fa44 Merge branch 'improve-ci' of gitnex/GitNex into master 2019-10-14 10:02:31 +00:00
6da4398369 dont run with empty task 2019-10-14 11:27:04 +02:00
dac0f690d8 more precise name 2019-10-14 11:06:46 +02:00
8a7031e7f5 Merge branch 'translation_add-Serbian' of 6543/GitNex into master 2019-10-14 05:11:31 +00:00
dd5f17d54d format code 2019-10-13 19:19:44 +02:00
505c930c32 first sr strings 2019-10-13 19:19:20 +02:00
edb6cdf154 add Serbian to Settings 2019-10-13 19:19:04 +02:00
687b66751f Merge branch 'crowdin_2019-10-13' of gitnex/GitNex into master 2019-10-13 12:51:24 +00:00
f14ae18324 Merge branch 'translation_add-Italian' of 6543/GitNex into master 2019-10-13 12:50:46 +00:00
ea52d6c6d2 dont run twice 2019-10-13 02:46:52 +02:00
40d12c3b97 Update Translation 2019-10-13 02:13:53 +02:00
32ebf31ef4 add first it strings 2019-10-13 02:08:46 +02:00
7fc4146c98 add Italian 2019-10-13 02:08:27 +02:00
e296a83aab Merge branch 'update-libs' of gitnex/GitNex into master 2019-10-12 17:13:43 +00:00
0fc7c67d0b update libs 2019-10-12 19:34:33 +05:00
143d680627 Merge branch '136-watch-a-repo' of gitnex/GitNex into master 2019-10-12 13:29:43 +00:00
69745b027e Implemented watch and unwatch a repository 2019-10-12 14:00:36 +05:00
7f3aed9bae fix star repo layout 2019-10-12 12:55:12 +05:00
5496401a77 Merge branch '130-star-a-repo' of gitnex/GitNex into master 2019-10-11 20:18:15 +00:00
4c0fd3c286 Implemented star/unstar a repository 2019-10-12 01:03:01 +05:00
40f924de2e Merge branch 'translation_add-Finnish' of 6543/GitNex into master 2019-10-11 19:24:49 +00:00
1953a9feff add Finnish 2019-10-11 20:14:59 +02:00
24c71b4beb Merge branch 'drone-rename-pipeline' of gitnex/GitNex into master 2019-10-11 18:08:52 +00:00
958606e476 add first strings 2019-10-11 20:07:50 +02:00
39d1007423 Drone Rename Pipeline
Rename Pipeline -> it does not loon nice and does not make sense
2019-10-11 18:02:40 +00:00
0e673bb256 Merge branch 'mentions' of 6543/GitNex into master 2019-10-11 16:53:11 +00:00
246ff6296a new line " " and italic 2019-10-11 18:34:22 +02:00
1d0b940c14 add sugestions + new translator 2019-10-11 18:15:19 +02:00
4d3fb54925 Merge branch 'lunny/add_ci_badge' of lunny/GitNex into master 2019-10-11 15:44:36 +00:00
cd81ff74bf add mentions 2019-10-11 16:57:53 +02:00
02843b4ca1 Add CI status badge on README 2019-10-11 13:15:05 +00:00
2189bd10bd Merge branch '100-bottomsheet-scroll' of gitnex/GitNex into master 2019-10-11 13:08:57 +00:00
35b9647709 improve bottomsheet with scroll and separater 2019-10-11 16:36:42 +05:00
2d2f486182 Merge branch '88-update-images' of gitnex/GitNex into master 2019-10-10 19:54:37 +00:00
640771d4fa update store images, update app description 2019-10-10 22:38:09 +05:00
2ba8a80b9f Merge branch 'repoSearch' of 6543/GitNex into master 2019-10-10 16:02:04 +00:00
2f55e7f5d1 enable to browse repository 2019-10-10 20:49:12 +05:00
d285115090 reset the adapter on new query 2019-10-10 19:01:15 +05:00
d5cffddc72 Implemented search ui and screen for exploring repositories. 2019-10-10 18:40:43 +05:00
9e2921697b Merge branch 'add-drone-ci' of gitnex/GitNex into master 2019-10-10 07:49:12 +00:00
e868364554 Merge branch 'crowdin_2019-10-10' of gitnex/GitNex into master 2019-10-10 07:48:27 +00:00
88a8303b1c Add Drone CI Config
* testing
       - test
       - build
2019-10-10 03:29:35 +02:00
ac1fc696ea complete france translation 2019-10-10 01:40:54 +02:00
2fe175223c combine commits
* add Explore Function
* define API
* Add Fragment + Code + String
* add to main activity (by @mmarif)
2019-10-10 01:21:34 +02:00
9cab502e84 Merge branch 'mv-org-update-links' of 6543/GitNex into master 2019-10-09 18:40:12 +00:00
88748998b3 update repo links 2019-10-09 16:09:07 +02:00
264ed393cb Merge branch 'readme-add-crowdin' of 6543/GitNex into master 2019-10-08 15:27:27 +00:00
821eef91a3 Merge branch 'crowdin_2019-10-07' of mmarif/GitNex into master 2019-10-08 15:26:56 +00:00
05afc9fc5a Merge branch 'crowdin-add-Persian' of 6543/GitNex into master 2019-10-08 15:26:18 +00:00
4cb6948288 Merge branch 'build-fix' of mmarif/GitNex into master 2019-10-08 14:48:28 +00:00
7012c2587c crowdin update 2019-10-08 02:54:18 +02:00
dbcbd076ea Build Fix 2019-10-08 02:41:39 +02:00
c633b62fdb show screenshots directly 2019-10-07 19:53:41 +02:00
1ce1a15955 mv Translation info (CONTRIBUTE -> README)
wil close https://gitea.com/mmarif/GitNex/issues/108
2019-10-07 19:53:30 +02:00
60b95e3c5d Add first Persian strings
got it from 243e53895b
2019-10-07 12:42:15 +02:00
48fb0cf91c add Persian to settings 2019-10-07 12:41:27 +02:00
8fcb05b0d2 Merge branch 'fixes' of mmarif/GitNex into master 2019-10-07 07:05:36 +00:00
074bbfe3cc Minor translation files fixes 2019-10-07 12:01:04 +05:00
84438b740a Merge branch '43-file-browser' of mmarif/GitNex into master 2019-10-07 06:32:42 +00:00
d4cd16a111 Merge branch 'master' into 43-file-browser 2019-10-07 11:26:24 +05:00
5ed053bba7 Merge branch 'crowdin-add-zh-CN' of mmarif/GitNex into master 2019-10-07 06:05:50 +00:00
598633a20a add first Chinese strings
@lunny thanks
2019-10-06 06:04:00 +02:00
8fe53dfd01 Settings: Languages: add Chinese and sort alphabetic 2019-10-06 06:01:48 +02:00
aadbcbd0c6 Merge branch 'crowdin-add-ar' into master 2019-10-04 19:25:53 +00:00
e3b901741a Add Untranslated Arabic 2019-10-04 20:56:29 +02:00
f8275cd7aa add Arabic to settings 2019-10-04 20:56:28 +02:00
c3afe1044c Merge branch 'crowdin' into master 2019-10-04 18:43:45 +00:00
a6503ba7c4 Crowdin Update 2019-10-04 20:26:20 +02:00
dddc9b0178 smal link fix for Translation 2019-10-04 20:24:44 +02:00
13bc50da40 git ignore crowdin config (crowdin.yml) 2019-10-04 20:23:43 +02:00
b32d291554 Merge branch 'translation-tool' of 6543/GitNex into master 2019-10-04 15:56:43 +00:00
c15e6e99f7 Added Arabic file 2019-10-04 20:46:56 +05:00
1512032f05 move corwdin Link to strings 2019-10-04 17:44:38 +02:00
e32ccde995 add info if lang is not listed 2019-10-04 16:55:09 +02:00
1be577cd3f add ClickListener to open Translation URL 2019-10-04 16:25:27 +02:00
7fa57621d9 change about layout 2019-10-04 16:20:46 +02:00
75ac6ff113 Add Crowdin Badge 2019-10-04 16:08:40 +02:00
9ef04b1287 change CONTRIBUTING.md for Crowdin 2019-10-04 16:08:17 +02:00
8c903b9658 remove some comments 2019-10-04 12:23:56 +05:00
08b8275546 translation files updates 2019-10-04 12:08:21 +05:00
5baacbd801 revert back 2019-10-04 00:21:34 +05:00
56b8b486df Merge branch 'release-2.1' into 43-file-browser 2019-10-04 00:06:03 +05:00
7abfdc9567 Merge branch 'fix-old-gitea-api' of mmarif/GitNex into release-2.1 2019-10-03 19:03:06 +00:00
0ab8784a7a another quick release and another old Gitea instances issue 2019-10-04 00:00:05 +05:00
e4ab2f64fc wip, need clean up 2019-10-03 23:50:57 +05:00
345d577fbf Merge branch 'release-2.1' into 43-file-browser 2019-10-03 21:53:38 +05:00
22b3802e73 Merge branch 'fixes-2.1.2' of mmarif/GitNex into release-2.1 2019-10-03 16:45:36 +00:00
07a1fa6aad Fix crashes on my repo, starred repos etc - 2.1.2 release 2019-10-03 21:43:33 +05:00
5c9b53f5ab api interface for sub dirs
Signed-off-by: M M Arif <mmarif@swatian.com>
2019-10-03 21:32:09 +05:00
572f93d35c Idea to use breadcrumb 2019-10-03 20:57:49 +05:00
a77716970b update gradle 2019-10-03 12:15:55 +05:00
4d998150a3 click listener checks for file, dir and unknwon files 2019-10-02 23:32:01 +05:00
90df3a31fe Merge branch 'release-2.1' into 43-file-browser 2019-10-02 22:47:46 +05:00
4904b5899f Merge branch 'fixes-2.1' of mmarif/GitNex into release-2.1 2019-10-02 17:26:30 +00:00
f19327431f fix bugs since 2.1.0 release 2019-10-02 22:24:02 +05:00
0bcbca8bdc Fix crash from gplay console, app crash when no avatar url node is present in API. old gitea instances. 2019-10-02 22:11:10 +05:00
b90b3c3320 Added reading file contentts 2019-10-02 21:32:59 +05:00
21097da995 filter files and dirs 2019-10-02 18:21:44 +05:00
06b71586c1 Sort by folder 1st approach 2019-10-02 17:58:29 +05:00
d2213c0c14 new file icon 2019-10-02 13:59:34 +05:00
4c3b735534 translation updates 2019-10-02 13:35:14 +05:00
90dce6fff8 added layout, view models, adapter and fragment 2019-10-02 13:30:07 +05:00
d9337a24d3 Fixes since 2.1.0 release, ms progress bar fix, create issue enable fix 2019-10-01 22:45:21 +05:00
45ec660ba1 Merge branch 'master' into 43-file-browser 2019-10-01 21:23:03 +05:00
8b26355fc0 Merge branch 'prepare-release' of mmarif/GitNex into master 2019-10-01 15:35:05 +00:00
8effad46f8 app release 2.1.0 2019-10-01 20:31:01 +05:00
bb24254e66 added files model 2019-10-01 20:07:37 +05:00
13e69cd09b files tab in repo tabs 2019-10-01 19:48:20 +05:00
71839bcfd6 clean up 2019-10-01 19:35:51 +05:00
53efd8b777 Merge branch '79-repo-avatar' of mmarif/GitNex into master 2019-10-01 13:59:59 +00:00
19cd5b6c5e added repos avatars 2019-10-01 18:56:20 +05:00
69082b424a Merge branch '54-enable-disable-create-issue' of mmarif/GitNex into master 2019-10-01 13:07:58 +00:00
d8b3477940 check if repo issues is enalbed or disabled 2019-10-01 18:05:09 +05:00
34892e7f43 Merge branch 'fix-ms-bar' of mmarif/GitNex into master 2019-10-01 10:26:03 +00:00
d64b035d4a fix ms progress bar 2019-10-01 15:23:49 +05:00
e2fa79b2a9 Merge branch 'master' of gitea.com:mmarif/GitNex 2019-10-01 15:06:46 +05:00
9e658aa38c 63-ms-ui (#82) 2019-10-01 10:05:26 +00:00
e4700ffd69 Merge branch 'master' of gitea.com:mmarif/GitNex 2019-10-01 11:44:45 +05:00
e53ef41fc1 ui-improvements (#81) 2019-10-01 06:42:56 +00:00
c05e69cfe9 t 2019-10-01 10:23:50 +05:00
5c6d5177fb r 2019-10-01 10:14:54 +05:00
62a5452437 Merge branch 'master' of gitea.com:mmarif/GitNex
# Conflicts:
#	app/src/main/java/org/mian/gitnex/activities/IssueDetailActivity.java
#	app/src/main/java/org/mian/gitnex/activities/MainActivity.java
#	app/src/main/java/org/mian/gitnex/adapters/AdminGetUsersAdapter.java
#	app/src/main/java/org/mian/gitnex/adapters/CollaboratorsAdapter.java
#	app/src/main/java/org/mian/gitnex/adapters/IssueCommentsAdapter.java
#	app/src/main/java/org/mian/gitnex/adapters/MembersByOrgAdapter.java
#	app/src/main/java/org/mian/gitnex/adapters/MyReposListAdapter.java
#	app/src/main/java/org/mian/gitnex/adapters/OrganizationsListAdapter.java
#	app/src/main/java/org/mian/gitnex/adapters/ProfileFollowersAdapter.java
#	app/src/main/java/org/mian/gitnex/adapters/ProfileFollowingAdapter.java
#	app/src/main/java/org/mian/gitnex/adapters/ReposListAdapter.java
#	app/src/main/java/org/mian/gitnex/adapters/RepositoriesByOrgAdapter.java
#	app/src/main/java/org/mian/gitnex/adapters/StarredReposListAdapter.java
#	app/src/main/java/org/mian/gitnex/adapters/TeamMembersByOrgAdapter.java
#	app/src/main/java/org/mian/gitnex/adapters/UserSearchAdapter.java
#	app/src/main/java/org/mian/gitnex/fragments/OrganizationInfoFragment.java
#	app/src/main/java/org/mian/gitnex/fragments/ProfileFragment.java
#	app/src/main/res/layout/activity_issue_detail.xml
#	app/src/main/res/layout/admin_users_list.xml
#	app/src/main/res/layout/fragment_profile.xml
#	app/src/main/res/layout/issue_comments.xml
#	app/src/main/res/layout/my_repos_list.xml
#	app/src/main/res/layout/nav_header.xml
#	app/src/main/res/layout/organizations_list.xml
#	app/src/main/res/layout/profile_followers_list.xml
#	app/src/main/res/layout/profile_following_list.xml
#	app/src/main/res/layout/repos_list.xml
#	app/src/main/res/layout/repositories_by_org_list.xml
#	app/src/main/res/layout/starred_repos_list.xml
2019-10-01 10:14:45 +05:00
5f402c2c60 merge 2019-10-01 10:12:18 +05:00
85140fbee0 Merge branch '77-ui-changes' of mmarif/GitNex into master 2019-09-30 18:16:24 +00:00
d350fe96d9 Merge branch 'master' into 77-ui-changes 2019-09-30 23:14:04 +05:00
61a1a4446f Merge branch '62-improve-issues-ui' of mmarif/GitNex into master 2019-09-30 18:09:47 +00:00
c1e27c9776 Merge branch 'issue-copy-nr' of 6543/GitNex into master 2019-09-30 18:07:25 +00:00
03ec591643 more ui changes 2019-09-30 22:48:52 +05:00
3ebc1ae3e0 avatars improvements 2019-09-30 22:39:33 +05:00
3c8fb5bc60 markdown code cleanup 2019-09-30 21:21:51 +05:00
5503fe9951 Redid the issues list ui and some clean up 2019-09-30 21:12:45 +05:00
7f417da6b3 update libs, switch to io.notis for md. refactor all the markdown code 2019-09-29 21:44:42 +05:00
4e8a961643 copyIssue -> copyIssueUrl 2019-09-29 00:56:48 +02:00
bf5527a82d issue -> issueUrl 2019-09-29 00:10:28 +02:00
c31cf53023 Merge branch 'milestoneProgress' of 6543/GitNex into master 2019-09-28 18:15:41 +00:00
0ac2a27549 all milestones look similar 2019-09-27 23:58:23 +02:00
dcabfa4f14 add Progress Bar function 2019-09-27 23:32:31 +02:00
9688c75106 add progress bar to layout 2019-09-27 22:52:29 +02:00
71bb8cc75d add copy function 2019-09-27 21:17:28 +02:00
dcd28e845a add Copy to Clipboard String 2019-09-27 19:12:19 +02:00
b3e88b0a9d add content copy icon 2019-09-27 18:50:05 +02:00
ce67f59753 Merge branch '67-filter-icon' of mmarif/GitNex into master 2019-09-26 19:09:16 +00:00
d0b6730de4 change search icon/text to filter 2019-09-26 23:58:36 +05:00
f5e18ed5cc Merge branch 'dl-apk-buton' of 6543/GitNex into master 2019-09-23 18:38:31 +00:00
88394e1c25 Merge branch 'translate_german' of IndeedNotJames/GitNex into master 2019-09-23 18:19:01 +00:00
a9030eb8c9 Bump requred Gitea Version 2019-09-22 18:05:54 +02:00
fff307d45a test look 2019-09-22 17:48:41 +02:00
b64ee37edd add release badge 2019-09-22 17:40:18 +02:00
b4b3c2f5ee add download apk sing from website 2019-09-22 16:49:07 +02:00
8f3ef29f44 complete german translation 2019-09-21 20:50:33 +02:00
d00691d71b Merge branch 'new-font-testing' of mmarif/GitNex into master 2019-09-19 06:35:28 +00:00
4867524b4f Merge branch 'master' into new-font-testing 2019-09-19 11:28:07 +05:00
a59e818aa2 Merge branch 'master' into new-font-testing 2019-09-19 11:27:09 +05:00
aeca4a0edb Merge branch 'fix-open-issue-tab' of mmarif/GitNex into master 2019-09-19 06:22:57 +00:00
2c60f092f1 Fix open issues tab color bug, dim color for info tab headers 2019-09-19 11:21:15 +05:00
fe0b3a77cc Merge branch 'minor-enhancements' of mmarif/GitNex into master 2019-09-19 05:38:26 +00:00
43c014948a Repo label and info tabs fixes 2019-09-19 10:36:55 +05:00
a497e0a284 new font 2019-09-19 10:10:12 +05:00
da268b017e Merge branch 'prepare-2-0-release' of mmarif/GitNex into master 2019-09-18 10:27:06 +00:00
4451adb01c prepare for release 2019-09-18 15:02:33 +05:00
0cd4e36a66 Merge branch '16-create-files' of mmarif/GitNex into master 2019-09-18 09:51:27 +00:00
742b1894e6 finished work on creating new file 2019-09-18 14:49:29 +05:00
8d1b47de8e wip on creating new file. still has to do branches section for old and new. 2019-09-18 13:25:49 +05:00
c38d249571 new file layout and bottomsheet link 2019-09-17 11:17:05 +05:00
c3da1900a0 add donator to sponsor page, file icon 2019-09-17 09:24:32 +05:00
b4c0745b40 reduce large links in branches and releases to small text with links.
Signed-off-by: M M Arif <mmarif@swatian.com>
2019-09-16 20:28:34 +05:00
e8e0cf904b Merge branch '37-fix-crash-within-tabs' of mmarif/GitNex into master 2019-09-14 09:43:54 +00:00
99718bc0c8 fix branches hash url 2019-09-14 14:40:47 +05:00
d4a5d5ee8c fix url linking for repo website 2019-09-14 13:22:01 +05:00
efffc05a89 fix crash on tabs, other ui fixes 2019-09-14 13:20:00 +05:00
a78018fd08 Merge branch '36-open-repo-in-browser' of mmarif/GitNex into master 2019-09-14 07:41:00 +00:00
33d1373f6e added open in browser 2019-09-14 12:38:41 +05:00
b15394e97d Add browser icon and xml element in menu 2019-09-14 12:26:20 +05:00
2bdeee5429 Merge branch '24-list-repo-watchers' of mmarif/GitNex into master 2019-09-14 06:55:22 +00:00
39c1ec36a7 Added repo watchers/subscribrs list 2019-09-14 11:29:20 +05:00
6866154714 Merge branch '25-list-repo-stargazers' of mmarif/GitNex into master 2019-09-13 16:03:29 +00:00
df260f05d2 added stargazers and other fixes and enhancements 2019-09-13 20:56:30 +05:00
d24e7ffc3b Add dotted menu 2019-09-13 12:21:52 +05:00
481451c791 Merge branch '23-fixes' of mmarif/GitNex into master 2019-09-12 08:32:00 +00:00
914d5cfa26 libs update, fixes search tap crashing. remove depricated classes 2019-09-12 13:30:07 +05:00
6710aa0810 clean up unwanted namespaces from layouts 2019-09-12 10:29:41 +05:00
87376a2104 Fix collaborator not found text 2019-09-12 10:21:53 +05:00
1ec7ac4f9f Merge branch 'open-repo-web' of 6543/GitNex into master 2019-09-11 06:26:58 +00:00
25f8277f0a translate missing with deepl 2019-09-10 19:56:54 +02:00
498bf7a72c spelling corection 2019-09-10 19:51:43 +02:00
20f687e30e add sugestions of mmarif
* delete OpenWebRepoActivity (function is handled in RepoDetailActivity )
 * add&handle case "openWebRepo" in RepoDetailActivity
 * add new Value "instanceUrlWithProtocol" to tinyDb
2019-09-10 19:48:44 +02:00
83e3564c13 try to implement OpenWebRepoActivity 2019-09-06 01:01:46 +02:00
7977aaa2be shorter text 2019-09-05 22:19:26 +02:00
6bc13ad4fe ues language icon also to indicate webbrowser open action 2019-09-05 22:06:23 +02:00
1f6f50977e Merge branch 'german-translation' of 6543/GitNex into master 2019-09-05 10:09:51 +00:00
1ce1278095 tiny lang. changes 2019-09-03 16:55:51 +02:00
ce63cde4ee add menue entry and strings 2019-09-03 16:46:38 +02:00
f23c4074f3 Merge branch 'master' of PsychotherapistSam/GitNex into master 2019-07-18 10:43:17 +00:00
ace9111225 Update 'app/src/main/res/values-de/strings.xml'
Updated some of the german translations :)
2019-07-18 03:44:16 +00:00
4aeeb95308 Merge branch 'fix-contribute-file' of mmarif/GitNex into master 2019-06-24 10:04:55 +00:00
056413e0b0 fix wordings 2019-06-24 02:33:30 +05:00
223 changed files with 9061 additions and 1918 deletions

31
.drone.yml Normal file
View File

@ -0,0 +1,31 @@
---
kind: pipeline
name: gitnex-ci-test
steps:
- name: test
image: nextcloudci/android:android-49
commands:
- ./gradlew test
trigger:
event:
- pull_request
---
kind: pipeline
name: gitnex-ci-build
steps:
- name: build
image: nextcloudci/android:android-49
commands:
- ./gradlew build
trigger:
event:
- push
branch:
- master

3
.gitignore vendored
View File

@ -180,6 +180,9 @@ crashlytics.properties
crashlytics-build.properties
fabric.properties
# Crowdin
crowdin.yml
### AndroidStudio Patch ###
!/gradle/wrapper/gradle-wrapper.jar

View File

@ -1,2 +1,2 @@
# Changelog
[Check out the release notes](https://gitea.com/mmarif/GitNex/releases)
[Check out the release notes](https://gitea.com/gitnex/GitNex/releases)

View File

@ -3,14 +3,14 @@
Please take a few minutes to read this document to make the process of contribution more easy and healthy for all involved.
## Pull Requests
Patches, enhancements, features are always welcome. The MR should focus on the scope of work and avoid many unnecessary commits. Please provide as much detail and context as possible to explain the work submitted.
Patches, enhancements, features are always welcome. The PR should focus on the scope of work and avoid many unnecessary commits. Please provide as much detail and context as possible to explain the work submitted.
Please ask if you are not sure about the scope of work to be submitted to avoid waste of time spent on the work.
**How to submit MR/PR**
**How to submit a PR**
Fork this repository. Pull the forked repository from your namespace to your local machine. Create new branch and work on the bug/feature/enhancement you would like to submit. Push it to your forked version. From there create Pull Request(PR) against **master** branch.
**IMPORTANT:** By submitting MR, you agree to allow GitNex to license your work under the same license as that used by GitNex.
**IMPORTANT:** By submitting PR, you agree to allow GitNex to license your work under the same license as that used by GitNex.
## Issues and Reports
*1st of please be polite and gentle while commenting or creating new issue to maintain a healthy environment.*
@ -20,10 +20,3 @@ Before creating an issue please take a moment and search the repository issues(o
In case you want to submit a bug report, please provide as much details as possible to better debug the problem. The important part is how to reproduce the bug and steps to reproduce are appreciated.
**Note:** Please contact the project directly via email(gitnex@swatian.com) if have to share sensitive and security related details.
## Translation
Help us translate GitNex to your native language.
Take a look [here](https://gitea.com/mmarif/GitNex/src/branch/master/app/src/main/res/values/strings.xml) for strings, please ignore the lines with `translatable="false"`. It is recommended to create a Pull Request with your changes.
Check the structure of other languages for example [French](https://gitea.com/mmarif/GitNex/src/branch/master/app/src/main/res/values-fr/strings.xml).

22
CONTRIBUTORS.md Normal file
View File

@ -0,0 +1,22 @@
# Contributors
This part lists all PUBLIC individuals having contributed content to the code.
* M M Arif (mmarif)
* 6543
# Translators
This part lists all PUBLIC individuals having contributed content to the translation.
*Entries are in alphabetical order*
* 6543
* ButterflyOfFire (BoFFire)
* IndeedNotJames
* Lunny Xiao (xiaolunwen)
* mmarif
* Nadezhda Moiseeva (digitalkiller)
* PsychotherapistSam
* Rodion Borisov (vintproykt)
* valeriezhao1013
* Voyvode
**Thank you for all your work** :+1:

View File

@ -1,6 +1,10 @@
[![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
[![Release](https://img.shields.io/badge/dynamic/json.svg?label=release&url=https://gitea.com/api/v1/repos/gitnex/GitNex/releases&query=$[0].tag_name)](https://gitea.com/gitnex/GitNex/releases)
[![Build Status](https://drone.gitea.com/api/badges/gitnex/GitNex/status.svg)](https://drone.gitea.com/gitnex/GitNex)
[![Crowdin](https://badges.crowdin.net/gitnex/localized.svg)](https://crowdin.com/project/gitnex)
[<img alt="Become a Patroen" src="https://c5.patreon.com/external/logo/become_a_patron_button@2x.png" height="40"/>](https://www.patreon.com/mmarif) [<img alt="Donate using Liberapay" src="https://liberapay.com/assets/widgets/donate.svg"/>](https://liberapay.com/mmarif/donate)
[<img alt="Become a Patroen" src="https://c5.patreon.com/external/logo/become_a_patron_button@2x.png" height="40"/>](https://www.patreon.com/mmarif)
[<img alt="Donate using Liberapay" src="https://liberapay.com/assets/widgets/donate.svg" height="40"/>](https://liberapay.com/mmarif/donate)
# GitNex - Android client for Gitea
@ -10,12 +14,14 @@ GitNex is licensed under GPLv3 License. See the LICENSE file for the full licens
No trackers are used and source code is available here for anyone to audit.
## Downloads
[<img alt='Get it on F-droid' src='https://gitlab.com/fdroid/artwork/raw/master/badge/get-it-on.png' height="80"/>](https://f-droid.org/en/packages/org.mian.gitnex/) [<img alt='Get it on Google Play' src='https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png' height="80"/>](https://play.google.com/store/apps/details?id=org.mian.gitnex) [Download APK](https://gitea.com/mmarif/GitNex/releases)
[<img alt='Get it on F-droid' src='https://gitlab.com/fdroid/artwork/raw/master/badge/get-it-on.png' height="80"/>](https://f-droid.org/en/packages/org.mian.gitnex/)
[<img alt='Get it on Google Play' src='https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png' height="80"/>](https://play.google.com/store/apps/details?id=org.mian.gitnex)
[<img alt='Download APK' src='https://gitnex.com/img/download-apk.png' height="80"/>](https://gitea.com/gitnex/GitNex/releases)
## Note about Gitea version
Please make sure that you are on Gitea **1.7.x** stable release or later. Below this may not work as one would expect because of the newly added objects to the API at later versions. Please consider updating your Gitea server.
Please make sure that you are on Gitea **1.9.x** stable release or later. Below this may not work as one would expect because of the newly added objects to the API at later versions. Please consider updating your Gitea server.
Check the versions [compatibility page](https://gitea.com/mmarif/GitNex/wiki/Compatibility) which lists all the supported versions with compatibility ratio.
Check the versions [compatibility page](https://gitea.com/gitnex/GitNex/wiki/Compatibility) which lists all the supported versions with compatibility ratio.
## Build from source
Option 1 - Download the source code, open it in Android Studio and build it there.
@ -29,25 +35,37 @@ Option 2 - Open terminal(Linux) and cd to the project dir. Run `./gradlew build`
- Create repository
- Create organization
- Issues list
- [MANY MORE](https://gitea.com/mmarif/GitNex/wiki/Features)
- [MANY MORE](https://gitea.com/gitnex/GitNex/wiki/Features)
## Contributing
[CONTRIBUTING](https://gitea.com/mmarif/GitNex/src/branch/master/CONTRIBUTING.md)
[CONTRIBUTING](https://gitea.com/gitnex/GitNex/src/branch/master/CONTRIBUTING.md)
## Translation
Help us translate GitNex to your native language.
We use [Crowdin](https://crowdin.com/project/gitnex) for translation.
If your language is not listed, please request [here](https://gitea.com/gitnex/GitNex/issues) to add it to the project.
**Link: https://crowdin.com/project/GitNex**
## Screenshots:
[Screenshots](https://gitea.com/mmarif/GitNex/src/branch/master/fastlane/metadata/android/en-US/images/phoneScreenshots)
<img src="https://gitea.com/gitnex/GitNex/raw/branch/master/fastlane/metadata/android/en-US/images/phoneScreenshots/001.png" alt="001.png" width="200"/> | <img src="https://gitea.com/gitnex/GitNex/raw/branch/master/fastlane/metadata/android/en-US/images/phoneScreenshots/002.png" alt="002.png" width="200"/> | <img src="https://gitea.com/gitnex/GitNex/raw/branch/master/fastlane/metadata/android/en-US/images/phoneScreenshots/003.png" alt="003.png" width="200"/> | <img src="https://gitea.com/gitnex/GitNex/raw/branch/master/fastlane/metadata/android/en-US/images/phoneScreenshots/004.png" alt="004.png" width="200"/>
---|---|---|---
<img src="https://gitea.com/gitnex/GitNex/raw/branch/master/fastlane/metadata/android/en-US/images/phoneScreenshots/005.png" alt="005.png" width="200"/> | <img src="https://gitea.com/gitnex/GitNex/raw/branch/master/fastlane/metadata/android/en-US/images/phoneScreenshots/006.png" alt="006.png" width="200"/> | <img src="https://gitea.com/gitnex/GitNex/raw/branch/master/fastlane/metadata/android/en-US/images/phoneScreenshots/007.png" alt="007.png" width="200"/> | <img src="https://gitea.com/gitnex/GitNex/raw/branch/master/fastlane/metadata/android/en-US/images/phoneScreenshots/008.png" alt="008.png" width="200"/>
## FAQ
[Faq](https://gitea.com/mmarif/GitNex/wiki/FAQ)
[Faq](https://gitea.com/gitnex/GitNex/wiki/FAQ)
## Links
[Website](https://gitnex.com)
[Wiki](https://gitea.com/mmarif/GitNex/wiki/Home)
[Wiki](https://gitea.com/gitnex/GitNex/wiki/Home)
[Website Repository](https://gitlab.com/mmarif4u/gitnex-website)
[Troubleshoot Guide](https://gitea.com/mmarif/GitNex/wiki/Troubleshoot-Guide)
[Troubleshoot Guide](https://gitea.com/gitnex/GitNex/wiki/Troubleshoot-Guide)
## Thanks
Thanks to all the open source libraries, contributors and donators.
@ -65,5 +83,6 @@ Open source libraries
- Abumoallim/android-multi-select-dialog
- Pes/materialcolorpicker
- Hendraanggrian/socialview
- Fython/BreadcrumbsView
[Follow me on Fediverse - mastodon.social/@mmarif](https://mastodon.social/@mmarif)

View File

@ -6,8 +6,8 @@ android {
applicationId "org.mian.gitnex"
minSdkVersion 21
targetSdkVersion 28
versionCode 45
versionName "1.5.0"
versionCode 72
versionName "2.2.2"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
@ -23,12 +23,12 @@ android {
}
dependencies {
def lifecycle_version = "2.2.0-alpha01"
final def markwon_version = "3.0.0"
def lifecycle_version = "2.2.0-beta01"
final def markwon_version = "4.1.1"
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'androidx.appcompat:appcompat:1.1.0-beta01'
implementation 'com.google.android.material:material:1.1.0-alpha07'
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'com.google.android.material:material:1.1.0-beta01'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
testImplementation 'junit:junit:4.12'
@ -47,21 +47,27 @@ dependencies {
implementation "com.vdurmont:emoji-java:4.0.0"
implementation "com.pes.materialcolorpicker:library:1.2.5"
implementation "ru.noties.markwon:core:$markwon_version"
implementation "ru.noties.markwon:ext-strikethrough:$markwon_version"
implementation "ru.noties.markwon:ext-tables:$markwon_version"
implementation "ru.noties.markwon:ext-tasklist:$markwon_version"
implementation "ru.noties.markwon:syntax-highlight:$markwon_version"
implementation "ru.noties.markwon:image-okhttp:$markwon_version"
implementation "ru.noties.markwon:html:$markwon_version"
implementation "ru.noties.markwon:recycler:$markwon_version"
implementation "ru.noties.markwon:recycler-table:$markwon_version"
implementation "ru.noties.markwon:image-gif:$markwon_version"
implementation "ru.noties.markwon:image-svg:$markwon_version"
implementation "io.noties.markwon:core:$markwon_version"
implementation "io.noties.markwon:ext-latex:$markwon_version"
implementation "io.noties.markwon:ext-strikethrough:$markwon_version"
implementation "io.noties.markwon:ext-tables:$markwon_version"
implementation "io.noties.markwon:ext-tasklist:$markwon_version"
implementation "io.noties.markwon:html:$markwon_version"
implementation "io.noties.markwon:image:$markwon_version"
implementation "io.noties.markwon:image-picasso:$markwon_version"
implementation "io.noties.markwon:linkify:$markwon_version"
implementation "io.noties.markwon:recycler:$markwon_version"
implementation "io.noties.markwon:recycler-table:$markwon_version"
implementation "io.noties.markwon:simple-ext:$markwon_version"
implementation "io.noties.markwon:syntax-highlight:$markwon_version"
implementation "com.caverock:androidsvg:1.4"
implementation "pl.droidsonroids.gif:android-gif-drawable:1.2.14"
implementation "com.hendraanggrian.appcompat:socialview:0.2"
implementation "com.hendraanggrian.appcompat:socialview-commons:0.2"
implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-viewmodel:$lifecycle_version"
implementation "com.github.HamidrezaAmz:BreadcrumbsView:0.2.9"
}

View File

@ -2,9 +2,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.mian.gitnex">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:allowBackup="true"
android:icon="@mipmap/app_logo"
@ -13,7 +10,19 @@
android:roundIcon="@mipmap/app_logo_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".activities.AdminGetUsersActivity"></activity>
<activity
android:name=".activities.FileViewActivity"
android:theme="@style/AppTheme.NoActionBar"></activity>
<activity
android:name=".activities.NewFileActivity"
android:theme="@style/AppTheme.NoActionBar" />
<activity
android:name=".activities.RepoWatchersActivity"
android:theme="@style/AppTheme.NoActionBar" />
<activity
android:name=".activities.RepoStargazersActivity"
android:theme="@style/AppTheme.NoActionBar" />
<activity android:name=".activities.AdminGetUsersActivity" />
<activity
android:name=".activities.AddRemoveAssigneesActivity"
android:theme="@style/Theme.AppCompat.Light.Dialog" />
@ -56,6 +65,10 @@
android:launchMode="singleTask" />
<activity android:name=".activities.NewRepoActivity" />
<activity android:name=".activities.NewOrganizationActivity" />
<activity android:name=".activities.OpenRepoInBrowserActivity" />
</application>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
</manifest>

View File

@ -0,0 +1,280 @@
package org.mian.gitnex.actions;
import android.content.Context;
import android.util.Log;
import androidx.annotation.NonNull;
import com.google.gson.JsonElement;
import org.mian.gitnex.R;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.helpers.AlertDialogs;
import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.util.TinyDB;
import retrofit2.Call;
import retrofit2.Callback;
/**
* Author M M Arif
*/
public class RepositoryActions {
public static void starRepository(final Context context) {
final TinyDB tinyDb = new TinyDB(context);
final String instanceUrl = tinyDb.getString("instanceUrl");
final String loginUid = tinyDb.getString("loginUid");
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
String repoFullName = tinyDb.getString("repoFullName");
String[] parts = repoFullName.split("/");
final String repoOwner = parts[0];
final String repoName = parts[1];
Call<JsonElement> call;
call = RetrofitClient
.getInstance(instanceUrl)
.getApiInterface()
.starRepository(Authorization.returnAuthentication(context, loginUid, instanceToken), repoOwner, repoName);
call.enqueue(new Callback<JsonElement>() {
@Override
public void onResponse(@NonNull Call<JsonElement> call, @NonNull retrofit2.Response<JsonElement> response) {
if(response.isSuccessful()) {
if(response.code() == 204) {
tinyDb.putBoolean("repoCreated", true);
Toasty.info(context, context.getString(R.string.starRepositorySuccess));
}
}
else if(response.code() == 401) {
AlertDialogs.authorizationTokenRevokedDialog(context, context.getResources().getString(R.string.alertDialogTokenRevokedTitle),
context.getResources().getString(R.string.alertDialogTokenRevokedMessage),
context.getResources().getString(R.string.alertDialogTokenRevokedCopyNegativeButton),
context.getResources().getString(R.string.alertDialogTokenRevokedCopyPositiveButton));
}
else if(response.code() == 403) {
Toasty.info(context, context.getString(R.string.authorizeError));
}
else if(response.code() == 404) {
Toasty.info(context, context.getString(R.string.apiNotFound));
}
else {
Toasty.info(context, context.getString(R.string.genericError));
}
}
@Override
public void onFailure(@NonNull Call<JsonElement> call, @NonNull Throwable t) {
Log.e("onFailure", t.toString());
}
});
}
public static void unStarRepository(final Context context) {
final TinyDB tinyDb = new TinyDB(context);
final String instanceUrl = tinyDb.getString("instanceUrl");
final String loginUid = tinyDb.getString("loginUid");
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
String repoFullName = tinyDb.getString("repoFullName");
String[] parts = repoFullName.split("/");
final String repoOwner = parts[0];
final String repoName = parts[1];
Call<JsonElement> call;
call = RetrofitClient
.getInstance(instanceUrl)
.getApiInterface()
.unStarRepository(Authorization.returnAuthentication(context, loginUid, instanceToken), repoOwner, repoName);
call.enqueue(new Callback<JsonElement>() {
@Override
public void onResponse(@NonNull Call<JsonElement> call, @NonNull retrofit2.Response<JsonElement> response) {
if(response.isSuccessful()) {
if(response.code() == 204) {
tinyDb.putBoolean("repoCreated", true);
Toasty.info(context, context.getString(R.string.unStarRepositorySuccess));
}
}
else if(response.code() == 401) {
AlertDialogs.authorizationTokenRevokedDialog(context, context.getResources().getString(R.string.alertDialogTokenRevokedTitle),
context.getResources().getString(R.string.alertDialogTokenRevokedMessage),
context.getResources().getString(R.string.alertDialogTokenRevokedCopyNegativeButton),
context.getResources().getString(R.string.alertDialogTokenRevokedCopyPositiveButton));
}
else if(response.code() == 403) {
Toasty.info(context, context.getString(R.string.authorizeError));
}
else if(response.code() == 404) {
Toasty.info(context, context.getString(R.string.apiNotFound));
}
else {
Toasty.info(context, context.getString(R.string.genericError));
}
}
@Override
public void onFailure(@NonNull Call<JsonElement> call, @NonNull Throwable t) {
Log.e("onFailure", t.toString());
}
});
}
public static void watchRepository(final Context context) {
final TinyDB tinyDb = new TinyDB(context);
final String instanceUrl = tinyDb.getString("instanceUrl");
final String loginUid = tinyDb.getString("loginUid");
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
String repoFullName = tinyDb.getString("repoFullName");
String[] parts = repoFullName.split("/");
final String repoOwner = parts[0];
final String repoName = parts[1];
Call<JsonElement> call;
call = RetrofitClient
.getInstance(instanceUrl)
.getApiInterface()
.watchRepository(Authorization.returnAuthentication(context, loginUid, instanceToken), repoOwner, repoName);
call.enqueue(new Callback<JsonElement>() {
@Override
public void onResponse(@NonNull Call<JsonElement> call, @NonNull retrofit2.Response<JsonElement> response) {
if(response.isSuccessful()) {
if(response.code() == 200) {
tinyDb.putBoolean("repoCreated", true);
Toasty.info(context, context.getString(R.string.watchRepositorySuccess));
}
}
else if(response.code() == 401) {
AlertDialogs.authorizationTokenRevokedDialog(context, context.getResources().getString(R.string.alertDialogTokenRevokedTitle),
context.getResources().getString(R.string.alertDialogTokenRevokedMessage),
context.getResources().getString(R.string.alertDialogTokenRevokedCopyNegativeButton),
context.getResources().getString(R.string.alertDialogTokenRevokedCopyPositiveButton));
}
else if(response.code() == 403) {
Toasty.info(context, context.getString(R.string.authorizeError));
}
else if(response.code() == 404) {
Toasty.info(context, context.getString(R.string.apiNotFound));
}
else {
Toasty.info(context, context.getString(R.string.genericError));
}
}
@Override
public void onFailure(@NonNull Call<JsonElement> call, @NonNull Throwable t) {
Log.e("onFailure", t.toString());
}
});
}
public static void unWatchRepository(final Context context) {
final TinyDB tinyDb = new TinyDB(context);
final String instanceUrl = tinyDb.getString("instanceUrl");
final String loginUid = tinyDb.getString("loginUid");
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
String repoFullName = tinyDb.getString("repoFullName");
String[] parts = repoFullName.split("/");
final String repoOwner = parts[0];
final String repoName = parts[1];
Call<JsonElement> call;
call = RetrofitClient
.getInstance(instanceUrl)
.getApiInterface()
.unWatchRepository(Authorization.returnAuthentication(context, loginUid, instanceToken), repoOwner, repoName);
call.enqueue(new Callback<JsonElement>() {
@Override
public void onResponse(@NonNull Call<JsonElement> call, @NonNull retrofit2.Response<JsonElement> response) {
if(response.code() == 204) {
tinyDb.putBoolean("repoCreated", true);
Toasty.info(context, context.getString(R.string.unWatchRepositorySuccess));
}
else if(response.code() == 401) {
AlertDialogs.authorizationTokenRevokedDialog(context, context.getResources().getString(R.string.alertDialogTokenRevokedTitle),
context.getResources().getString(R.string.alertDialogTokenRevokedMessage),
context.getResources().getString(R.string.alertDialogTokenRevokedCopyNegativeButton),
context.getResources().getString(R.string.alertDialogTokenRevokedCopyPositiveButton));
}
else if(response.code() == 403) {
Toasty.info(context, context.getString(R.string.authorizeError));
}
else if(response.code() == 404) {
Toasty.info(context, context.getString(R.string.apiNotFound));
}
else {
Toasty.info(context, context.getString(R.string.genericError));
}
}
@Override
public void onFailure(@NonNull Call<JsonElement> call, @NonNull Throwable t) {
Log.e("onFailure", t.toString());
}
});
}
}

View File

@ -323,10 +323,11 @@ public class CreateIssueActivity extends AppCompatActivity implements View.OnCli
private void getMilestones(String instanceUrl, String instanceToken, String repoOwner, String repoName, String loginUid) {
String msState = "open";
Call<List<Milestones>> call = RetrofitClient
.getInstance(instanceUrl)
.getApiInterface()
.getMilestones(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName);
.getMilestones(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName, msState);
call.enqueue(new Callback<List<Milestones>>() {

View File

@ -56,6 +56,8 @@ public class EditIssueActivity extends AppCompatActivity implements View.OnClick
private Button editIssueButton;
private Spinner editIssueMilestoneSpinner;
private String msState = "open";
List<Milestones> milestonesList = new ArrayList<>();
private ArrayAdapter<Mention> defaultMentionAdapter;
@ -331,7 +333,7 @@ public class EditIssueActivity extends AppCompatActivity implements View.OnClick
Call<List<Milestones>> call_ = RetrofitClient
.getInstance(instanceUrl)
.getApiInterface()
.getMilestones(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName);
.getMilestones(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName, msState);
final int finalMsId = msId;

View File

@ -0,0 +1,149 @@
package org.mian.gitnex.activities;
import android.content.Context;
import android.os.Bundle;
import android.text.method.ScrollingMovementMethod;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import org.mian.gitnex.R;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.helpers.AlertDialogs;
import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.models.Files;
import org.mian.gitnex.util.AppUtil;
import org.mian.gitnex.util.TinyDB;
import retrofit2.Call;
import retrofit2.Callback;
/**
* Author M M Arif
*/
public class FileViewActivity extends AppCompatActivity {
private View.OnClickListener onClickListener;
private TextView singleFileContents;
final Context ctx = this;
private ProgressBar mProgressBar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_file_view);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
final TinyDB tinyDb = new TinyDB(getApplicationContext());
String repoFullName = tinyDb.getString("repoFullName");
String[] parts = repoFullName.split("/");
final String repoOwner = parts[0];
final String repoName = parts[1];
final String instanceUrl = tinyDb.getString("instanceUrl");
final String loginUid = tinyDb.getString("loginUid");
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
boolean connToInternet = AppUtil.haveNetworkConnection(getApplicationContext());
ImageView closeActivity = findViewById(R.id.close);
singleFileContents = findViewById(R.id.singleFileContents);
singleFileContents.setVisibility(View.GONE);
mProgressBar = findViewById(R.id.progress_bar);
String singleFileName = getIntent().getStringExtra("singleFileName");
TextView toolbar_title = findViewById(R.id.toolbar_title);
toolbar_title.setMovementMethod(new ScrollingMovementMethod());
toolbar_title.setText(singleFileName);
initCloseListener();
closeActivity.setOnClickListener(onClickListener);
if(connToInternet) {
getSingleFileContents(instanceUrl, instanceToken, repoOwner, repoName, singleFileName);
}
else {
Toasty.info(getApplicationContext(), getString(R.string.checkNetConnection));
}
}
private void getSingleFileContents(String instanceUrl, String token, final String owner, String repo, final String filename) {
Call<Files> call = RetrofitClient
.getInstance(instanceUrl)
.getApiInterface()
.getSingleFileContents(token, owner, repo, filename);
call.enqueue(new Callback<Files>() {
@Override
public void onResponse(@NonNull Call<Files> call, @NonNull retrofit2.Response<Files> response) {
if (response.code() == 200) {
AppUtil appUtil = new AppUtil();
assert response.body() != null;
if(!response.body().getContent().equals("")) {
singleFileContents.setVisibility(View.VISIBLE);
mProgressBar.setVisibility(View.GONE);
singleFileContents.setText(appUtil.decodeBase64(response.body().getContent()));
}
else {
singleFileContents.setText("");
mProgressBar.setVisibility(View.GONE);
}
}
else if(response.code() == 401) {
AlertDialogs.authorizationTokenRevokedDialog(ctx, getResources().getString(R.string.alertDialogTokenRevokedTitle),
getResources().getString(R.string.alertDialogTokenRevokedMessage),
getResources().getString(R.string.alertDialogTokenRevokedCopyNegativeButton),
getResources().getString(R.string.alertDialogTokenRevokedCopyPositiveButton));
}
else if(response.code() == 403) {
Toasty.info(ctx, ctx.getString(R.string.authorizeError));
}
else if(response.code() == 404) {
Toasty.info(ctx, ctx.getString(R.string.apiNotFound));
}
else {
Toasty.info(getApplicationContext(), getString(R.string.labelGeneralError));
}
}
@Override
public void onFailure(@NonNull Call<Files> call, @NonNull Throwable t) {
Log.e("onFailure", t.toString());
}
});
}
private void initCloseListener() {
onClickListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
getIntent().removeExtra("singleFileName");
finish();
}
};
}
}

View File

@ -10,26 +10,33 @@ import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import okhttp3.OkHttpClient;
import io.noties.markwon.AbstractMarkwonPlugin;
import io.noties.markwon.Markwon;
import io.noties.markwon.core.CorePlugin;
import io.noties.markwon.core.MarkwonTheme;
import io.noties.markwon.ext.strikethrough.StrikethroughPlugin;
import io.noties.markwon.ext.tables.TablePlugin;
import io.noties.markwon.ext.tasklist.TaskListPlugin;
import io.noties.markwon.html.HtmlPlugin;
import io.noties.markwon.image.AsyncDrawable;
import io.noties.markwon.image.DefaultMediaDecoder;
import io.noties.markwon.image.ImageItem;
import io.noties.markwon.image.ImagesPlugin;
import io.noties.markwon.image.SchemeHandler;
import io.noties.markwon.image.gif.GifMediaDecoder;
import io.noties.markwon.image.svg.SvgMediaDecoder;
import io.noties.markwon.linkify.LinkifyPlugin;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import ru.noties.markwon.AbstractMarkwonPlugin;
import ru.noties.markwon.Markwon;
import ru.noties.markwon.core.CorePlugin;
import ru.noties.markwon.core.MarkwonTheme;
import ru.noties.markwon.ext.strikethrough.StrikethroughPlugin;
import ru.noties.markwon.ext.tables.TablePlugin;
import ru.noties.markwon.ext.tasklist.TaskListPlugin;
import ru.noties.markwon.html.HtmlPlugin;
import ru.noties.markwon.image.ImagesPlugin;
import ru.noties.markwon.image.gif.GifPlugin;
import ru.noties.markwon.image.okhttp.OkHttpImagesPlugin;
import android.content.Context;
import android.graphics.Color;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.text.Spanned;
import android.util.Log;
import android.view.Gravity;
import android.view.Menu;
@ -63,6 +70,8 @@ import org.mian.gitnex.viewmodels.IssueCommentsViewModel;
import org.ocpsoft.prettytime.PrettyTime;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
@ -286,22 +295,60 @@ public class IssueDetailActivity extends AppCompatActivity {
final Markwon markwon = Markwon.builder(Objects.requireNonNull(getApplicationContext()))
.usePlugin(CorePlugin.create())
.usePlugin(OkHttpImagesPlugin.create(new OkHttpClient()))
.usePlugin(ImagesPlugin.createWithAssets(getApplicationContext()))
.usePlugin(ImagesPlugin.create(new ImagesPlugin.ImagesConfigure() {
@Override
public void configureImages(@NonNull ImagesPlugin plugin) {
plugin.addSchemeHandler(new SchemeHandler() {
@NonNull
@Override
public ImageItem handle(@NonNull String raw, @NonNull Uri uri) {
final int resourceId = getApplicationContext().getResources().getIdentifier(
raw.substring("drawable://".length()),
"drawable",
getApplicationContext().getPackageName());
final Drawable drawable = getApplicationContext().getDrawable(resourceId);
assert drawable != null;
return ImageItem.withResult(drawable);
}
@NonNull
@Override
public Collection<String> supportedSchemes() {
return Collections.singleton("drawable");
}
});
plugin.placeholderProvider(new ImagesPlugin.PlaceholderProvider() {
@Nullable
@Override
public Drawable providePlaceholder(@NonNull AsyncDrawable drawable) {
return null;
}
});
plugin.addMediaDecoder(GifMediaDecoder.create(false));
plugin.addMediaDecoder(SvgMediaDecoder.create(getApplicationContext().getResources()));
plugin.addMediaDecoder(SvgMediaDecoder.create());
plugin.defaultMediaDecoder(DefaultMediaDecoder.create(getApplicationContext().getResources()));
plugin.defaultMediaDecoder(DefaultMediaDecoder.create());
}
}))
.usePlugin(new AbstractMarkwonPlugin() {
@Override
public void configureTheme(@NonNull MarkwonTheme.Builder builder) {
builder
.codeTextColor(tinyDb.getInt("codeBlockColor"))
.codeBackgroundColor(tinyDb.getInt("codeBlockBackground"))
.linkColor(getApplicationContext().getResources().getColor(R.color.lightBlue));
.linkColor(getResources().getColor(R.color.lightBlue));
}
})
.usePlugin(TablePlugin.create(getApplicationContext()))
.usePlugin(TaskListPlugin.create(getApplicationContext()))
.usePlugin(HtmlPlugin.create())
.usePlugin(GifPlugin.create())
.usePlugin(StrikethroughPlugin.create())
.usePlugin(LinkifyPlugin.create())
.build();
TinyDB tinyDb = new TinyDB(getApplicationContext());
@ -310,11 +357,11 @@ public class IssueDetailActivity extends AppCompatActivity {
tinyDb.putString("issueState", singleIssue.getState());
tinyDb.putString("issueTitle", singleIssue.getTitle());
Picasso.get().load(singleIssue.getUser().getAvatar_url()).transform(new RoundedTransformation(100, 0)).resize(200, 200).centerCrop().into(assigneeAvatar);
Picasso.get().load(singleIssue.getUser().getAvatar_url()).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(assigneeAvatar);
issueTitle.setText(getString(R.string.issueTitleWithId, singleIssue.getNumber(), singleIssue.getTitle()));
String cleanIssueDescription = singleIssue.getBody().trim();
final CharSequence bodyWithMD = markwon.toMarkdown(EmojiParser.parseToUnicode(cleanIssueDescription));
issueDescription.setText(UserMentions.UserMentionsFunc(getApplicationContext(), bodyWithMD, cleanIssueDescription));
Spanned bodyWithMD = markwon.toMarkdown(EmojiParser.parseToUnicode(cleanIssueDescription));
markwon.setParsedMarkdown(issueDescription, UserMentions.UserMentionsFunc(getApplicationContext(), bodyWithMD, cleanIssueDescription));
RelativeLayout.LayoutParams paramsDesc = (RelativeLayout.LayoutParams)issueDescription.getLayoutParams();
@ -327,7 +374,7 @@ public class IssueDetailActivity extends AppCompatActivity {
ImageView assigneesView = new ImageView(getApplicationContext());
Picasso.get().load(singleIssue.getAssignees().get(i).getAvatar_url()).transform(new RoundedTransformation(100, 0)).resize(80, 80).centerCrop().into(assigneesView);
Picasso.get().load(singleIssue.getAssignees().get(i).getAvatar_url()).transform(new RoundedTransformation(8, 0)).resize(100, 100).centerCrop().into(assigneesView);
assigneesLayout.addView(assigneesView);
assigneesView.setLayoutParams(params1);
@ -431,7 +478,7 @@ public class IssueDetailActivity extends AppCompatActivity {
case "pretty": {
PrettyTime prettyTime = new PrettyTime(new Locale(locale));
String createdTime = prettyTime.format(singleIssue.getCreated_at());
issueCreatedTime.setText(getString(R.string.createdTime, createdTime));
issueCreatedTime.setText(createdTime);
issueCreatedTime.setVisibility(View.VISIBLE);
issueCreatedTime.setOnClickListener(new ClickListener(TimeHelper.customDateFormatForToastDateFormat(singleIssue.getCreated_at()), getApplicationContext()));
break;
@ -439,14 +486,14 @@ public class IssueDetailActivity extends AppCompatActivity {
case "normal": {
DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd '" + getResources().getString(R.string.timeAtText) + "' HH:mm", new Locale(locale));
String createdTime = formatter.format(singleIssue.getCreated_at());
issueCreatedTime.setText(getString(R.string.createdTime, createdTime));
issueCreatedTime.setText(createdTime);
issueCreatedTime.setVisibility(View.VISIBLE);
break;
}
case "normal1": {
DateFormat formatter = new SimpleDateFormat("dd-MM-yyyy '" + getResources().getString(R.string.timeAtText) + "' HH:mm", new Locale(locale));
String createdTime = formatter.format(singleIssue.getCreated_at());
issueCreatedTime.setText(getString(R.string.createdTime, createdTime));
issueCreatedTime.setText(createdTime);
issueCreatedTime.setVisibility(View.VISIBLE);
break;
}

View File

@ -194,16 +194,20 @@ public class LoginActivity extends AppCompatActivity implements View.OnClickList
instanceHost = instanceUrl;
}
String instanceUrlWithProtocol;
if(protocol.toLowerCase().equals("https")) {
instanceUrl = "https://" + instanceHost + "/api/v1/";
instanceUrlWithProtocol = "https://" + instanceHost;
}
else {
instanceUrl = "http://" + instanceHost + "/api/v1/";
instanceUrlWithProtocol = "https://" + instanceHost;
}
tinyDb.putString("instanceUrlRaw", instanceHost);
tinyDb.putString("loginUid", loginUid);
tinyDb.putString("instanceUrl", instanceUrl);
tinyDb.putString("instanceUrlWithProtocol", instanceUrlWithProtocol);
if(connToInternet) {

View File

@ -21,6 +21,7 @@ import com.squareup.picasso.Picasso;
import org.mian.gitnex.R;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.fragments.AboutFragment;
import org.mian.gitnex.fragments.ExploreRepositoriesFragment;
import org.mian.gitnex.fragments.MyRepositoriesFragment;
import org.mian.gitnex.fragments.NavSubMenuBottomSheetFragment;
import org.mian.gitnex.fragments.OrganizationsFragment;
@ -148,7 +149,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
userAvatar = hView.findViewById(R.id.userAvatar);
if (!userAvatarNav.equals("")) {
Picasso.get().load(userAvatarNav).networkPolicy(NetworkPolicy.OFFLINE).transform(new RoundedTransformation(100, 0)).resize(180, 180).centerCrop().into(userAvatar);
Picasso.get().load(userAvatarNav).networkPolicy(NetworkPolicy.OFFLINE).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(userAvatar);
}
} else {
@ -278,6 +279,11 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
new StarredRepositoriesFragment()).commit();
break;
case R.id.nav_explore:
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
new ExploreRepositoriesFragment()).commit();
break;
}
drawer.closeDrawer(GravityCompat.START);
@ -330,6 +336,9 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
if (response.code() == 200) {
assert userDetails != null;
if(userDetails.getIs_admin() != null) {
tinyDb.putBoolean("userIsAdmin", userDetails.getIs_admin());
}
tinyDb.putString("userLogin", userDetails.getLogin());
tinyDb.putInt("userId", userDetails.getId());
if(!userDetails.getFullname().equals("")) {
@ -351,9 +360,9 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
userAvatar = hView.findViewById(R.id.userAvatar);
if (!Objects.requireNonNull(userDetails).getAvatar().equals("")) {
Picasso.get().load(userDetails.getAvatar()).transform(new RoundedTransformation(100, 0)).resize(180, 180).centerCrop().into(userAvatar);
Picasso.get().load(userDetails.getAvatar()).transform(new RoundedTransformation(8, 0)).resize(160, 160).centerCrop().into(userAvatar);
} else {
userAvatar.setImageResource(R.mipmap.ic_launcher_round);
userAvatar.setImageResource(R.mipmap.app_logo_round);
}
userFullName = hView.findViewById(R.id.userFullname);

View File

@ -0,0 +1,335 @@
package org.mian.gitnex.activities;
import android.content.Context;
import android.graphics.PorterDuff;
import android.graphics.drawable.GradientDrawable;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.Spinner;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import com.google.gson.JsonElement;
import org.mian.gitnex.R;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.helpers.AlertDialogs;
import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.models.Branches;
import org.mian.gitnex.models.NewFile;
import org.mian.gitnex.util.AppUtil;
import org.mian.gitnex.util.TinyDB;
import java.util.ArrayList;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
/**
* Author M M Arif
*/
public class NewFileActivity extends AppCompatActivity {
public ImageView closeActivity;
private View.OnClickListener onClickListener;
private Button newFileCreate;
private EditText newFileName;
private EditText newFileContent;
private EditText newFileBranchName;
private EditText newFileCommitMessage;
private Spinner newFileBranchesSpinner;
final Context ctx = this;
List<Branches> branchesList = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_new_file);
boolean connToInternet = AppUtil.haveNetworkConnection(getApplicationContext());
TinyDB tinyDb = new TinyDB(getApplicationContext());
final String instanceUrl = tinyDb.getString("instanceUrl");
final String loginUid = tinyDb.getString("loginUid");
String repoFullName = tinyDb.getString("repoFullName");
String[] parts = repoFullName.split("/");
final String repoOwner = parts[0];
final String repoName = parts[1];
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
closeActivity = findViewById(R.id.close);
newFileName = findViewById(R.id.newFileName);
newFileContent = findViewById(R.id.newFileContent);
newFileBranchName = findViewById(R.id.newFileBranchName);
newFileCommitMessage = findViewById(R.id.newFileCommitMessage);
initCloseListener();
closeActivity.setOnClickListener(onClickListener);
newFileCreate = findViewById(R.id.newFileCreate);
initCloseListener();
closeActivity.setOnClickListener(onClickListener);
newFileBranchesSpinner = findViewById(R.id.newFileBranchesSpinner);
newFileBranchesSpinner.getBackground().setColorFilter(getResources().getColor(R.color.white), PorterDuff.Mode.SRC_ATOP);
getBranches(instanceUrl, instanceToken, repoOwner, repoName, loginUid);
newFileBranchesSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener()
{
public void onItemSelected(AdapterView<?> arg0,
View arg1, int arg2, long arg3)
{
Branches bModelValue = (Branches) newFileBranchesSpinner.getSelectedItem();
Log.i("bModelSelected", bModelValue.toString());
if(bModelValue.toString().equals("No branch")) {
newFileBranchName.setEnabled(true);
}
else {
newFileBranchName.setEnabled(false);
newFileBranchName.setText("");
}
}
public void onNothingSelected(AdapterView<?> arg0) {}
});
disableProcessButton();
if(!connToInternet) {
newFileCreate.setEnabled(false);
GradientDrawable shape = new GradientDrawable();
shape.setCornerRadius( 8 );
shape.setColor(getResources().getColor(R.color.hintColor));
newFileCreate.setBackground(shape);
} else {
newFileCreate.setOnClickListener(createFileListener);
}
}
private View.OnClickListener createFileListener = new View.OnClickListener() {
public void onClick(View v) {
processNewFile();
}
};
private void processNewFile() {
boolean connToInternet = AppUtil.haveNetworkConnection(getApplicationContext());
AppUtil appUtil = new AppUtil();
TinyDB tinyDb = new TinyDB(getApplicationContext());
final String instanceUrl = tinyDb.getString("instanceUrl");
final String loginUid = tinyDb.getString("loginUid");
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
String repoFullName = tinyDb.getString("repoFullName");
String[] parts = repoFullName.split("/");
final String repoOwner = parts[0];
final String repoName = parts[1];
String newFileName_ = newFileName.getText().toString();
String newFileContent_ = newFileContent.getText().toString();
String newFileBranchName_ = newFileBranchName.getText().toString();
String newFileCommitMessage_ = newFileCommitMessage.getText().toString();
Branches currentBranch = (Branches) newFileBranchesSpinner.getSelectedItem();
if(!connToInternet) {
Toasty.info(getApplicationContext(), getResources().getString(R.string.checkNetConnection));
return;
}
if(newFileName_.equals("") || newFileContent_.equals("") || newFileCommitMessage_.equals("")) {
Toasty.info(getApplicationContext(), getString(R.string.newFileRequiredFields));
return;
}
if(currentBranch.toString().equals("No branch")) {
if(newFileBranchName_.equals("")) {
Toasty.info(getApplicationContext(), getString(R.string.newFileRequiredFieldNewBranchName));
return;
}
else {
if(!appUtil.checkStringsWithDash(newFileBranchName_)) {
Toasty.info(getApplicationContext(), getString(R.string.newFileInvalidBranchName));
return;
}
}
}
if(appUtil.charactersLength(newFileCommitMessage_) > 255) {
Toasty.info(getApplicationContext(), getString(R.string.newFileCommitMessageError));
}
else {
disableProcessButton();
createNewFile(instanceUrl, Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName, newFileName_, appUtil.encodeBase64(newFileContent_), newFileBranchName_, newFileCommitMessage_, currentBranch.toString());
}
}
private void createNewFile(final String instanceUrl, final String token, String repoOwner, String repoName, String fileName, String fileContent, String fileBranchName, String fileCommitMessage, String currentBranch) {
NewFile createNewFileJsonStr;
if(currentBranch.equals("No branch")) {
createNewFileJsonStr = new NewFile("", fileContent, fileCommitMessage, fileBranchName);
}
else {
createNewFileJsonStr = new NewFile(currentBranch, fileContent, fileCommitMessage, "");
}
Call<JsonElement> call = RetrofitClient
.getInstance(instanceUrl)
.getApiInterface()
.createNewFile(token, repoOwner, repoName, fileName, createNewFileJsonStr);
call.enqueue(new Callback<JsonElement>() {
@Override
public void onResponse(@NonNull Call<JsonElement> call, @NonNull retrofit2.Response<JsonElement> response) {
if(response.code() == 201) {
enableProcessButton();
Toasty.info(getApplicationContext(), getString(R.string.newFileSuccessMessage));
finish();
}
else if(response.code() == 401) {
enableProcessButton();
AlertDialogs.authorizationTokenRevokedDialog(ctx, getResources().getString(R.string.alertDialogTokenRevokedTitle),
getResources().getString(R.string.alertDialogTokenRevokedMessage),
getResources().getString(R.string.alertDialogTokenRevokedCopyNegativeButton),
getResources().getString(R.string.alertDialogTokenRevokedCopyPositiveButton));
}
else {
if(response.code() == 404) {
enableProcessButton();
Toasty.info(getApplicationContext(), getString(R.string.apiNotFound));
}
else {
enableProcessButton();
Toasty.info(getApplicationContext(), getString(R.string.orgCreatedError));
}
}
}
@Override
public void onFailure(@NonNull Call<JsonElement> call, @NonNull Throwable t) {
Log.e("onFailure", t.toString());
enableProcessButton();
}
});
}
private void getBranches(String instanceUrl, String instanceToken, String repoOwner, String repoName, String loginUid) {
Call<List<Branches>> call = RetrofitClient
.getInstance(instanceUrl)
.getApiInterface()
.getBranches(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName);
call.enqueue(new Callback<List<Branches>>() {
@Override
public void onResponse(@NonNull Call<List<Branches>> call, @NonNull retrofit2.Response<List<Branches>> response) {
if(response.isSuccessful()) {
if(response.code() == 200) {
List<Branches> branchesList_ = response.body();
branchesList.add(new Branches("No branch"));
assert branchesList_ != null;
if(branchesList_.size() > 0) {
for (int i = 0; i < branchesList_.size(); i++) {
Branches data = new Branches(
branchesList_.get(i).getName()
);
branchesList.add(data);
}
}
ArrayAdapter<Branches> adapter = new ArrayAdapter<>(getApplicationContext(),
R.layout.spinner_item, branchesList);
adapter.setDropDownViewResource(R.layout.spinner_dropdown_item);
newFileBranchesSpinner.setAdapter(adapter);
enableProcessButton();
}
}
}
@Override
public void onFailure(@NonNull Call<List<Branches>> call, @NonNull Throwable t) {
Log.e("onFailure", t.toString());
}
});
}
private void initCloseListener() {
onClickListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
finish();
}
};
}
private void disableProcessButton() {
newFileCreate.setEnabled(false);
GradientDrawable shape = new GradientDrawable();
shape.setCornerRadius( 8 );
shape.setColor(getResources().getColor(R.color.hintColor));
newFileCreate.setBackground(shape);
}
private void enableProcessButton() {
newFileCreate.setEnabled(true);
GradientDrawable shape = new GradientDrawable();
shape.setCornerRadius( 8 );
shape.setColor(getResources().getColor(R.color.btnBackground));
newFileCreate.setBackground(shape);
}
}

View File

@ -0,0 +1,35 @@
package org.mian.gitnex.activities;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import org.mian.gitnex.util.TinyDB;
/**
* Author M M Arif
*/
public class OpenRepoInBrowserActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TinyDB tinyDb = new TinyDB(getApplicationContext());
String instanceUrlWithProtocol = "https://" + tinyDb.getString("instanceUrlRaw");
if (!tinyDb.getString("instanceUrlWithProtocol").isEmpty()) {
instanceUrlWithProtocol = tinyDb.getString("instanceUrlWithProtocol");
}
String repoFullNameBrowser = getIntent().getStringExtra("repoFullNameBrowser");
Uri url = Uri.parse(instanceUrlWithProtocol + "/" + repoFullNameBrowser);
Intent i = new Intent(Intent.ACTION_VIEW, url);
startActivity(i);
finish();
}
}

View File

@ -3,9 +3,8 @@ package org.mian.gitnex.activities;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProviders;
import androidx.lifecycle.ViewModelProvider;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.GridView;
import android.widget.ImageView;
@ -63,7 +62,7 @@ public class OrgTeamMembersActivity extends AppCompatActivity {
}
getIntent().getStringExtra("teamId");
Log.i("teamId", getIntent().getStringExtra("teamId"));
//Log.i("teamId", getIntent().getStringExtra("teamId"));
fetchDataAsync(instanceUrl, Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), Integer.valueOf(teamId));
@ -71,7 +70,7 @@ public class OrgTeamMembersActivity extends AppCompatActivity {
private void fetchDataAsync(String instanceUrl, String instanceToken, int teamId) {
TeamMembersByOrgViewModel teamMembersModel = ViewModelProviders.of(this).get(TeamMembersByOrgViewModel.class);
TeamMembersByOrgViewModel teamMembersModel = new ViewModelProvider(this).get(TeamMembersByOrgViewModel.class);
teamMembersModel.getMembersByOrgList(instanceUrl, instanceToken, teamId).observe(this, new Observer<List<UserInfo>>() {
@Override

View File

@ -1,6 +1,7 @@
package org.mian.gitnex.activities;
import com.google.android.material.tabs.TabLayout;
import com.google.gson.JsonElement;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
@ -10,7 +11,9 @@ import androidx.fragment.app.FragmentStatePagerAdapter;
import androidx.viewpager.widget.ViewPager;
import retrofit2.Call;
import retrofit2.Callback;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.content.res.ColorStateList;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
@ -24,6 +27,7 @@ import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.fragments.BranchesFragment;
import org.mian.gitnex.fragments.ClosedIssuesFragment;
import org.mian.gitnex.fragments.CollaboratorsFragment;
import org.mian.gitnex.fragments.FilesFragment;
import org.mian.gitnex.fragments.IssuesFragment;
import org.mian.gitnex.fragments.LabelsFragment;
import org.mian.gitnex.fragments.MilestonesFragment;
@ -32,9 +36,11 @@ import org.mian.gitnex.fragments.RepoBottomSheetFragment;
import org.mian.gitnex.fragments.RepoInfoFragment;
import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.models.UserRepositories;
import org.mian.gitnex.models.WatchRepository;
import org.mian.gitnex.util.AppUtil;
import org.mian.gitnex.util.TinyDB;
import java.util.Objects;
import android.net.Uri;
/**
* Author M M Arif
@ -79,14 +85,23 @@ public class RepoDetailActivity extends AppCompatActivity implements RepoBottomS
if(tinyDb.getBoolean("enableCounterIssueBadge")) {
View tabHeader = LayoutInflater.from(this).inflate(R.layout.badge, null);
@SuppressLint("InflateParams") View tabHeader = LayoutInflater.from(this).inflate(R.layout.badge, null);
textViewBadge = tabHeader.findViewById(R.id.counterBadge);
if(!tinyDb.getString("issuesCounter").isEmpty()) {
getRepoInfo(instanceUrl, Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName1);
}
Objects.requireNonNull(tabLayout.getTabAt(1)).setCustomView(tabHeader);
Objects.requireNonNull(tabLayout.getTabAt(2)).setCustomView(tabHeader);
TabLayout.Tab tabOpenIssues = tabLayout.getTabAt(2);
ColorStateList textColor = tabLayout.getTabTextColors();
assert tabOpenIssues != null;
TextView openIssueTabView = Objects.requireNonNull(tabOpenIssues.getCustomView()).findViewById(R.id.counterBadgeText);
openIssueTabView.setTextColor(textColor);
}
checkRepositoryStarStatus(instanceUrl, Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName1);
checkRepositoryWatchStatus(instanceUrl, Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName1);
}
@Override
@ -107,7 +122,6 @@ public class RepoDetailActivity extends AppCompatActivity implements RepoBottomS
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
@ -153,6 +167,20 @@ public class RepoDetailActivity extends AppCompatActivity implements RepoBottomS
case "createRelease":
startActivity(new Intent(RepoDetailActivity.this, CreateReleaseActivity.class));
break;
case "openWebRepo":
TinyDB tinyDb = new TinyDB(getApplicationContext());
String repoFullName = tinyDb.getString("repoFullName");
String instanceUrlWithProtocol = "https://" + tinyDb.getString("instanceUrlRaw");
if(!tinyDb.getString("instanceUrlWithProtocol").isEmpty()) {
instanceUrlWithProtocol = tinyDb.getString("instanceUrlWithProtocol");
}
Uri url = Uri.parse(instanceUrlWithProtocol + "/" + repoFullName);
Intent i = new Intent(Intent.ACTION_VIEW, url);
startActivity(i);
break;
case "newFile":
startActivity(new Intent(RepoDetailActivity.this, NewFileActivity.class));
break;
}
}
@ -160,7 +188,7 @@ public class RepoDetailActivity extends AppCompatActivity implements RepoBottomS
public class SectionsPagerAdapter extends FragmentStatePagerAdapter {
SectionsPagerAdapter(FragmentManager fm) {
super(fm);
super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
}
@NonNull
@ -177,21 +205,23 @@ public class RepoDetailActivity extends AppCompatActivity implements RepoBottomS
switch (position) {
case 0: // information
return RepoInfoFragment.newInstance(repoOwner, repoName);
case 1: // issues
case 1: // files
return FilesFragment.newInstance(repoOwner, repoName);
case 2: // issues
fragment = new IssuesFragment();
break;
case 2: // closed issues
case 3: // closed issues
fragment = new ClosedIssuesFragment();
break;
case 3: // milestones
case 4: // milestones
return MilestonesFragment.newInstance(repoOwner, repoName);
case 4: // labels
case 5: // labels
return LabelsFragment.newInstance(repoOwner, repoName);
case 5: // branches
case 6: // branches
return BranchesFragment.newInstance(repoOwner, repoName);
case 6: // releases
case 7: // releases
return ReleasesFragment.newInstance(repoOwner, repoName);
case 7: // collaborators
case 8: // collaborators
return CollaboratorsFragment.newInstance(repoOwner, repoName);
}
return fragment;
@ -199,7 +229,7 @@ public class RepoDetailActivity extends AppCompatActivity implements RepoBottomS
@Override
public int getCount() {
return 8;
return 9;
}
}
@ -242,4 +272,67 @@ public class RepoDetailActivity extends AppCompatActivity implements RepoBottomS
}
private void checkRepositoryStarStatus(String instanceUrl, String instanceToken, final String owner, String repo) {
Call<JsonElement> call;
call = RetrofitClient
.getInstance(instanceUrl)
.getApiInterface()
.checkRepoStarStatus(instanceToken, owner, repo);
call.enqueue(new Callback<JsonElement>() {
@Override
public void onResponse(@NonNull Call<JsonElement> call, @NonNull retrofit2.Response<JsonElement> response) {
TinyDB tinyDb = new TinyDB(getApplicationContext());
tinyDb.putInt("repositoryStarStatus", response.code());
}
@Override
public void onFailure(@NonNull Call<JsonElement> call, @NonNull Throwable t) {
Log.e("onFailure", t.toString());
}
});
}
private void checkRepositoryWatchStatus(String instanceUrl, String instanceToken, final String owner, String repo) {
Call<WatchRepository> call;
call = RetrofitClient
.getInstance(instanceUrl)
.getApiInterface()
.checkRepoWatchStatus(instanceToken, owner, repo);
call.enqueue(new Callback<WatchRepository>() {
@Override
public void onResponse(@NonNull Call<WatchRepository> call, @NonNull retrofit2.Response<WatchRepository> response) {
TinyDB tinyDb = new TinyDB(getApplicationContext());
if(response.code() == 200) {
assert response.body() != null;
if(response.body().getSubscribed()) {
tinyDb.putBoolean("repositoryWatchStatus", true);
}
}
else {
tinyDb.putBoolean("repositoryWatchStatus", false);
}
}
@Override
public void onFailure(@NonNull Call<WatchRepository> call, @NonNull Throwable t) {
Log.e("onFailure", t.toString());
}
});
}
}

View File

@ -0,0 +1,95 @@
package org.mian.gitnex.activities;
import android.os.Bundle;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import android.view.View;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import org.mian.gitnex.R;
import org.mian.gitnex.adapters.RepoStargazersAdapter;
import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.models.UserInfo;
import org.mian.gitnex.util.TinyDB;
import org.mian.gitnex.viewmodels.RepoStargazersViewModel;
import java.util.List;
/**
* Author M M Arif
*/
public class RepoStargazersActivity extends AppCompatActivity {
private TextView noDataStargazers;
private View.OnClickListener onClickListener;
private RepoStargazersAdapter adapter;
private GridView mGridView;
private ProgressBar mProgressBar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_repo_stargazers);
TinyDB tinyDb = new TinyDB(getApplicationContext());
final String instanceUrl = tinyDb.getString("instanceUrl");
final String loginUid = tinyDb.getString("loginUid");
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
ImageView closeActivity = findViewById(R.id.close);
TextView toolbarTitle = findViewById(R.id.toolbar_title);
noDataStargazers = findViewById(R.id.noDataStargazers);
mGridView = findViewById(R.id.gridView);
mProgressBar = findViewById(R.id.progress_bar);
String repoFullNameForStars = getIntent().getStringExtra("repoFullNameForStars");
String[] parts = repoFullNameForStars.split("/");
final String repoOwner = parts[0];
final String repoName = parts[1];
initCloseListener();
closeActivity.setOnClickListener(onClickListener);
toolbarTitle.setText(R.string.repoStargazersInMenu);
fetchDataAsync(instanceUrl, Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName);
}
private void fetchDataAsync(String instanceUrl, String instanceToken, String repoOwner, String repoName) {
RepoStargazersViewModel repoStargazersModel = new ViewModelProvider(this).get(RepoStargazersViewModel.class);
repoStargazersModel.getRepoStargazers(instanceUrl, instanceToken, repoOwner, repoName).observe(this, new Observer<List<UserInfo>>() {
@Override
public void onChanged(@Nullable List<UserInfo> stargazersListMain) {
adapter = new RepoStargazersAdapter(getApplicationContext(), stargazersListMain);
if(adapter.getCount() > 0) {
mGridView.setAdapter(adapter);
noDataStargazers.setVisibility(View.GONE);
}
else {
adapter.notifyDataSetChanged();
mGridView.setAdapter(adapter);
noDataStargazers.setVisibility(View.VISIBLE);
}
mProgressBar.setVisibility(View.GONE);
}
});
}
private void initCloseListener() {
onClickListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
finish();
}
};
}
}

View File

@ -0,0 +1,95 @@
package org.mian.gitnex.activities;
import android.os.Bundle;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import android.view.View;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import org.mian.gitnex.R;
import org.mian.gitnex.adapters.RepoWatchersAdapter;
import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.models.UserInfo;
import org.mian.gitnex.util.TinyDB;
import org.mian.gitnex.viewmodels.RepoWatchersViewModel;
import java.util.List;
/**
* Author M M Arif
*/
public class RepoWatchersActivity extends AppCompatActivity {
private TextView noDataWatchers;
private View.OnClickListener onClickListener;
private RepoWatchersAdapter adapter;
private GridView mGridView;
private ProgressBar mProgressBar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_repo_watchers);
TinyDB tinyDb = new TinyDB(getApplicationContext());
final String instanceUrl = tinyDb.getString("instanceUrl");
final String loginUid = tinyDb.getString("loginUid");
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
ImageView closeActivity = findViewById(R.id.close);
TextView toolbarTitle = findViewById(R.id.toolbar_title);
noDataWatchers = findViewById(R.id.noDataWatchers);
mGridView = findViewById(R.id.gridView);
mProgressBar = findViewById(R.id.progress_bar);
String repoFullNameForWatchers = getIntent().getStringExtra("repoFullNameForWatchers");
String[] parts = repoFullNameForWatchers.split("/");
final String repoOwner = parts[0];
final String repoName = parts[1];
initCloseListener();
closeActivity.setOnClickListener(onClickListener);
toolbarTitle.setText(R.string.repoWatchersInMenu);
fetchDataAsync(instanceUrl, Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName);
}
private void fetchDataAsync(String instanceUrl, String instanceToken, String repoOwner, String repoName) {
RepoWatchersViewModel repoWatchersModel = new ViewModelProvider(this).get(RepoWatchersViewModel.class);
repoWatchersModel.getRepoWatchers(instanceUrl, instanceToken, repoOwner, repoName).observe(this, new Observer<List<UserInfo>>() {
@Override
public void onChanged(@Nullable List<UserInfo> watchersListMain) {
adapter = new RepoWatchersAdapter(getApplicationContext(), watchersListMain);
if(adapter.getCount() > 0) {
mGridView.setAdapter(adapter);
noDataWatchers.setVisibility(View.GONE);
}
else {
adapter.notifyDataSetChanged();
mGridView.setAdapter(adapter);
noDataWatchers.setVisibility(View.VISIBLE);
}
mProgressBar.setVisibility(View.GONE);
}
});
}
private void initCloseListener() {
onClickListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
finish();
}
};
}
}

View File

@ -2,8 +2,10 @@ package org.mian.gitnex.activities;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.text.method.LinkMovementMethod;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import org.mian.gitnex.R;
/**
@ -20,6 +22,9 @@ public class SponsorsActivity extends AppCompatActivity {
setContentView(R.layout.activity_sponsors);
ImageView closeActivity = findViewById(R.id.close);
TextView liberaPaySponsorsThomas = findViewById(R.id.liberaPaySponsorsThomas);
liberaPaySponsorsThomas.setMovementMethod(LinkMovementMethod.getInstance());
initCloseListener();
closeActivity.setOnClickListener(onClickListener);

View File

@ -98,7 +98,7 @@ public class AdminGetUsersAdapter extends RecyclerView.Adapter<AdminGetUsersAdap
holder.userRole.setVisibility(View.GONE);
}
Picasso.get().load(currentItem.getAvatar()).transform(new RoundedTransformation(100, 0)).resize(140, 140).centerCrop().into(holder.userAvatar);
Picasso.get().load(currentItem.getAvatar()).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(holder.userAvatar);
}
@Override

View File

@ -1,12 +1,13 @@
package org.mian.gitnex.adapters;
import android.content.Context;
import android.text.Html;
import android.text.method.LinkMovementMethod;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import org.mian.gitnex.R;
import org.mian.gitnex.helpers.UrlHelper;
import org.mian.gitnex.models.Branches;
import org.mian.gitnex.util.TinyDB;
import java.util.List;
@ -66,7 +67,9 @@ public class BranchesAdapter extends RecyclerView.Adapter<BranchesAdapter.Branch
holder.branchCommitAuthor.setText(mCtx.getResources().getString(R.string.commitAuthor, currentItem.getCommit().getAuthor().getUsername()));
}
holder.branchCommitHash.setText(mCtx.getResources().getString(R.string.commitHash, UrlHelper.cleanUrl(instanceUrl), currentItem.getCommit().getUrl()));
holder.branchCommitHash.setText(
Html.fromHtml("<a href='" + currentItem.getCommit().getUrl() + "'>" + mCtx.getResources().getString(R.string.commitLinkBranchesTab) + "</a> "));
holder.branchCommitHash.setMovementMethod(LinkMovementMethod.getInstance());
}

View File

@ -3,22 +3,21 @@ package org.mian.gitnex.adapters;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.text.Html;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.squareup.picasso.Picasso;
import com.vdurmont.emoji.EmojiParser;
import org.mian.gitnex.R;
import org.mian.gitnex.activities.IssueDetailActivity;
import org.mian.gitnex.helpers.ClickListener;
import org.mian.gitnex.helpers.RoundedTransformation;
import org.mian.gitnex.helpers.TimeHelper;
import org.mian.gitnex.helpers.UserMentions;
import org.mian.gitnex.models.Issues;
import org.mian.gitnex.util.TinyDB;
import org.ocpsoft.prettytime.PrettyTime;
@ -27,22 +26,8 @@ import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import okhttp3.OkHttpClient;
import ru.noties.markwon.AbstractMarkwonPlugin;
import ru.noties.markwon.Markwon;
import ru.noties.markwon.core.CorePlugin;
import ru.noties.markwon.core.MarkwonTheme;
import ru.noties.markwon.ext.strikethrough.StrikethroughPlugin;
import ru.noties.markwon.ext.tables.TablePlugin;
import ru.noties.markwon.ext.tables.TableTheme;
import ru.noties.markwon.ext.tasklist.TaskListPlugin;
import ru.noties.markwon.html.HtmlPlugin;
import ru.noties.markwon.image.ImagesPlugin;
import ru.noties.markwon.image.gif.GifPlugin;
import ru.noties.markwon.image.okhttp.OkHttpImagesPlugin;
/**
* Author M M Arif
@ -122,8 +107,6 @@ public class ClosedIssuesAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
private TextView issueNumber;
private ImageView issueAssigneeAvatar;
private TextView issueTitle;
private TextView issueDescription;
//private ImageView issueState;
private TextView issueCreatedTime;
private TextView issueCommentsCount;
private ImageView issueType;
@ -135,9 +118,8 @@ public class ClosedIssuesAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
issueNumber = itemView.findViewById(R.id.issueNumber);
issueAssigneeAvatar = itemView.findViewById(R.id.assigneeAvatar);
issueTitle = itemView.findViewById(R.id.issueTitle);
issueDescription = itemView.findViewById(R.id.issueDescription);
issueCommentsCount = itemView.findViewById(R.id.issueCommentsCount);
//issueState = itemView.findViewById(R.id.issueStatus);
LinearLayout frameCommentsCount = itemView.findViewById(R.id.frameCommentsCount);
issueCreatedTime = itemView.findViewById(R.id.issueCreatedTime);
issueType = itemView.findViewById(R.id.issueType);
@ -157,7 +139,7 @@ public class ClosedIssuesAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
}
});
issueDescription.setOnClickListener(new View.OnClickListener() {
frameCommentsCount.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
@ -183,26 +165,6 @@ public class ClosedIssuesAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
final String locale = tinyDb.getString("locale");
final String timeFormat = tinyDb.getString("dateFormat");
final Markwon markwon = Markwon.builder(Objects.requireNonNull(context))
.usePlugin(CorePlugin.create())
.usePlugin(OkHttpImagesPlugin.create(new OkHttpClient()))
.usePlugin(ImagesPlugin.createWithAssets(context))
.usePlugin(new AbstractMarkwonPlugin() {
@Override
public void configureTheme(@NonNull MarkwonTheme.Builder builder) {
builder
.codeTextColor(tinyDb.getInt("codeBlockColor"))
.codeBackgroundColor(tinyDb.getInt("codeBlockBackground"))
.linkColor(context.getResources().getColor(R.color.lightBlue));
}
})
.usePlugin(TablePlugin.create(context))
.usePlugin(TaskListPlugin.create(context))
.usePlugin(HtmlPlugin.create())
.usePlugin(GifPlugin.create())
.usePlugin(StrikethroughPlugin.create())
.build();
if (!issuesModel.getUser().getFull_name().equals("")) {
issueAssigneeAvatar.setOnClickListener(new ClickListener(context.getResources().getString(R.string.issueCreator) + issuesModel.getUser().getFull_name(), context));
} else {
@ -210,9 +172,9 @@ public class ClosedIssuesAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
}
if (issuesModel.getUser().getAvatar_url() != null) {
Picasso.get().load(issuesModel.getUser().getAvatar_url()).transform(new RoundedTransformation(100, 0)).resize(200, 200).centerCrop().into(issueAssigneeAvatar);
Picasso.get().load(issuesModel.getUser().getAvatar_url()).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(issueAssigneeAvatar);
} else {
Picasso.get().load(issuesModel.getUser().getAvatar_url()).transform(new RoundedTransformation(100, 0)).resize(200, 200).centerCrop().into(issueAssigneeAvatar);
Picasso.get().load(issuesModel.getUser().getAvatar_url()).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(issueAssigneeAvatar);
}
if (issuesModel.getPull_request() == null) {
@ -223,28 +185,12 @@ public class ClosedIssuesAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
issueType.setOnClickListener(new ClickListener(context.getResources().getString(R.string.issueTypePullRequest), context));
}
issueTitle.setText(context.getResources().getString(R.string.hash) + issuesModel.getNumber() + " " + issuesModel.getTitle());
String issueNumber_ = "<font color='" + context.getResources().getColor(R.color.lightGray) + "'>" + context.getResources().getString(R.string.hash) + issuesModel.getNumber() + "</font>";
issueTitle.setText(Html.fromHtml(issueNumber_ + " " + issuesModel.getTitle()));
issueNumber.setText(String.valueOf(issuesModel.getNumber()));
issueCommentsCount.setText(String.valueOf(issuesModel.getComments()));
if (!issuesModel.getBody().equals("")) {
String cleanIssueDescription = issuesModel.getBody().trim();
issueDescription.setVisibility(View.VISIBLE);
final CharSequence bodyWithMD = markwon.toMarkdown(EmojiParser.parseToUnicode(cleanIssueDescription));
issueDescription.setText(UserMentions.UserMentionsFunc(context, bodyWithMD, cleanIssueDescription));
}
else {
issueDescription.setText("");
issueDescription.setVisibility(View.GONE);
}
/*if (issuesModel.getState().equals("open")) {
issueState.setImageResource(R.drawable.ic_issue_open);
issueState.setOnClickListener(new ClickListener(context.getResources().getString(R.string.issueStatusTextOpen), context));
} else {
issueState.setImageResource(R.drawable.ic_issue_closed);
issueState.setOnClickListener(new ClickListener(context.getResources().getString(R.string.issueStatusTextClosed), context));
}*/
switch (timeFormat) {
case "pretty": {
PrettyTime prettyTime = new PrettyTime(new Locale(locale));

View File

@ -77,7 +77,7 @@ public class CollaboratorsAdapter extends BaseAdapter {
private void initData(ViewHolder viewHolder, int position) {
Collaborators currentItem = collaboratorsList.get(position);
Picasso.get().load(currentItem.getAvatar_url()).transform(new RoundedTransformation(100, 0)).resize(200, 200).centerCrop().into(viewHolder.collaboratorAvatar);
Picasso.get().load(currentItem.getAvatar_url()).transform(new RoundedTransformation(8, 0)).resize(180, 180).centerCrop().into(viewHolder.collaboratorAvatar);
if(!currentItem.getFull_name().equals("")) {
viewHolder.collaboratorName.setText(currentItem.getFull_name());

View File

@ -0,0 +1,216 @@
package org.mian.gitnex.adapters;
import android.content.Context;
import android.content.Intent;
import android.graphics.Typeface;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.view.ContextThemeWrapper;
import androidx.appcompat.widget.PopupMenu;
import androidx.recyclerview.widget.RecyclerView;
import com.amulyakhare.textdrawable.TextDrawable;
import com.amulyakhare.textdrawable.util.ColorGenerator;
import com.squareup.picasso.Picasso;
import org.mian.gitnex.R;
import org.mian.gitnex.activities.OpenRepoInBrowserActivity;
import org.mian.gitnex.activities.RepoDetailActivity;
import org.mian.gitnex.activities.RepoStargazersActivity;
import org.mian.gitnex.activities.RepoWatchersActivity;
import org.mian.gitnex.helpers.RoundedTransformation;
import org.mian.gitnex.models.UserRepositories;
import org.mian.gitnex.util.TinyDB;
import java.lang.reflect.Field;
import java.util.List;
/**
* Author M M Arif
*/
public class ExploreRepositoriesAdapter extends RecyclerView.Adapter<ExploreRepositoriesAdapter.ReposSearchViewHolder> {
private List<UserRepositories> searchedReposList;
private Context mCtx;
public ExploreRepositoriesAdapter(List<UserRepositories> dataList, Context mCtx) {
this.mCtx = mCtx;
this.searchedReposList = dataList;
}
static class ReposSearchViewHolder extends RecyclerView.ViewHolder {
private ImageView image;
private TextView mTextView1;
private TextView mTextView2;
private TextView fullName;
private ImageView repoPrivatePublic;
private TextView repoStars;
private TextView repoForks;
private TextView repoOpenIssuesCount;
private ReposSearchViewHolder(View itemView) {
super(itemView);
mTextView1 = itemView.findViewById(R.id.repoName);
mTextView2 = itemView.findViewById(R.id.repoDescription);
image = itemView.findViewById(R.id.imageAvatar);
fullName = itemView.findViewById(R.id.repoFullName);
repoPrivatePublic = itemView.findViewById(R.id.imageRepoType);
repoStars = itemView.findViewById(R.id.repoStars);
repoForks = itemView.findViewById(R.id.repoForks);
repoOpenIssuesCount = itemView.findViewById(R.id.repoOpenIssuesCount);
ImageView reposDropdownMenu = itemView.findViewById(R.id.reposDropdownMenu);
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Context context = v.getContext();
TextView repoFullName = v.findViewById(R.id.repoFullName);
Intent intent = new Intent(context, RepoDetailActivity.class);
intent.putExtra("repoFullName", repoFullName.getText().toString());
TinyDB tinyDb = new TinyDB(context);
tinyDb.putString("repoFullName", repoFullName.getText().toString());
tinyDb.putBoolean("resumeIssues", true);
context.startActivity(intent);
}
});
reposDropdownMenu.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
final Context context = v.getContext();
Context context_ = new ContextThemeWrapper(context, R.style.popupMenuStyle);
PopupMenu popupMenu = new PopupMenu(context_, v);
popupMenu.inflate(R.menu.repo_dotted_list_menu);
Object menuHelper;
Class[] argTypes;
try {
Field fMenuHelper = PopupMenu.class.getDeclaredField("mPopup");
fMenuHelper.setAccessible(true);
menuHelper = fMenuHelper.get(popupMenu);
argTypes = new Class[] { boolean.class };
menuHelper.getClass().getDeclaredMethod("setForceShowIcon",
argTypes).invoke(menuHelper, true);
} catch (Exception e) {
popupMenu.show();
return;
}
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case R.id.repoStargazers:
Intent intent = new Intent(context, RepoStargazersActivity.class);
intent.putExtra("repoFullNameForStars", fullName.getText());
context.startActivity(intent);
break;
case R.id.repoWatchers:
Intent intentW = new Intent(context, RepoWatchersActivity.class);
intentW.putExtra("repoFullNameForWatchers", fullName.getText());
context.startActivity(intentW);
break;
case R.id.repoOpenInBrowser:
Intent intentOpenInBrowser = new Intent(context, OpenRepoInBrowserActivity.class);
intentOpenInBrowser.putExtra("repoFullNameBrowser", fullName.getText());
context.startActivity(intentOpenInBrowser);
break;
}
return false;
}
});
popupMenu.show();
}
});
}
}
@NonNull
@Override
public ExploreRepositoriesAdapter.ReposSearchViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.repos_list, parent, false);
return new ExploreRepositoriesAdapter.ReposSearchViewHolder(v);
}
@Override
public void onBindViewHolder(@NonNull final ExploreRepositoriesAdapter.ReposSearchViewHolder holder, int position) {
final UserRepositories currentItem = searchedReposList.get(position);
holder.mTextView2.setVisibility(View.GONE);
ColorGenerator generator = ColorGenerator.MATERIAL;
int color = generator.getColor(currentItem.getName());
String firstCharacter = String.valueOf(currentItem.getName().charAt(0));
TextDrawable drawable = TextDrawable.builder()
.beginConfig()
.useFont(Typeface.DEFAULT)
.fontSize(18)
.toUpperCase()
.width(28)
.height(28)
.endConfig()
.buildRoundRect(firstCharacter, color, 3);
if (currentItem.getAvatar_url() != null) {
if (!currentItem.getAvatar_url().equals("")) {
Picasso.get().load(currentItem.getAvatar_url()).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(holder.image);
} else {
holder.image.setImageDrawable(drawable);
}
}
else {
holder.image.setImageDrawable(drawable);
}
holder.mTextView1.setText(currentItem.getName());
if (!currentItem.getDescription().equals("")) {
holder.mTextView2.setVisibility(View.VISIBLE);
holder.mTextView2.setText(currentItem.getDescription());
}
holder.fullName.setText(currentItem.getFullname());
if(currentItem.getPrivateFlag()) {
holder.repoPrivatePublic.setImageResource(R.drawable.ic_lock_bold);
}
else {
holder.repoPrivatePublic.setImageResource(R.drawable.ic_public);
}
holder.repoStars.setText(currentItem.getStars_count());
holder.repoForks.setText(currentItem.getForks_count());
holder.repoOpenIssuesCount.setText(currentItem.getOpen_issues_count());
}
@Override
public int getItemCount() {
return searchedReposList.size();
}
}

View File

@ -0,0 +1,212 @@
package org.mian.gitnex.adapters;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import org.mian.gitnex.R;
import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.models.Files;
import java.util.ArrayList;
import java.util.List;
/**
* Author M M Arif
*/
public class FilesAdapter extends RecyclerView.Adapter<FilesAdapter.FilesViewHolder> implements Filterable {
private List<Files> filesList;
private Context mCtx;
private List<Files> filesListFull;
private FilesAdapterListener filesListener;
public interface FilesAdapterListener {
void onClickDir(String str);
void onClickFile(String str);
}
class FilesViewHolder extends RecyclerView.ViewHolder {
private ImageView fileTypeImage;
private TextView fileName;
private TextView fileType;
private FilesViewHolder(View itemView) {
super(itemView);
fileName = itemView.findViewById(R.id.fileName);
fileTypeImage = itemView.findViewById(R.id.fileImage);
fileType = itemView.findViewById(R.id.fileType);
//ImageView filesDropdownMenu = itemView.findViewById(R.id.filesDropdownMenu);
fileName.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Context context = v.getContext();
if(fileType.getText().toString().equals("file")) {
filesListener.onClickFile(fileName.getText().toString());
}
else if(fileType.getText().toString().equals("dir")) {
filesListener.onClickDir(fileName.getText().toString());
}
else {
Toasty.info(context, context.getString(R.string.filesGenericError));
}
}
});
/*filesDropdownMenu.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
final Context context = v.getContext();
Context context_ = new ContextThemeWrapper(context, R.style.popupMenuStyle);
PopupMenu popupMenu = new PopupMenu(context_, v);
popupMenu.inflate(R.menu.files_dotted_list_menu);
Object menuHelper;
Class[] argTypes;
try {
Field fMenuHelper = PopupMenu.class.getDeclaredField("mPopup");
fMenuHelper.setAccessible(true);
menuHelper = fMenuHelper.get(popupMenu);
argTypes = new Class[] { boolean.class };
menuHelper.getClass().getDeclaredMethod("setForceShowIcon",
argTypes).invoke(menuHelper, true);
} catch (Exception e) {
popupMenu.show();
return;
}
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case R.id.deleteFile:
Intent intent = new Intent(context, DeleteFileActivity.class);
intent.putExtra("repoFullNameForDeleteFile", fullName.getText());
context.startActivity(intent);
break;
case R.id.editFile:
Intent intentW = new Intent(context, EditFileActivity.class);
intentW.putExtra("repoFullNameForEditFile", fullName.getText());
context.startActivity(intentW);
break;
case R.id.openInBrowser:
Intent intentOpenInBrowser = new Intent(context, OpenFileInBrowserActivity.class);
intentOpenInBrowser.putExtra("fileFullNameBrowser", fullName.getText());
context.startActivity(intentOpenInBrowser);
break;
}
return false;
}
});
popupMenu.show();
}
});*/
}
}
public FilesAdapter(Context mCtx, List<Files> filesListMain, FilesAdapterListener filesListener) {
this.mCtx = mCtx;
this.filesList = filesListMain;
filesListFull = new ArrayList<>(filesList);
this.filesListener = filesListener;
}
@NonNull
@Override
public FilesAdapter.FilesViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.files_list, parent, false);
return new FilesAdapter.FilesViewHolder(v);
}
@Override
public void onBindViewHolder(@NonNull FilesAdapter.FilesViewHolder holder, int position) {
Files currentItem = filesList.get(position);
holder.fileType.setText(currentItem.getType());
holder.fileName.setText(currentItem.getName());
if(currentItem.getType().equals("file")) {
holder.fileTypeImage.setImageDrawable(mCtx.getResources().getDrawable(R.drawable.ic_file_new));
}
else if(currentItem.getType().equals("dir")) {
holder.fileTypeImage.setImageDrawable(mCtx.getResources().getDrawable(R.drawable.ic_folder_24));
}
else {
holder.fileTypeImage.setImageDrawable(mCtx.getResources().getDrawable(R.drawable.ic_question_mark_24));
}
}
@Override
public int getItemCount() {
return filesList.size();
}
@Override
public Filter getFilter() {
return filesFilter;
}
private Filter filesFilter = new Filter() {
@Override
protected FilterResults performFiltering(CharSequence constraint) {
List<Files> filteredList = new ArrayList<>();
if (constraint == null || constraint.length() == 0) {
filteredList.addAll(filesListFull);
} else {
String filterPattern = constraint.toString().toLowerCase().trim();
for (Files item : filesListFull) {
if (item.getName().toLowerCase().contains(filterPattern) || item.getPath().toLowerCase().contains(filterPattern)) {
filteredList.add(item);
}
}
}
FilterResults results = new FilterResults();
results.values = filteredList;
return results;
}
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
filesList.clear();
filesList.addAll((List) results.values);
notifyDataSetChanged();
}
};
}

View File

@ -3,7 +3,9 @@ package org.mian.gitnex.adapters;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.text.Spanned;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
@ -14,8 +16,8 @@ import com.squareup.picasso.Picasso;
import com.vdurmont.emoji.EmojiParser;
import org.mian.gitnex.R;
import org.mian.gitnex.activities.ReplyToIssueActivity;
import org.mian.gitnex.helpers.UserMentions;
import org.mian.gitnex.helpers.TimeHelper;
import org.mian.gitnex.helpers.UserMentions;
import org.mian.gitnex.models.IssueComments;
import org.mian.gitnex.helpers.RoundedTransformation;
import org.mian.gitnex.util.TinyDB;
@ -24,26 +26,32 @@ import org.ocpsoft.prettytime.PrettyTime;
import java.lang.reflect.Field;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.view.ContextThemeWrapper;
import androidx.appcompat.widget.PopupMenu;
import androidx.recyclerview.widget.RecyclerView;
import okhttp3.OkHttpClient;
import ru.noties.markwon.AbstractMarkwonPlugin;
import ru.noties.markwon.Markwon;
import ru.noties.markwon.core.CorePlugin;
import ru.noties.markwon.core.MarkwonTheme;
import ru.noties.markwon.ext.strikethrough.StrikethroughPlugin;
import ru.noties.markwon.ext.tables.TablePlugin;
import ru.noties.markwon.ext.tables.TableTheme;
import ru.noties.markwon.ext.tasklist.TaskListPlugin;
import ru.noties.markwon.html.HtmlPlugin;
import ru.noties.markwon.image.ImagesPlugin;
import ru.noties.markwon.image.gif.GifPlugin;
import ru.noties.markwon.image.okhttp.OkHttpImagesPlugin;
import io.noties.markwon.AbstractMarkwonPlugin;
import io.noties.markwon.Markwon;
import io.noties.markwon.core.CorePlugin;
import io.noties.markwon.core.MarkwonTheme;
import io.noties.markwon.ext.strikethrough.StrikethroughPlugin;
import io.noties.markwon.ext.tables.TablePlugin;
import io.noties.markwon.ext.tasklist.TaskListPlugin;
import io.noties.markwon.html.HtmlPlugin;
import io.noties.markwon.image.AsyncDrawable;
import io.noties.markwon.image.DefaultMediaDecoder;
import io.noties.markwon.image.ImageItem;
import io.noties.markwon.image.ImagesPlugin;
import io.noties.markwon.image.SchemeHandler;
import io.noties.markwon.image.gif.GifMediaDecoder;
import io.noties.markwon.image.svg.SvgMediaDecoder;
import io.noties.markwon.linkify.LinkifyPlugin;
/**
* Author M M Arif
@ -171,34 +179,72 @@ public class IssueCommentsAdapter extends RecyclerView.Adapter<IssueCommentsAdap
}
if (currentItem.getUser().getAvatar_url() != null) {
Picasso.get().load(currentItem.getUser().getAvatar_url()).transform(new RoundedTransformation(100, 0)).resize(200, 200).centerCrop().into(holder.issueCommenterAvatar);
Picasso.get().load(currentItem.getUser().getAvatar_url()).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(holder.issueCommenterAvatar);
} else {
Picasso.get().load(currentItem.getUser().getAvatar_url()).transform(new RoundedTransformation(100, 0)).resize(200, 200).centerCrop().into(holder.issueCommenterAvatar);
Picasso.get().load(currentItem.getUser().getAvatar_url()).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(holder.issueCommenterAvatar);
}
String cleanIssueComments = currentItem.getBody().trim();
final Markwon markwon = Markwon.builder(Objects.requireNonNull(mCtx))
.usePlugin(CorePlugin.create())
.usePlugin(OkHttpImagesPlugin.create(new OkHttpClient()))
.usePlugin(ImagesPlugin.create(mCtx))
.usePlugin(ImagesPlugin.create(new ImagesPlugin.ImagesConfigure() {
@Override
public void configureImages(@NonNull ImagesPlugin plugin) {
plugin.addSchemeHandler(new SchemeHandler() {
@NonNull
@Override
public ImageItem handle(@NonNull String raw, @NonNull Uri uri) {
final int resourceId = mCtx.getResources().getIdentifier(
raw.substring("drawable://".length()),
"drawable",
mCtx.getPackageName());
final Drawable drawable = mCtx.getDrawable(resourceId);
assert drawable != null;
return ImageItem.withResult(drawable);
}
@NonNull
@Override
public Collection<String> supportedSchemes() {
return Collections.singleton("drawable");
}
});
plugin.placeholderProvider(new ImagesPlugin.PlaceholderProvider() {
@Nullable
@Override
public Drawable providePlaceholder(@NonNull AsyncDrawable drawable) {
return null;
}
});
plugin.addMediaDecoder(GifMediaDecoder.create(false));
plugin.addMediaDecoder(SvgMediaDecoder.create(mCtx.getResources()));
plugin.addMediaDecoder(SvgMediaDecoder.create());
plugin.defaultMediaDecoder(DefaultMediaDecoder.create(mCtx.getResources()));
plugin.defaultMediaDecoder(DefaultMediaDecoder.create());
}
}))
.usePlugin(new AbstractMarkwonPlugin() {
@Override
public void configureTheme(@NonNull MarkwonTheme.Builder builder) {
builder
.codeTextColor(tinyDb.getInt("codeBlockColor"))
.codeBackgroundColor(tinyDb.getInt("codeBlockBackground"));
.codeBackgroundColor(tinyDb.getInt("codeBlockBackground"))
.linkColor(mCtx.getResources().getColor(R.color.lightBlue));
}
})
.usePlugin(TablePlugin.create(mCtx))
.usePlugin(TaskListPlugin.create(mCtx))
.usePlugin(HtmlPlugin.create())
.usePlugin(GifPlugin.create())
.usePlugin(StrikethroughPlugin.create())
.usePlugin(LinkifyPlugin.create())
.build();
final CharSequence bodyWithMD = markwon.toMarkdown(EmojiParser.parseToUnicode(cleanIssueComments));
holder.issueComment.setText(UserMentions.UserMentionsFunc(mCtx, bodyWithMD, cleanIssueComments));
Spanned bodyWithMD = markwon.toMarkdown(EmojiParser.parseToUnicode(cleanIssueComments));
markwon.setParsedMarkdown(holder.issueComment, UserMentions.UserMentionsFunc(mCtx, bodyWithMD, cleanIssueComments));
String edited;

View File

@ -3,22 +3,21 @@ package org.mian.gitnex.adapters;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.text.Html;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.squareup.picasso.Picasso;
import com.vdurmont.emoji.EmojiParser;
import org.mian.gitnex.R;
import org.mian.gitnex.activities.IssueDetailActivity;
import org.mian.gitnex.helpers.ClickListener;
import org.mian.gitnex.helpers.RoundedTransformation;
import org.mian.gitnex.helpers.TimeHelper;
import org.mian.gitnex.helpers.UserMentions;
import org.mian.gitnex.models.Issues;
import org.mian.gitnex.util.TinyDB;
import org.ocpsoft.prettytime.PrettyTime;
@ -27,22 +26,8 @@ import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import okhttp3.OkHttpClient;
import ru.noties.markwon.AbstractMarkwonPlugin;
import ru.noties.markwon.Markwon;
import ru.noties.markwon.core.CorePlugin;
import ru.noties.markwon.core.MarkwonTheme;
import ru.noties.markwon.ext.strikethrough.StrikethroughPlugin;
import ru.noties.markwon.ext.tables.TablePlugin;
import ru.noties.markwon.ext.tables.TableTheme;
import ru.noties.markwon.ext.tasklist.TaskListPlugin;
import ru.noties.markwon.html.HtmlPlugin;
import ru.noties.markwon.image.ImagesPlugin;
import ru.noties.markwon.image.gif.GifPlugin;
import ru.noties.markwon.image.okhttp.OkHttpImagesPlugin;
/**
* Author M M Arif
@ -122,8 +107,6 @@ public class IssuesAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
private TextView issueNumber;
private ImageView issueAssigneeAvatar;
private TextView issueTitle;
private TextView issueDescription;
//private ImageView issueState;
private TextView issueCreatedTime;
private TextView issueCommentsCount;
private ImageView issueType;
@ -135,9 +118,8 @@ public class IssuesAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
issueNumber = itemView.findViewById(R.id.issueNumber);
issueAssigneeAvatar = itemView.findViewById(R.id.assigneeAvatar);
issueTitle = itemView.findViewById(R.id.issueTitle);
issueDescription = itemView.findViewById(R.id.issueDescription);
issueCommentsCount = itemView.findViewById(R.id.issueCommentsCount);
//issueState = itemView.findViewById(R.id.issueStatus);
LinearLayout frameCommentsCount = itemView.findViewById(R.id.frameCommentsCount);
issueCreatedTime = itemView.findViewById(R.id.issueCreatedTime);
issueType = itemView.findViewById(R.id.issueType);
@ -157,7 +139,7 @@ public class IssuesAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
}
});
issueDescription.setOnClickListener(new View.OnClickListener() {
frameCommentsCount.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
@ -183,26 +165,6 @@ public class IssuesAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
final String locale = tinyDb.getString("locale");
final String timeFormat = tinyDb.getString("dateFormat");
final Markwon markwon = Markwon.builder(Objects.requireNonNull(context))
.usePlugin(CorePlugin.create())
.usePlugin(OkHttpImagesPlugin.create(new OkHttpClient()))
.usePlugin(ImagesPlugin.createWithAssets(context))
.usePlugin(new AbstractMarkwonPlugin() {
@Override
public void configureTheme(@NonNull MarkwonTheme.Builder builder) {
builder
.codeTextColor(tinyDb.getInt("codeBlockColor"))
.codeBackgroundColor(tinyDb.getInt("codeBlockBackground"))
.linkColor(context.getResources().getColor(R.color.lightBlue));
}
})
.usePlugin(TablePlugin.create(context))
.usePlugin(TaskListPlugin.create(context))
.usePlugin(HtmlPlugin.create())
.usePlugin(GifPlugin.create())
.usePlugin(StrikethroughPlugin.create())
.build();
if (!issuesModel.getUser().getFull_name().equals("")) {
issueAssigneeAvatar.setOnClickListener(new ClickListener(context.getResources().getString(R.string.issueCreator) + issuesModel.getUser().getFull_name(), context));
} else {
@ -210,9 +172,9 @@ public class IssuesAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
}
if (issuesModel.getUser().getAvatar_url() != null) {
Picasso.get().load(issuesModel.getUser().getAvatar_url()).transform(new RoundedTransformation(100, 0)).resize(200, 200).centerCrop().into(issueAssigneeAvatar);
Picasso.get().load(issuesModel.getUser().getAvatar_url()).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(issueAssigneeAvatar);
} else {
Picasso.get().load(issuesModel.getUser().getAvatar_url()).transform(new RoundedTransformation(100, 0)).resize(200, 200).centerCrop().into(issueAssigneeAvatar);
Picasso.get().load(issuesModel.getUser().getAvatar_url()).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(issueAssigneeAvatar);
}
if (issuesModel.getPull_request() == null) {
@ -223,28 +185,12 @@ public class IssuesAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
issueType.setOnClickListener(new ClickListener(context.getResources().getString(R.string.issueTypePullRequest), context));
}
issueTitle.setText(context.getResources().getString(R.string.hash) + issuesModel.getNumber() + " " + issuesModel.getTitle());
String issueNumber_ = "<font color='" + context.getResources().getColor(R.color.lightGray) + "'>" + context.getResources().getString(R.string.hash) + issuesModel.getNumber() + "</font>";
issueTitle.setText(Html.fromHtml(issueNumber_ + " " + issuesModel.getTitle()));
issueNumber.setText(String.valueOf(issuesModel.getNumber()));
issueCommentsCount.setText(String.valueOf(issuesModel.getComments()));
if (!issuesModel.getBody().equals("")) {
String cleanIssueDescription = issuesModel.getBody().trim();
issueDescription.setVisibility(View.VISIBLE);
final CharSequence bodyWithMD = markwon.toMarkdown(EmojiParser.parseToUnicode(cleanIssueDescription));
issueDescription.setText(UserMentions.UserMentionsFunc(context, bodyWithMD, cleanIssueDescription));
}
else {
issueDescription.setText("");
issueDescription.setVisibility(View.GONE);
}
/*if (issuesModel.getState().equals("open")) {
issueState.setImageResource(R.drawable.ic_issue_open);
issueState.setOnClickListener(new ClickListener(context.getResources().getString(R.string.issueStatusTextOpen), context));
} else {
issueState.setImageResource(R.drawable.ic_issue_closed);
issueState.setOnClickListener(new ClickListener(context.getResources().getString(R.string.issueStatusTextClosed), context));
}*/
switch (timeFormat) {
case "pretty": {
PrettyTime prettyTime = new PrettyTime(new Locale(locale));

View File

@ -3,7 +3,6 @@ package org.mian.gitnex.adapters;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
@ -42,13 +41,12 @@ public class LabelsAdapter extends RecyclerView.Adapter<LabelsAdapter.LabelsView
private TextView labelId;
private TextView labelColor;
private ImageView labelsView;
private ImageView labelsOptionsMenu;
private LabelsViewHolder(View itemView) {
super(itemView);
labelsView = itemView.findViewById(R.id.labelsView);
labelsOptionsMenu = itemView.findViewById(R.id.labelsOptionsMenu);
ImageView labelsOptionsMenu = itemView.findViewById(R.id.labelsOptionsMenu);
labelTitle = itemView.findViewById(R.id.labelTitle);
labelId = itemView.findViewById(R.id.labelId);
labelColor = itemView.findViewById(R.id.labelColor);
@ -146,6 +144,7 @@ public class LabelsAdapter extends RecyclerView.Adapter<LabelsAdapter.LabelsView
TextDrawable drawable = TextDrawable.builder()
.beginConfig()
//.useFont(Typeface.DEFAULT)
.bold()
.textColor(new ColorInverter().getContrastColor(color))
.fontSize(36)
.width(LabelWidthCalculator.customWidth(getMaxLabelLength()))

View File

@ -83,7 +83,7 @@ public class MembersByOrgAdapter extends BaseAdapter implements Filterable {
private void initData(MembersByOrgAdapter.ViewHolder viewHolder, int position) {
UserInfo currentItem = membersList.get(position);
Picasso.get().load(currentItem.getAvatar()).transform(new RoundedTransformation(100, 0)).resize(200, 200).centerCrop().into(viewHolder.memberAvatar);
Picasso.get().load(currentItem.getAvatar()).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(viewHolder.memberAvatar);
if(!currentItem.getFullname().equals("")) {
viewHolder.memberName.setText(currentItem.getFullname());

View File

@ -3,12 +3,16 @@ package org.mian.gitnex.adapters;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.text.Spanned;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.amulyakhare.textdrawable.TextDrawable;
import com.vdurmont.emoji.EmojiParser;
@ -21,25 +25,31 @@ import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;
import okhttp3.OkHttpClient;
import ru.noties.markwon.AbstractMarkwonPlugin;
import ru.noties.markwon.Markwon;
import ru.noties.markwon.core.CorePlugin;
import ru.noties.markwon.core.MarkwonTheme;
import ru.noties.markwon.ext.strikethrough.StrikethroughPlugin;
import ru.noties.markwon.ext.tables.TablePlugin;
import ru.noties.markwon.ext.tables.TableTheme;
import ru.noties.markwon.ext.tasklist.TaskListPlugin;
import ru.noties.markwon.html.HtmlPlugin;
import ru.noties.markwon.image.ImagesPlugin;
import ru.noties.markwon.image.gif.GifPlugin;
import ru.noties.markwon.image.okhttp.OkHttpImagesPlugin;
import io.noties.markwon.AbstractMarkwonPlugin;
import io.noties.markwon.Markwon;
import io.noties.markwon.core.CorePlugin;
import io.noties.markwon.core.MarkwonTheme;
import io.noties.markwon.ext.strikethrough.StrikethroughPlugin;
import io.noties.markwon.ext.tables.TablePlugin;
import io.noties.markwon.ext.tasklist.TaskListPlugin;
import io.noties.markwon.html.HtmlPlugin;
import io.noties.markwon.image.AsyncDrawable;
import io.noties.markwon.image.DefaultMediaDecoder;
import io.noties.markwon.image.ImageItem;
import io.noties.markwon.image.ImagesPlugin;
import io.noties.markwon.image.SchemeHandler;
import io.noties.markwon.image.gif.GifMediaDecoder;
import io.noties.markwon.image.svg.SvgMediaDecoder;
import io.noties.markwon.linkify.LinkifyPlugin;
/**
* Author M M Arif
@ -59,6 +69,7 @@ public class MilestonesAdapter extends RecyclerView.Adapter<MilestonesAdapter.Mi
private TextView msClosedIssues;
private TextView msDueDate;
private ImageView msStatus;
private ProgressBar msProgress;
private MilestonesViewHolder(View itemView) {
super(itemView);
@ -69,8 +80,9 @@ public class MilestonesAdapter extends RecyclerView.Adapter<MilestonesAdapter.Mi
msOpenIssues = itemView.findViewById(R.id.milestoneIssuesOpen);
msClosedIssues = itemView.findViewById(R.id.milestoneIssuesClosed);
msDueDate = itemView.findViewById(R.id.milestoneDueDate);
msProgress = itemView.findViewById(R.id.milestoneProgress);
/*issueTitle.setOnClickListener(new View.OnClickListener() {
/*msTitle.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
@ -113,8 +125,45 @@ public class MilestonesAdapter extends RecyclerView.Adapter<MilestonesAdapter.Mi
final Markwon markwon = Markwon.builder(Objects.requireNonNull(mCtx))
.usePlugin(CorePlugin.create())
.usePlugin(OkHttpImagesPlugin.create(new OkHttpClient()))
.usePlugin(ImagesPlugin.createWithAssets(mCtx))
.usePlugin(ImagesPlugin.create(new ImagesPlugin.ImagesConfigure() {
@Override
public void configureImages(@NonNull ImagesPlugin plugin) {
plugin.addSchemeHandler(new SchemeHandler() {
@NonNull
@Override
public ImageItem handle(@NonNull String raw, @NonNull Uri uri) {
final int resourceId = mCtx.getResources().getIdentifier(
raw.substring("drawable://".length()),
"drawable",
mCtx.getPackageName());
final Drawable drawable = mCtx.getDrawable(resourceId);
assert drawable != null;
return ImageItem.withResult(drawable);
}
@NonNull
@Override
public Collection<String> supportedSchemes() {
return Collections.singleton("drawable");
}
});
plugin.placeholderProvider(new ImagesPlugin.PlaceholderProvider() {
@Nullable
@Override
public Drawable providePlaceholder(@NonNull AsyncDrawable drawable) {
return null;
}
});
plugin.addMediaDecoder(GifMediaDecoder.create(false));
plugin.addMediaDecoder(SvgMediaDecoder.create(mCtx.getResources()));
plugin.addMediaDecoder(SvgMediaDecoder.create());
plugin.defaultMediaDecoder(DefaultMediaDecoder.create(mCtx.getResources()));
plugin.defaultMediaDecoder(DefaultMediaDecoder.create());
}
}))
.usePlugin(new AbstractMarkwonPlugin() {
@Override
public void configureTheme(@NonNull MarkwonTheme.Builder builder) {
@ -127,11 +176,12 @@ public class MilestonesAdapter extends RecyclerView.Adapter<MilestonesAdapter.Mi
.usePlugin(TablePlugin.create(mCtx))
.usePlugin(TaskListPlugin.create(mCtx))
.usePlugin(HtmlPlugin.create())
.usePlugin(GifPlugin.create())
.usePlugin(StrikethroughPlugin.create())
.usePlugin(LinkifyPlugin.create())
.build();
holder.msTitle.setText(currentItem.getTitle());
Spanned msTitle = markwon.toMarkdown(currentItem.getTitle());
markwon.setParsedMarkdown(holder.msTitle, msTitle);
//holder.msStatus.setText(currentItem.getState());
if(currentItem.getState().equals("open")) {
@ -183,6 +233,24 @@ public class MilestonesAdapter extends RecyclerView.Adapter<MilestonesAdapter.Mi
holder.msClosedIssues.setText(String.valueOf(currentItem.getClosed_issues()));
holder.msClosedIssues.setOnClickListener(new ClickListener(mCtx.getResources().getString(R.string.milestoneClosedIssues, currentItem.getClosed_issues()), mCtx));
if ((currentItem.getOpen_issues() + currentItem.getClosed_issues()) > 0) {
if (currentItem.getOpen_issues() == 0) {
holder.msProgress.setProgress(100);
holder.msProgress.setOnClickListener(new ClickListener(mCtx.getResources().getString(R.string.milestoneCompletion, 100), mCtx));
}
else {
int msCompletion = 100 * currentItem.getClosed_issues() / (currentItem.getOpen_issues() + currentItem.getClosed_issues());
holder.msProgress.setOnClickListener(new ClickListener(mCtx.getResources().getString(R.string.milestoneCompletion, msCompletion), mCtx));
holder.msProgress.setProgress(msCompletion);
}
}
else {
holder.msProgress.setProgress(0);
holder.msProgress.setOnClickListener(new ClickListener(mCtx.getResources().getString(R.string.milestoneCompletion, 0), mCtx));
}
if(currentItem.getDue_on() != null) {
if (timeFormat.equals("normal") || timeFormat.equals("pretty")) {
@ -216,7 +284,7 @@ public class MilestonesAdapter extends RecyclerView.Adapter<MilestonesAdapter.Mi
}
else {
holder.msDueDate.setVisibility(View.INVISIBLE);
holder.msDueDate.setVisibility(View.GONE);
}
}

View File

@ -4,6 +4,7 @@ import android.content.Context;
import android.content.Intent;
import android.graphics.Typeface;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Filter;
@ -12,13 +13,21 @@ import android.widget.ImageView;
import android.widget.TextView;
import com.amulyakhare.textdrawable.TextDrawable;
import com.amulyakhare.textdrawable.util.ColorGenerator;
import com.squareup.picasso.Picasso;
import org.mian.gitnex.R;
import org.mian.gitnex.activities.OpenRepoInBrowserActivity;
import org.mian.gitnex.activities.RepoDetailActivity;
import org.mian.gitnex.activities.RepoStargazersActivity;
import org.mian.gitnex.activities.RepoWatchersActivity;
import org.mian.gitnex.helpers.RoundedTransformation;
import org.mian.gitnex.models.UserRepositories;
import org.mian.gitnex.util.TinyDB;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import androidx.annotation.NonNull;
import androidx.appcompat.view.ContextThemeWrapper;
import androidx.appcompat.widget.PopupMenu;
import androidx.recyclerview.widget.RecyclerView;
/**
@ -39,7 +48,7 @@ public class MyReposListAdapter extends RecyclerView.Adapter<MyReposListAdapter.
private TextView fullNameMy;
private ImageView repoPrivatePublicMy;
private TextView repoStarsMy;
private TextView repoWatchersMy;
private TextView repoForksMy;
private TextView repoOpenIssuesCountMy;
private MyReposViewHolder(View itemView) {
@ -50,8 +59,9 @@ public class MyReposListAdapter extends RecyclerView.Adapter<MyReposListAdapter.
fullNameMy = itemView.findViewById(R.id.repoFullNameMy);
repoPrivatePublicMy = itemView.findViewById(R.id.imageRepoTypeMy);
repoStarsMy = itemView.findViewById(R.id.repoStarsMy);
repoWatchersMy = itemView.findViewById(R.id.repoWatchersMy);
repoForksMy = itemView.findViewById(R.id.repoForksMy);
repoOpenIssuesCountMy = itemView.findViewById(R.id.repoOpenIssuesCountMy);
ImageView reposDropdownMenu = itemView.findViewById(R.id.reposDropdownMenu);
itemView.setOnClickListener(new View.OnClickListener() {
@Override
@ -70,6 +80,69 @@ public class MyReposListAdapter extends RecyclerView.Adapter<MyReposListAdapter.
}
});
reposDropdownMenu.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
final Context context = v.getContext();
Context context_ = new ContextThemeWrapper(context, R.style.popupMenuStyle);
PopupMenu popupMenu = new PopupMenu(context_, v);
popupMenu.inflate(R.menu.repo_dotted_list_menu);
Object menuHelper;
Class[] argTypes;
try {
Field fMenuHelper = PopupMenu.class.getDeclaredField("mPopup");
fMenuHelper.setAccessible(true);
menuHelper = fMenuHelper.get(popupMenu);
argTypes = new Class[] { boolean.class };
menuHelper.getClass().getDeclaredMethod("setForceShowIcon",
argTypes).invoke(menuHelper, true);
} catch (Exception e) {
popupMenu.show();
return;
}
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case R.id.repoStargazers:
Intent intent = new Intent(context, RepoStargazersActivity.class);
intent.putExtra("repoFullNameForStars", fullNameMy.getText());
context.startActivity(intent);
break;
case R.id.repoWatchers:
Intent intentW = new Intent(context, RepoWatchersActivity.class);
intentW.putExtra("repoFullNameForWatchers", fullNameMy.getText());
context.startActivity(intentW);
break;
case R.id.repoOpenInBrowser:
Intent intentOpenInBrowser = new Intent(context, OpenRepoInBrowserActivity.class);
intentOpenInBrowser.putExtra("repoFullNameBrowser", fullNameMy.getText());
context.startActivity(intentOpenInBrowser);
break;
}
return false;
}
});
popupMenu.show();
}
});
}
}
@ -94,19 +167,29 @@ public class MyReposListAdapter extends RecyclerView.Adapter<MyReposListAdapter.
ColorGenerator generator = ColorGenerator.MATERIAL;
int color = generator.getColor(currentItem.getName());
String charac = String.valueOf(currentItem.getName().charAt(0));
String firstCharacter = String.valueOf(currentItem.getName().charAt(0));
TextDrawable drawable = TextDrawable.builder()
.beginConfig()
.useFont(Typeface.DEFAULT)
.fontSize(16)
.fontSize(18)
.toUpperCase()
.width(28)
.height(28)
.endConfig()
.buildRound(charac, color);
.buildRoundRect(firstCharacter, color, 3);
if (currentItem.getAvatar_url() != null) {
if (!currentItem.getAvatar_url().equals("")) {
Picasso.get().load(currentItem.getAvatar_url()).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(holder.imageMy);
} else {
holder.imageMy.setImageDrawable(drawable);
}
}
else {
holder.imageMy.setImageDrawable(drawable);
}
holder.imageMy.setImageDrawable(drawable);
holder.mTextView1My.setText(currentItem.getName());
if (!currentItem.getDescription().equals("")) {
holder.mTextView2My.setVisibility(View.VISIBLE);
@ -120,7 +203,7 @@ public class MyReposListAdapter extends RecyclerView.Adapter<MyReposListAdapter.
holder.repoPrivatePublicMy.setImageResource(R.drawable.ic_public);
}
holder.repoStarsMy.setText(currentItem.getStars_count());
holder.repoWatchersMy.setText(currentItem.getWatchers_count());
holder.repoForksMy.setText(currentItem.getForks_count());
holder.repoOpenIssuesCountMy.setText(currentItem.getOpen_issues_count());
}

View File

@ -76,11 +76,10 @@ public class OrganizationsListAdapter extends RecyclerView.Adapter<Organizations
@Override
public void onBindViewHolder(@NonNull OrganizationsViewHolder holder, int position) {
UserOrganizations currentItem = orgList.get(position);
holder.mTextView2.setVisibility(View.GONE);
Picasso.get().load(currentItem.getAvatar_url()).transform(new RoundedTransformation(100, 0)).resize(200, 200).centerCrop().into(holder.image);
Picasso.get().load(currentItem.getAvatar_url()).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(holder.image);
holder.mTextView1.setText(currentItem.getUsername());
if (!currentItem.getDescription().equals("")) {
holder.mTextView2.setVisibility(View.VISIBLE);

View File

@ -65,7 +65,7 @@ public class ProfileFollowersAdapter extends RecyclerView.Adapter<ProfileFollowe
holder.userName.setVisibility(View.GONE);
}
Picasso.get().load(currentItem.getAvatar()).transform(new RoundedTransformation(100, 0)).resize(140, 140).centerCrop().into(holder.userAvatar);
Picasso.get().load(currentItem.getAvatar()).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(holder.userAvatar);
}
@Override

View File

@ -65,7 +65,7 @@ public class ProfileFollowingAdapter extends RecyclerView.Adapter<ProfileFollowi
holder.userName.setVisibility(View.GONE);
}
Picasso.get().load(currentItem.getAvatar()).transform(new RoundedTransformation(100, 0)).resize(140, 140).centerCrop().into(holder.userAvatar);
Picasso.get().load(currentItem.getAvatar()).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(holder.userAvatar);
}
@Override

View File

@ -1,7 +1,11 @@
package org.mian.gitnex.adapters;
import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.text.Html;
import android.text.Spanned;
import android.text.method.LinkMovementMethod;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@ -11,22 +15,30 @@ import com.amulyakhare.textdrawable.TextDrawable;
import com.vdurmont.emoji.EmojiParser;
import org.mian.gitnex.R;
import org.mian.gitnex.models.Releases;
import org.mian.gitnex.util.TinyDB;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;
import okhttp3.OkHttpClient;
import ru.noties.markwon.AbstractMarkwonPlugin;
import ru.noties.markwon.Markwon;
import ru.noties.markwon.core.CorePlugin;
import ru.noties.markwon.core.MarkwonTheme;
import ru.noties.markwon.ext.strikethrough.StrikethroughPlugin;
import ru.noties.markwon.ext.tables.TablePlugin;
import ru.noties.markwon.ext.tasklist.TaskListPlugin;
import ru.noties.markwon.html.HtmlPlugin;
import ru.noties.markwon.image.ImagesPlugin;
import ru.noties.markwon.image.gif.GifPlugin;
import ru.noties.markwon.image.okhttp.OkHttpImagesPlugin;
import io.noties.markwon.AbstractMarkwonPlugin;
import io.noties.markwon.Markwon;
import io.noties.markwon.core.CorePlugin;
import io.noties.markwon.core.MarkwonTheme;
import io.noties.markwon.ext.strikethrough.StrikethroughPlugin;
import io.noties.markwon.ext.tables.TablePlugin;
import io.noties.markwon.ext.tasklist.TaskListPlugin;
import io.noties.markwon.html.HtmlPlugin;
import io.noties.markwon.image.AsyncDrawable;
import io.noties.markwon.image.DefaultMediaDecoder;
import io.noties.markwon.image.ImageItem;
import io.noties.markwon.image.ImagesPlugin;
import io.noties.markwon.image.SchemeHandler;
import io.noties.markwon.image.gif.GifMediaDecoder;
import io.noties.markwon.image.svg.SvgMediaDecoder;
import io.noties.markwon.linkify.LinkifyPlugin;
/**
* Author M M Arif
@ -75,6 +87,8 @@ public class ReleasesAdapter extends RecyclerView.Adapter<ReleasesAdapter.Releas
@Override
public void onBindViewHolder(@NonNull ReleasesAdapter.ReleasesViewHolder holder, int position) {
final TinyDB tinyDb = new TinyDB(mCtx);
Releases currentItem = releasesList.get(position);
holder.releaseTitle.setText(currentItem.getName());
@ -113,34 +127,77 @@ public class ReleasesAdapter extends RecyclerView.Adapter<ReleasesAdapter.Releas
final Markwon markwon = Markwon.builder(Objects.requireNonNull(mCtx))
.usePlugin(CorePlugin.create())
.usePlugin(OkHttpImagesPlugin.create(new OkHttpClient()))
.usePlugin(ImagesPlugin.createWithAssets(mCtx))
.usePlugin(ImagesPlugin.create(new ImagesPlugin.ImagesConfigure() {
@Override
public void configureImages(@NonNull ImagesPlugin plugin) {
plugin.addSchemeHandler(new SchemeHandler() {
@NonNull
@Override
public ImageItem handle(@NonNull String raw, @NonNull Uri uri) {
final int resourceId = mCtx.getResources().getIdentifier(
raw.substring("drawable://".length()),
"drawable",
mCtx.getPackageName());
final Drawable drawable = mCtx.getDrawable(resourceId);
assert drawable != null;
return ImageItem.withResult(drawable);
}
@NonNull
@Override
public Collection<String> supportedSchemes() {
return Collections.singleton("drawable");
}
});
plugin.placeholderProvider(new ImagesPlugin.PlaceholderProvider() {
@Nullable
@Override
public Drawable providePlaceholder(@NonNull AsyncDrawable drawable) {
return null;
}
});
plugin.addMediaDecoder(GifMediaDecoder.create(false));
plugin.addMediaDecoder(SvgMediaDecoder.create(mCtx.getResources()));
plugin.addMediaDecoder(SvgMediaDecoder.create());
plugin.defaultMediaDecoder(DefaultMediaDecoder.create(mCtx.getResources()));
plugin.defaultMediaDecoder(DefaultMediaDecoder.create());
}
}))
.usePlugin(new AbstractMarkwonPlugin() {
@Override
public void configureTheme(@NonNull MarkwonTheme.Builder builder) {
builder
.codeTextColor(Color.GREEN)
.codeBackgroundColor(Color.BLACK)
.codeTextColor(tinyDb.getInt("codeBlockColor"))
.codeBackgroundColor(tinyDb.getInt("codeBlockBackground"))
.linkColor(mCtx.getResources().getColor(R.color.lightBlue));
}
})
.usePlugin(TablePlugin.create(mCtx))
.usePlugin(TaskListPlugin.create(mCtx))
.usePlugin(HtmlPlugin.create())
.usePlugin(GifPlugin.create())
.usePlugin(StrikethroughPlugin.create())
.usePlugin(LinkifyPlugin.create())
.build();
final CharSequence bodyWithMD = markwon.toMarkdown(EmojiParser.parseToUnicode(currentItem.getBody()));
Spanned bodyWithMD = markwon.toMarkdown(EmojiParser.parseToUnicode(currentItem.getBody()));
if(!currentItem.getBody().equals("")) {
holder.releaseDescription.setText(bodyWithMD);
markwon.setParsedMarkdown(holder.releaseDescription, bodyWithMD);
}
else {
holder.releaseDescription.setVisibility(View.GONE);
}
holder.releaseZipDownload.setText(currentItem.getZipball_url());
holder.releaseTarDownload.setText(currentItem.getTarball_url());
holder.releaseZipDownload.setText(
Html.fromHtml("<a href='" + currentItem.getZipball_url() + "'>" + mCtx.getResources().getString(R.string.zipArchiveDownloadReleasesTab) + "</a> "));
holder.releaseZipDownload.setMovementMethod(LinkMovementMethod.getInstance());
holder.releaseTarDownload.setText(
Html.fromHtml("<a href='" + currentItem.getTarball_url() + "'>" + mCtx.getResources().getString(R.string.tarArchiveDownloadReleasesTab) + "</a> "));
holder.releaseTarDownload.setMovementMethod(LinkMovementMethod.getInstance());
}

View File

@ -0,0 +1,91 @@
package org.mian.gitnex.adapters;
import android.annotation.SuppressLint;
import android.content.Context;
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 com.squareup.picasso.Picasso;
import org.mian.gitnex.R;
import org.mian.gitnex.helpers.RoundedTransformation;
import org.mian.gitnex.models.UserInfo;
import java.util.List;
/**
* Author M M Arif
*/
public class RepoStargazersAdapter extends BaseAdapter {
private List<UserInfo> stargazersList;
private Context mCtx;
private class ViewHolder {
private ImageView memberAvatar;
private TextView memberName;
ViewHolder(View v) {
memberAvatar = v.findViewById(R.id.memberAvatar);
memberName = v.findViewById(R.id.memberName);
}
}
public RepoStargazersAdapter(Context mCtx, List<UserInfo> membersListMain) {
this.mCtx = mCtx;
this.stargazersList = membersListMain;
}
@Override
public int getCount() {
return stargazersList.size();
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return 0;
}
@SuppressLint("InflateParams")
@Override
public View getView(int position, View finalView, ViewGroup parent) {
RepoStargazersAdapter.ViewHolder viewHolder;
if (finalView == null) {
finalView = LayoutInflater.from(mCtx).inflate(R.layout.repo_stargazers_list, null);
viewHolder = new RepoStargazersAdapter.ViewHolder(finalView);
finalView.setTag(viewHolder);
}
else {
viewHolder = (RepoStargazersAdapter.ViewHolder) finalView.getTag();
}
initData(viewHolder, position);
return finalView;
}
private void initData(RepoStargazersAdapter.ViewHolder viewHolder, int position) {
UserInfo currentItem = stargazersList.get(position);
Picasso.get().load(currentItem.getAvatar()).transform(new RoundedTransformation(8, 0)).resize(180, 180).centerCrop().into(viewHolder.memberAvatar);
if(!currentItem.getFullname().equals("")) {
viewHolder.memberName.setText(currentItem.getFullname());
}
else {
viewHolder.memberName.setText(currentItem.getLogin());
}
}
}

View File

@ -0,0 +1,91 @@
package org.mian.gitnex.adapters;
import android.annotation.SuppressLint;
import android.content.Context;
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 com.squareup.picasso.Picasso;
import org.mian.gitnex.R;
import org.mian.gitnex.helpers.RoundedTransformation;
import org.mian.gitnex.models.UserInfo;
import java.util.List;
/**
* Author M M Arif
*/
public class RepoWatchersAdapter extends BaseAdapter {
private List<UserInfo> watchersList;
private Context mCtx;
private class ViewHolder {
private ImageView memberAvatar;
private TextView memberName;
ViewHolder(View v) {
memberAvatar = v.findViewById(R.id.memberAvatar);
memberName = v.findViewById(R.id.memberName);
}
}
public RepoWatchersAdapter(Context mCtx, List<UserInfo> membersListMain) {
this.mCtx = mCtx;
this.watchersList = membersListMain;
}
@Override
public int getCount() {
return watchersList.size();
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return 0;
}
@SuppressLint("InflateParams")
@Override
public View getView(int position, View finalView, ViewGroup parent) {
RepoWatchersAdapter.ViewHolder viewHolder;
if (finalView == null) {
finalView = LayoutInflater.from(mCtx).inflate(R.layout.repo_watchers_list, null);
viewHolder = new RepoWatchersAdapter.ViewHolder(finalView);
finalView.setTag(viewHolder);
}
else {
viewHolder = (RepoWatchersAdapter.ViewHolder) finalView.getTag();
}
initData(viewHolder, position);
return finalView;
}
private void initData(RepoWatchersAdapter.ViewHolder viewHolder, int position) {
UserInfo currentItem = watchersList.get(position);
Picasso.get().load(currentItem.getAvatar()).transform(new RoundedTransformation(8, 0)).resize(180, 180).centerCrop().into(viewHolder.memberAvatar);
if(!currentItem.getFullname().equals("")) {
viewHolder.memberName.setText(currentItem.getFullname());
}
else {
viewHolder.memberName.setText(currentItem.getLogin());
}
}
}

View File

@ -4,8 +4,11 @@ import android.content.Context;
import android.content.Intent;
import android.graphics.Typeface;
import androidx.annotation.NonNull;
import androidx.appcompat.view.ContextThemeWrapper;
import androidx.appcompat.widget.PopupMenu;
import androidx.recyclerview.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Filter;
@ -14,10 +17,16 @@ import android.widget.ImageView;
import android.widget.TextView;
import com.amulyakhare.textdrawable.TextDrawable;
import com.amulyakhare.textdrawable.util.ColorGenerator;
import com.squareup.picasso.Picasso;
import org.mian.gitnex.R;
import org.mian.gitnex.activities.OpenRepoInBrowserActivity;
import org.mian.gitnex.activities.RepoDetailActivity;
import org.mian.gitnex.activities.RepoStargazersActivity;
import org.mian.gitnex.activities.RepoWatchersActivity;
import org.mian.gitnex.helpers.RoundedTransformation;
import org.mian.gitnex.models.UserRepositories;
import org.mian.gitnex.util.TinyDB;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
@ -39,10 +48,11 @@ public class ReposListAdapter extends RecyclerView.Adapter<ReposListAdapter.Repo
private TextView fullName;
private ImageView repoPrivatePublic;
private TextView repoStars;
private TextView repoWatchers;
private TextView repoForks;
private TextView repoOpenIssuesCount;
private ReposViewHolder(View itemView) {
super(itemView);
mTextView1 = itemView.findViewById(R.id.repoName);
mTextView2 = itemView.findViewById(R.id.repoDescription);
@ -50,15 +60,16 @@ public class ReposListAdapter extends RecyclerView.Adapter<ReposListAdapter.Repo
fullName = itemView.findViewById(R.id.repoFullName);
repoPrivatePublic = itemView.findViewById(R.id.imageRepoType);
repoStars = itemView.findViewById(R.id.repoStars);
repoWatchers = itemView.findViewById(R.id.repoWatchers);
repoForks = itemView.findViewById(R.id.repoForks);
repoOpenIssuesCount = itemView.findViewById(R.id.repoOpenIssuesCount);
ImageView reposDropdownMenu = itemView.findViewById(R.id.reposDropdownMenu);
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Context context = v.getContext();
TextView repoFullName = (TextView) v.findViewById(R.id.repoFullName);
TextView repoFullName = v.findViewById(R.id.repoFullName);
Intent intent = new Intent(context, RepoDetailActivity.class);
intent.putExtra("repoFullName", repoFullName.getText().toString());
@ -70,6 +81,70 @@ public class ReposListAdapter extends RecyclerView.Adapter<ReposListAdapter.Repo
}
});
reposDropdownMenu.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
final Context context = v.getContext();
Context context_ = new ContextThemeWrapper(context, R.style.popupMenuStyle);
PopupMenu popupMenu = new PopupMenu(context_, v);
popupMenu.inflate(R.menu.repo_dotted_list_menu);
Object menuHelper;
Class[] argTypes;
try {
Field fMenuHelper = PopupMenu.class.getDeclaredField("mPopup");
fMenuHelper.setAccessible(true);
menuHelper = fMenuHelper.get(popupMenu);
argTypes = new Class[] { boolean.class };
menuHelper.getClass().getDeclaredMethod("setForceShowIcon",
argTypes).invoke(menuHelper, true);
} catch (Exception e) {
popupMenu.show();
return;
}
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case R.id.repoStargazers:
Intent intent = new Intent(context, RepoStargazersActivity.class);
intent.putExtra("repoFullNameForStars", fullName.getText());
context.startActivity(intent);
break;
case R.id.repoWatchers:
Intent intentW = new Intent(context, RepoWatchersActivity.class);
intentW.putExtra("repoFullNameForWatchers", fullName.getText());
context.startActivity(intentW);
break;
case R.id.repoOpenInBrowser:
Intent intentOpenInBrowser = new Intent(context, OpenRepoInBrowserActivity.class);
intentOpenInBrowser.putExtra("repoFullNameBrowser", fullName.getText());
context.startActivity(intentOpenInBrowser);
break;
}
return false;
}
});
popupMenu.show();
}
});
}
}
@ -94,19 +169,29 @@ public class ReposListAdapter extends RecyclerView.Adapter<ReposListAdapter.Repo
ColorGenerator generator = ColorGenerator.MATERIAL;
int color = generator.getColor(currentItem.getName());
String charac = String.valueOf(currentItem.getName().charAt(0));
String firstCharacter = String.valueOf(currentItem.getName().charAt(0));
TextDrawable drawable = TextDrawable.builder()
.beginConfig()
.useFont(Typeface.DEFAULT)
.fontSize(16)
.fontSize(18)
.toUpperCase()
.width(28)
.height(28)
.endConfig()
.buildRound(charac, color);
.buildRoundRect(firstCharacter, color, 3);
if (currentItem.getAvatar_url() != null) {
if (!currentItem.getAvatar_url().equals("")) {
Picasso.get().load(currentItem.getAvatar_url()).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(holder.image);
} else {
holder.image.setImageDrawable(drawable);
}
}
else {
holder.image.setImageDrawable(drawable);
}
holder.image.setImageDrawable(drawable);
holder.mTextView1.setText(currentItem.getName());
if (!currentItem.getDescription().equals("")) {
holder.mTextView2.setVisibility(View.VISIBLE);
@ -120,7 +205,7 @@ public class ReposListAdapter extends RecyclerView.Adapter<ReposListAdapter.Repo
holder.repoPrivatePublic.setImageResource(R.drawable.ic_public);
}
holder.repoStars.setText(currentItem.getStars_count());
holder.repoWatchers.setText(currentItem.getWatchers_count());
holder.repoForks.setText(currentItem.getForks_count());
holder.repoOpenIssuesCount.setText(currentItem.getOpen_issues_count());
}

View File

@ -4,6 +4,7 @@ import android.content.Context;
import android.content.Intent;
import android.graphics.Typeface;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Filter;
@ -12,13 +13,21 @@ import android.widget.ImageView;
import android.widget.TextView;
import com.amulyakhare.textdrawable.TextDrawable;
import com.amulyakhare.textdrawable.util.ColorGenerator;
import com.squareup.picasso.Picasso;
import org.mian.gitnex.R;
import org.mian.gitnex.activities.OpenRepoInBrowserActivity;
import org.mian.gitnex.activities.RepoDetailActivity;
import org.mian.gitnex.activities.RepoStargazersActivity;
import org.mian.gitnex.activities.RepoWatchersActivity;
import org.mian.gitnex.helpers.RoundedTransformation;
import org.mian.gitnex.models.UserRepositories;
import org.mian.gitnex.util.TinyDB;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import androidx.annotation.NonNull;
import androidx.appcompat.view.ContextThemeWrapper;
import androidx.appcompat.widget.PopupMenu;
import androidx.recyclerview.widget.RecyclerView;
/**
@ -39,7 +48,7 @@ public class RepositoriesByOrgAdapter extends RecyclerView.Adapter<RepositoriesB
private TextView fullName;
private ImageView repoPrivatePublic;
private TextView repoStars;
private TextView repoWatchers;
private TextView repoForks;
private TextView repoOpenIssuesCount;
private OrgReposViewHolder(View itemView) {
@ -50,8 +59,9 @@ public class RepositoriesByOrgAdapter extends RecyclerView.Adapter<RepositoriesB
fullName = itemView.findViewById(R.id.repoFullName);
repoPrivatePublic = itemView.findViewById(R.id.imageRepoType);
repoStars = itemView.findViewById(R.id.repoStars);
repoWatchers = itemView.findViewById(R.id.repoWatchers);
repoForks = itemView.findViewById(R.id.repoForks);
repoOpenIssuesCount = itemView.findViewById(R.id.repoOpenIssuesCount);
ImageView reposDropdownMenu = itemView.findViewById(R.id.reposDropdownMenu);
itemView.setOnClickListener(new View.OnClickListener() {
@Override
@ -70,6 +80,69 @@ public class RepositoriesByOrgAdapter extends RecyclerView.Adapter<RepositoriesB
}
});
reposDropdownMenu.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
final Context context = v.getContext();
Context context_ = new ContextThemeWrapper(context, R.style.popupMenuStyle);
PopupMenu popupMenu = new PopupMenu(context_, v);
popupMenu.inflate(R.menu.repo_dotted_list_menu);
Object menuHelper;
Class[] argTypes;
try {
Field fMenuHelper = PopupMenu.class.getDeclaredField("mPopup");
fMenuHelper.setAccessible(true);
menuHelper = fMenuHelper.get(popupMenu);
argTypes = new Class[] { boolean.class };
menuHelper.getClass().getDeclaredMethod("setForceShowIcon",
argTypes).invoke(menuHelper, true);
} catch (Exception e) {
popupMenu.show();
return;
}
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case R.id.repoStargazers:
Intent intent = new Intent(context, RepoStargazersActivity.class);
intent.putExtra("repoFullNameForStars", fullName.getText());
context.startActivity(intent);
break;
case R.id.repoWatchers:
Intent intentW = new Intent(context, RepoWatchersActivity.class);
intentW.putExtra("repoFullNameForWatchers", fullName.getText());
context.startActivity(intentW);
break;
case R.id.repoOpenInBrowser:
Intent intentOpenInBrowser = new Intent(context, OpenRepoInBrowserActivity.class);
intentOpenInBrowser.putExtra("repoFullNameBrowser", fullName.getText());
context.startActivity(intentOpenInBrowser);
break;
}
return false;
}
});
popupMenu.show();
}
});
}
}
@ -95,19 +168,29 @@ public class RepositoriesByOrgAdapter extends RecyclerView.Adapter<RepositoriesB
ColorGenerator generator = ColorGenerator.MATERIAL;
int color = generator.getColor(currentItem.getName());
String charac = String.valueOf(currentItem.getName().charAt(0));
String firstCharacter = String.valueOf(currentItem.getName().charAt(0));
TextDrawable drawable = TextDrawable.builder()
.beginConfig()
.useFont(Typeface.DEFAULT)
.fontSize(16)
.fontSize(18)
.toUpperCase()
.width(28)
.height(28)
.endConfig()
.buildRound(charac, color);
.buildRoundRect(firstCharacter, color, 3);
if (currentItem.getAvatar_url() != null) {
if (!currentItem.getAvatar_url().equals("")) {
Picasso.get().load(currentItem.getAvatar_url()).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(holder.image);
} else {
holder.image.setImageDrawable(drawable);
}
}
else {
holder.image.setImageDrawable(drawable);
}
holder.image.setImageDrawable(drawable);
holder.mTextView1.setText(currentItem.getName());
if (!currentItem.getDescription().equals("")) {
holder.mTextView2.setVisibility(View.VISIBLE);
@ -121,7 +204,7 @@ public class RepositoriesByOrgAdapter extends RecyclerView.Adapter<RepositoriesB
holder.repoPrivatePublic.setImageResource(R.drawable.ic_public);
}
holder.repoStars.setText(currentItem.getStars_count());
holder.repoWatchers.setText(currentItem.getWatchers_count());
holder.repoForks.setText(currentItem.getForks_count());
holder.repoOpenIssuesCount.setText(currentItem.getOpen_issues_count());
}

View File

@ -4,6 +4,7 @@ import android.content.Context;
import android.content.Intent;
import android.graphics.Typeface;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Filter;
@ -12,13 +13,21 @@ import android.widget.ImageView;
import android.widget.TextView;
import com.amulyakhare.textdrawable.TextDrawable;
import com.amulyakhare.textdrawable.util.ColorGenerator;
import com.squareup.picasso.Picasso;
import org.mian.gitnex.R;
import org.mian.gitnex.activities.OpenRepoInBrowserActivity;
import org.mian.gitnex.activities.RepoDetailActivity;
import org.mian.gitnex.activities.RepoStargazersActivity;
import org.mian.gitnex.activities.RepoWatchersActivity;
import org.mian.gitnex.helpers.RoundedTransformation;
import org.mian.gitnex.models.UserRepositories;
import org.mian.gitnex.util.TinyDB;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import androidx.annotation.NonNull;
import androidx.appcompat.view.ContextThemeWrapper;
import androidx.appcompat.widget.PopupMenu;
import androidx.recyclerview.widget.RecyclerView;
/**
@ -39,7 +48,7 @@ public class StarredReposListAdapter extends RecyclerView.Adapter<StarredReposLi
private TextView fullName;
private ImageView repoPrivatePublic;
private TextView repoStars;
private TextView repoWatchers;
private TextView repoForks;
private TextView repoOpenIssuesCount;
private StarredReposViewHolder(View itemView) {
@ -50,8 +59,9 @@ public class StarredReposListAdapter extends RecyclerView.Adapter<StarredReposLi
fullName = itemView.findViewById(R.id.repoFullName);
repoPrivatePublic = itemView.findViewById(R.id.imageRepoType);
repoStars = itemView.findViewById(R.id.repoStars);
repoWatchers = itemView.findViewById(R.id.repoWatchers);
repoForks = itemView.findViewById(R.id.repoForks);
repoOpenIssuesCount = itemView.findViewById(R.id.repoOpenIssuesCount);
ImageView reposDropdownMenu = itemView.findViewById(R.id.reposDropdownMenu);
itemView.setOnClickListener(new View.OnClickListener() {
@Override
@ -70,6 +80,69 @@ public class StarredReposListAdapter extends RecyclerView.Adapter<StarredReposLi
}
});
reposDropdownMenu.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
final Context context = v.getContext();
Context context_ = new ContextThemeWrapper(context, R.style.popupMenuStyle);
PopupMenu popupMenu = new PopupMenu(context_, v);
popupMenu.inflate(R.menu.repo_dotted_list_menu);
Object menuHelper;
Class[] argTypes;
try {
Field fMenuHelper = PopupMenu.class.getDeclaredField("mPopup");
fMenuHelper.setAccessible(true);
menuHelper = fMenuHelper.get(popupMenu);
argTypes = new Class[] { boolean.class };
menuHelper.getClass().getDeclaredMethod("setForceShowIcon",
argTypes).invoke(menuHelper, true);
} catch (Exception e) {
popupMenu.show();
return;
}
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case R.id.repoStargazers:
Intent intent = new Intent(context, RepoStargazersActivity.class);
intent.putExtra("repoFullNameForStars", fullName.getText());
context.startActivity(intent);
break;
case R.id.repoWatchers:
Intent intentW = new Intent(context, RepoWatchersActivity.class);
intentW.putExtra("repoFullNameForWatchers", fullName.getText());
context.startActivity(intentW);
break;
case R.id.repoOpenInBrowser:
Intent intentOpenInBrowser = new Intent(context, OpenRepoInBrowserActivity.class);
intentOpenInBrowser.putExtra("repoFullNameBrowser", fullName.getText());
context.startActivity(intentOpenInBrowser);
break;
}
return false;
}
});
popupMenu.show();
}
});
}
}
@ -95,19 +168,29 @@ public class StarredReposListAdapter extends RecyclerView.Adapter<StarredReposLi
ColorGenerator generator = ColorGenerator.MATERIAL;
int color = generator.getColor(currentItem.getName());
String charac = String.valueOf(currentItem.getName().charAt(0));
String firstCharacter = String.valueOf(currentItem.getName().charAt(0));
TextDrawable drawable = TextDrawable.builder()
.beginConfig()
.useFont(Typeface.DEFAULT)
.fontSize(16)
.fontSize(18)
.toUpperCase()
.width(28)
.height(28)
.endConfig()
.buildRound(charac, color);
.buildRoundRect(firstCharacter, color, 3);
if (currentItem.getAvatar_url() != null) {
if (!currentItem.getAvatar_url().equals("")) {
Picasso.get().load(currentItem.getAvatar_url()).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(holder.image);
} else {
holder.image.setImageDrawable(drawable);
}
}
else {
holder.image.setImageDrawable(drawable);
}
holder.image.setImageDrawable(drawable);
holder.mTextView1.setText(currentItem.getName());
if (!currentItem.getDescription().equals("")) {
holder.mTextView2.setVisibility(View.VISIBLE);
@ -121,7 +204,7 @@ public class StarredReposListAdapter extends RecyclerView.Adapter<StarredReposLi
holder.repoPrivatePublic.setImageResource(R.drawable.ic_public);
}
holder.repoStars.setText(currentItem.getStars_count());
holder.repoWatchers.setText(currentItem.getWatchers_count());
holder.repoForks.setText(currentItem.getForks_count());
holder.repoOpenIssuesCount.setText(currentItem.getOpen_issues_count());
}

View File

@ -78,7 +78,7 @@ public class TeamMembersByOrgAdapter extends BaseAdapter {
private void initData(TeamMembersByOrgAdapter.ViewHolder viewHolder, int position) {
UserInfo currentItem = teamMembersList.get(position);
Picasso.get().load(currentItem.getAvatar()).transform(new RoundedTransformation(100, 0)).resize(200, 200).centerCrop().into(viewHolder.memberAvatar);
Picasso.get().load(currentItem.getAvatar()).transform(new RoundedTransformation(8, 0)).resize(180, 180).centerCrop().into(viewHolder.memberAvatar);
if(!currentItem.getFullname().equals("")) {
viewHolder.memberName.setText(currentItem.getFullname());

View File

@ -141,7 +141,7 @@ public class UserSearchAdapter extends RecyclerView.Adapter<UserSearchAdapter.Us
}
if (!currentItem.getAvatar().equals("")) {
Picasso.get().load(currentItem.getAvatar()).transform(new RoundedTransformation(100, 0)).resize(200, 200).centerCrop().into(holder.userAvatar);
Picasso.get().load(currentItem.getAvatar()).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(holder.userAvatar);
}
if(getItemCount() > 0) {

View File

@ -49,6 +49,7 @@ public class AboutFragment extends Fragment {
final TextView appVerBuild;
final TextView donationLink;
final TextView donationLinkPatreon;
final TextView translateLink;
final TextView creditsButton;
final TextView sponsorsButton;
final TextView appWebsite;
@ -64,6 +65,7 @@ public class AboutFragment extends Fragment {
creditsButton = v.findViewById(R.id.creditsButton);
donationLink = v.findViewById(R.id.donationLink);
donationLinkPatreon = v.findViewById(R.id.donationLinkPatreon);
translateLink = v.findViewById(R.id.translateLink);
sponsorsButton = v.findViewById(R.id.sponsorsButton);
appWebsite = v.findViewById(R.id.appWebsite);
appRepo = v.findViewById(R.id.appRepo);
@ -90,6 +92,16 @@ public class AboutFragment extends Fragment {
}
});
translateLink.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.addCategory(Intent.CATEGORY_BROWSABLE);
intent.setData(Uri.parse(getResources().getString(R.string.crowdInLink)));
startActivity(intent);
}
});
appWebsite.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Intent intent = new Intent();

View File

@ -6,7 +6,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProviders;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
@ -125,7 +125,7 @@ public class BranchesFragment extends Fragment {
private void fetchDataAsync(String instanceUrl, String instanceToken, String owner, String repo) {
BranchesViewModel branchesModel = ViewModelProviders.of(this).get(BranchesViewModel.class);
BranchesViewModel branchesModel = new ViewModelProvider(this).get(BranchesViewModel.class);
branchesModel.getBranchesList(instanceUrl, instanceToken, owner, repo).observe(this, new Observer<List<Branches>>() {
@Override

View File

@ -263,6 +263,7 @@ public class ClosedIssuesFragment extends Fragment {
MenuItem searchItem = menu.findItem(R.id.action_search);
androidx.appcompat.widget.SearchView searchView = (androidx.appcompat.widget.SearchView) searchItem.getActionView();
searchView.setImeOptions(EditorInfo.IME_ACTION_DONE);
searchView.setQueryHint(getContext().getString(R.string.strFilter));
if(!connToInternet) {
return;

View File

@ -6,11 +6,12 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProviders;
import androidx.lifecycle.ViewModelProvider;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.GridView;
import android.widget.ProgressBar;
import android.widget.TextView;
import org.mian.gitnex.R;
import org.mian.gitnex.adapters.CollaboratorsAdapter;
@ -26,6 +27,7 @@ import java.util.List;
public class CollaboratorsFragment extends Fragment {
private ProgressBar mProgressBar;
private CollaboratorsAdapter adapter;
private GridView mGridView;
private TextView noDataCollaborators;
@ -69,6 +71,8 @@ public class CollaboratorsFragment extends Fragment {
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
noDataCollaborators = v.findViewById(R.id.noDataCollaborators);
mProgressBar = v.findViewById(R.id.progress_bar);
mGridView = v.findViewById(R.id.gridView);
fetchDataAsync(instanceUrl, Authorization.returnAuthentication(getContext(), loginUid, instanceToken), repoOwner, repoName);
@ -94,7 +98,7 @@ public class CollaboratorsFragment extends Fragment {
private void fetchDataAsync(String instanceUrl, String instanceToken, String owner, String repo) {
CollaboratorsViewModel collaboratorsModel = ViewModelProviders.of(this).get(CollaboratorsViewModel.class);
CollaboratorsViewModel collaboratorsModel = new ViewModelProvider(this).get(CollaboratorsViewModel.class);
collaboratorsModel.getCollaboratorsList(instanceUrl, instanceToken, owner, repo).observe(this, new Observer<List<Collaborators>>() {
@Override
@ -109,6 +113,7 @@ public class CollaboratorsFragment extends Fragment {
mGridView.setAdapter(adapter);
noDataCollaborators.setVisibility(View.VISIBLE);
}
mProgressBar.setVisibility(View.GONE);
}
});

View File

@ -0,0 +1,194 @@
package org.mian.gitnex.fragments;
import android.content.Context;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import org.mian.gitnex.R;
import org.mian.gitnex.activities.MainActivity;
import org.mian.gitnex.adapters.ExploreRepositoriesAdapter;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.models.ExploreRepositories;
import org.mian.gitnex.models.UserRepositories;
import org.mian.gitnex.util.AppUtil;
import org.mian.gitnex.util.TinyDB;
import java.util.List;
import java.util.Objects;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
/**
+ * Template Author M M Arif
+ * Author 6543
+ */
public class ExploreRepositoriesFragment extends Fragment {
private static String repoNameF = "param2";
private static String repoOwnerF = "param1";
private ProgressBar mProgressBar;
private RecyclerView mRecyclerView;
private TextView noData;
private TextView searchKeyword;
private Boolean repoTypeInclude = true;
private String sort = "updated";
private String order = "asc";
private ExploreRepositoriesAdapter adapter;
private OnFragmentInteractionListener mListener;
public ExploreRepositoriesFragment() {
}
public static ExploreRepositoriesFragment newInstance(String param1, String param2) {
ExploreRepositoriesFragment fragment = new ExploreRepositoriesFragment();
Bundle args = new Bundle();
args.putString(repoOwnerF, param1);
args.putString(repoNameF, param2);
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
String repoName = getArguments().getString(repoNameF);
String repoOwner = getArguments().getString(repoOwnerF);
}
}
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
boolean connToInternet = AppUtil.haveNetworkConnection(Objects.requireNonNull(getContext()));
final View v = inflater.inflate(R.layout.fragment_explore_repo, container, false);
//setHasOptionsMenu(true);
((MainActivity) Objects.requireNonNull(getActivity())).setActionBarTitle(getResources().getString(R.string.pageTitleExplore));
TinyDB tinyDb = new TinyDB(getContext());
final String instanceUrl = tinyDb.getString("instanceUrl");
final String loginUid = tinyDb.getString("loginUid");
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
searchKeyword = v.findViewById(R.id.searchKeyword);
noData = v.findViewById(R.id.noData);
mProgressBar = v.findViewById(R.id.progress_bar);
mRecyclerView = v.findViewById(R.id.recyclerViewReposSearch);
if(connToInternet) {
searchKeyword.setOnEditorActionListener(new TextView.OnEditorActionListener() {
@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if (actionId == EditorInfo.IME_ACTION_SEND) {
if(!searchKeyword.getText().toString().equals("")) {
mProgressBar.setVisibility(View.VISIBLE);
mRecyclerView.setVisibility(View.GONE);
loadSearchReposList(instanceUrl, instanceToken, loginUid, searchKeyword.getText().toString(), repoTypeInclude, sort, order, getContext());
}
}
return false;
}
});
}
else {
mProgressBar.setVisibility(View.GONE);
}
return v;
}
private void loadSearchReposList(String instanceUrl, String instanceToken, String loginUid, String searchKeyword, Boolean repoTypeInclude, String sort, String order, final Context context) {
Call<ExploreRepositories> call = RetrofitClient
.getInstance(instanceUrl)
.getApiInterface()
.queryRepos(Authorization.returnAuthentication(getContext(), loginUid, instanceToken), searchKeyword, repoTypeInclude, sort, order);
call.enqueue(new Callback<ExploreRepositories>() {
@Override
public void onResponse(@NonNull Call<ExploreRepositories> call, @NonNull Response<ExploreRepositories> response) {
if (response.isSuccessful()) {
assert response.body() != null;
getReposList(response.body().getSearchedData(), context);
} else {
Log.i("onResponse", String.valueOf(response.code()));
}
}
@Override
public void onFailure(@NonNull Call<ExploreRepositories> call, @NonNull Throwable t) {
Log.i("onFailure", t.getMessage());
}
});
}
private void getReposList(List<UserRepositories> dataList, Context context) {
adapter = new ExploreRepositoriesAdapter(dataList, context);
mRecyclerView.setVisibility(View.VISIBLE);
mRecyclerView.setHasFixedSize(true);
mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(mRecyclerView.getContext(),
DividerItemDecoration.VERTICAL);
mRecyclerView.addItemDecoration(dividerItemDecoration);
if(adapter.getItemCount() > 0) {
mRecyclerView.setAdapter(adapter);
noData.setVisibility(View.GONE);
mProgressBar.setVisibility(View.GONE);
}
else {
noData.setVisibility(View.VISIBLE);
mProgressBar.setVisibility(View.GONE);
}
}
public void onButtonPressed(Uri uri) {
if (mListener != null) {
mListener.onFragmentInteraction(uri);
}
}
@Override
public void onDetach() {
super.onDetach();
mListener = null;
}
public interface OnFragmentInteractionListener {
void onFragmentInteraction(Uri uri);
}
}

View File

@ -0,0 +1,301 @@
package org.mian.gitnex.fragments;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
import org.mian.gitnex.R;
import org.mian.gitnex.activities.FileViewActivity;
import org.mian.gitnex.adapters.FilesAdapter;
import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.models.Files;
import org.mian.gitnex.util.AppUtil;
import org.mian.gitnex.util.TinyDB;
import org.mian.gitnex.viewmodels.FilesViewModel;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import moe.feng.common.view.breadcrumbs.BreadcrumbsView;
import moe.feng.common.view.breadcrumbs.DefaultBreadcrumbsCallback;
import moe.feng.common.view.breadcrumbs.model.BreadcrumbItem;
/**
* Author M M Arif
*/
public class FilesFragment extends Fragment implements FilesAdapter.FilesAdapterListener {
private ProgressBar mProgressBar;
private FilesAdapter adapter;
private RecyclerView mRecyclerView;
private TextView noDataFiles;
private LinearLayout filesFrame;
private TextView fileStructure;
private static String repoNameF = "param2";
private static String repoOwnerF = "param1";
private BreadcrumbsView mBreadcrumbsView;
private String repoName;
private String repoOwner;
private OnFragmentInteractionListener mListener;
public FilesFragment() {
}
public static FilesFragment newInstance(String param1, String param2) {
FilesFragment fragment = new FilesFragment();
Bundle args = new Bundle();
args.putString(repoOwnerF, param1);
args.putString(repoNameF, param2);
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
repoName = getArguments().getString(repoNameF);
repoOwner = getArguments().getString(repoOwnerF);
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_files, container, false);
setHasOptionsMenu(true);
TinyDB tinyDb = new TinyDB(getContext());
final String instanceUrl = tinyDb.getString("instanceUrl");
final String loginUid = tinyDb.getString("loginUid");
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
noDataFiles = v.findViewById(R.id.noDataFiles);
filesFrame = v.findViewById(R.id.filesFrame);
fileStructure = v.findViewById(R.id.fileStructure);
mRecyclerView = v.findViewById(R.id.recyclerView);
mRecyclerView.setHasFixedSize(true);
mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(mRecyclerView.getContext(),
DividerItemDecoration.VERTICAL);
mRecyclerView.addItemDecoration(dividerItemDecoration);
mProgressBar = v.findViewById(R.id.progress_bar);
mBreadcrumbsView = v.findViewById(R.id.breadcrumbs_view);
mBreadcrumbsView.setItems(new ArrayList<>(Arrays.asList(
BreadcrumbItem.createSimpleItem(getResources().getString(R.string.filesBreadcrumbRoot))
)));
fetchDataAsync(instanceUrl, Authorization.returnAuthentication(getContext(), loginUid, instanceToken), repoOwner, repoName);
return v;
}
@Override
public void onResume() {
super.onResume();
}
private static BreadcrumbItem createItem(String title) {
List<String> list = new ArrayList<>();
list.add(title);
return new BreadcrumbItem(list);
}
@Override
public void onClickDir(String dirName) {
TinyDB tinyDb = new TinyDB(getContext());
final String instanceUrl = tinyDb.getString("instanceUrl");
final String loginUid = tinyDb.getString("loginUid");
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
StringBuilder breadcrumbBuilder = new StringBuilder();
breadcrumbBuilder.append(fileStructure.getText().toString()).append("/").append(dirName);
fileStructure.setText(breadcrumbBuilder);
mBreadcrumbsView.addItem(createItem(dirName));
mBreadcrumbsView.setCallback(new DefaultBreadcrumbsCallback<BreadcrumbItem>() {
@Override
public void onNavigateBack(BreadcrumbItem item, int position) {
if(position == 0) {
fetchDataAsync(instanceUrl, Authorization.returnAuthentication(getContext(), loginUid, instanceToken), repoOwner, repoName);
fileStructure.setText("");
return;
}
String filterDir = fileStructure.getText().toString();
String result = filterDir.substring(0, filterDir.indexOf(item.getSelectedItem()));
fileStructure.setText(result + item.getSelectedItem());
fetchDataAsyncSub(instanceUrl, Authorization.returnAuthentication(getContext(), loginUid, instanceToken), repoOwner, repoName, fileStructure.getText().toString());
}
@Override
public void onNavigateNewLocation(BreadcrumbItem newItem, int changedPosition) {
}
});
fetchDataAsyncSub(instanceUrl, Authorization.returnAuthentication(getContext(), loginUid, instanceToken), repoOwner, repoName, fileStructure.getText().toString());
}
@Override
public void onClickFile(String fileName) {
Intent intent = new Intent(getContext(), FileViewActivity.class);
if(!fileStructure.getText().toString().equals("Root")) {
intent.putExtra("singleFileName", fileStructure.getText().toString()+"/"+fileName);
}
else {
intent.putExtra("singleFileName", fileName);
}
Objects.requireNonNull(getContext()).startActivity(intent);
}
private void fetchDataAsync(String instanceUrl, String instanceToken, String owner, String repo) {
mRecyclerView.setVisibility(View.GONE);
mProgressBar.setVisibility(View.VISIBLE);
FilesViewModel filesModel = new ViewModelProvider(this).get(FilesViewModel.class);
filesModel.getFilesList(instanceUrl, instanceToken, owner, repo, getContext()).observe(this, new Observer<List<Files>>() {
@Override
public void onChanged(@Nullable List<Files> filesListMain) {
adapter = new FilesAdapter(getContext(), filesListMain, FilesFragment.this);
mBreadcrumbsView.removeItemAfter(1);
if(adapter.getItemCount() > 0) {
mRecyclerView.setVisibility(View.VISIBLE);
mRecyclerView.setAdapter(adapter);
filesFrame.setVisibility(View.VISIBLE);
noDataFiles.setVisibility(View.GONE);
}
else {
mRecyclerView.setVisibility(View.VISIBLE);
adapter.notifyDataSetChanged();
mRecyclerView.setAdapter(adapter);
filesFrame.setVisibility(View.VISIBLE);
noDataFiles.setVisibility(View.VISIBLE);
}
filesFrame.setVisibility(View.VISIBLE);
mProgressBar.setVisibility(View.GONE);
}
});
}
private void fetchDataAsyncSub(String instanceUrl, String instanceToken, String owner, String repo, String filesDir) {
mRecyclerView.setVisibility(View.GONE);
mProgressBar.setVisibility(View.VISIBLE);
FilesViewModel filesModel2 = new ViewModelProvider(this).get(FilesViewModel.class);
filesModel2.getFilesList2(instanceUrl, instanceToken, owner, repo, filesDir, getContext()).observe(this, new Observer<List<Files>>() {
@Override
public void onChanged(@Nullable List<Files> filesListMain2) {
adapter = new FilesAdapter(getContext(), filesListMain2, FilesFragment.this);
if(adapter.getItemCount() > 0) {
mRecyclerView.setVisibility(View.VISIBLE);
mRecyclerView.setAdapter(adapter);
filesFrame.setVisibility(View.VISIBLE);
noDataFiles.setVisibility(View.GONE);
}
else {
mRecyclerView.setVisibility(View.VISIBLE);
adapter.notifyDataSetChanged();
mRecyclerView.setAdapter(adapter);
filesFrame.setVisibility(View.VISIBLE);
noDataFiles.setVisibility(View.VISIBLE);
}
filesFrame.setVisibility(View.VISIBLE);
mProgressBar.setVisibility(View.GONE);
}
});
}
@Override
public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
boolean connToInternet = AppUtil.haveNetworkConnection(Objects.requireNonNull(getContext()));
inflater.inflate(R.menu.search_menu, menu);
super.onCreateOptionsMenu(menu, inflater);
MenuItem searchItem = menu.findItem(R.id.action_search);
androidx.appcompat.widget.SearchView searchView = (androidx.appcompat.widget.SearchView) searchItem.getActionView();
searchView.setImeOptions(EditorInfo.IME_ACTION_DONE);
searchView.setQueryHint(getContext().getString(R.string.strFilter));
if(!connToInternet) {
return;
}
searchView.setOnQueryTextListener(new androidx.appcompat.widget.SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
return false;
}
@Override
public boolean onQueryTextChange(String newText) {
if(mRecyclerView.getAdapter() != null) {
adapter.getFilter().filter(newText);
}
return false;
}
});
}
public void onButtonPressed(Uri uri) {
if (mListener != null) {
mListener.onFragmentInteraction(uri);
}
}
@Override
public void onDetach() {
super.onDetach();
mListener = null;
}
public interface OnFragmentInteractionListener {
void onFragmentInteraction(Uri uri);
}
}

View File

@ -262,6 +262,7 @@ public class IssuesFragment extends Fragment {
MenuItem searchItem = menu.findItem(R.id.action_search);
androidx.appcompat.widget.SearchView searchView = (androidx.appcompat.widget.SearchView) searchItem.getActionView();
searchView.setImeOptions(EditorInfo.IME_ACTION_DONE);
searchView.setQueryHint(getContext().getString(R.string.strFilter));
if(!connToInternet) {
return;

View File

@ -6,7 +6,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProviders;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
@ -142,7 +142,7 @@ public class LabelsFragment extends Fragment {
private void fetchDataAsync(String instanceUrl, String instanceToken, String owner, String repo) {
LabelsViewModel labelsModel = ViewModelProviders.of(this).get(LabelsViewModel.class);
LabelsViewModel labelsModel = new ViewModelProvider(this).get(LabelsViewModel.class);
labelsModel.getLabelsList(instanceUrl, instanceToken, owner, repo).observe(this, new Observer<List<Labels>>() {
@Override

View File

@ -6,7 +6,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProviders;
import androidx.lifecycle.ViewModelProvider;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
@ -81,7 +81,7 @@ public class MembersByOrgFragment extends Fragment {
private void fetchDataAsync(String instanceUrl, String instanceToken, String owner) {
MembersByOrgViewModel membersModel = ViewModelProviders.of(this).get(MembersByOrgViewModel.class);
MembersByOrgViewModel membersModel= new ViewModelProvider(this).get(MembersByOrgViewModel.class);
membersModel.getMembersList(instanceUrl, instanceToken, owner).observe(this, new Observer<List<UserInfo>>() {
@Override
@ -112,6 +112,7 @@ public class MembersByOrgFragment extends Fragment {
MenuItem searchItem = menu.findItem(R.id.action_search);
androidx.appcompat.widget.SearchView searchView = (androidx.appcompat.widget.SearchView) searchItem.getActionView();
searchView.setImeOptions(EditorInfo.IME_ACTION_DONE);
searchView.setQueryHint(getContext().getString(R.string.strFilter));
if(!connToInternet) {
return;
@ -125,7 +126,9 @@ public class MembersByOrgFragment extends Fragment {
@Override
public boolean onQueryTextChange(String newText) {
adapter.getFilter().filter(newText);
if(mGridView.getAdapter() != null) {
adapter.getFilter().filter(newText);
}
return false;
}
});

View File

@ -6,7 +6,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProviders;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
@ -46,6 +46,7 @@ public class MilestonesFragment extends Fragment {
private String repoName;
private String repoOwner;
private String msState = "all";
private OnFragmentInteractionListener mListener;
@ -103,7 +104,7 @@ public class MilestonesFragment extends Fragment {
@Override
public void run() {
swipeRefresh.setRefreshing(false);
MilestonesViewModel.loadMilestonesList(instanceUrl, Authorization.returnAuthentication(getContext(), loginUid, instanceToken), repoOwner, repoName);
MilestonesViewModel.loadMilestonesList(instanceUrl, Authorization.returnAuthentication(getContext(), loginUid, instanceToken), repoOwner, repoName, msState);
}
}, 50);
}
@ -127,7 +128,7 @@ public class MilestonesFragment extends Fragment {
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
if(tinyDb.getBoolean("milestoneCreated")) {
MilestonesViewModel.loadMilestonesList(instanceUrl, Authorization.returnAuthentication(getContext(), loginUid, instanceToken), repoOwner, repoName);
MilestonesViewModel.loadMilestonesList(instanceUrl, Authorization.returnAuthentication(getContext(), loginUid, instanceToken), repoOwner, repoName, msState);
tinyDb.putBoolean("milestoneCreated", false);
}
}
@ -150,9 +151,9 @@ public class MilestonesFragment extends Fragment {
private void fetchDataAsync(String instanceUrl, String instanceToken, String owner, String repo) {
MilestonesViewModel msModel = ViewModelProviders.of(this).get(MilestonesViewModel.class);
MilestonesViewModel msModel = new ViewModelProvider(this).get(MilestonesViewModel.class);
msModel.getMilestonesList(instanceUrl, instanceToken, owner, repo).observe(this, new Observer<List<Milestones>>() {
msModel.getMilestonesList(instanceUrl, instanceToken, owner, repo, msState).observe(this, new Observer<List<Milestones>>() {
@Override
public void onChanged(@Nullable List<Milestones> msListMain) {
adapter = new MilestonesAdapter(getContext(), msListMain);
@ -182,6 +183,7 @@ public class MilestonesFragment extends Fragment {
MenuItem searchItem = menu.findItem(R.id.action_search);
androidx.appcompat.widget.SearchView searchView = (androidx.appcompat.widget.SearchView) searchItem.getActionView();
searchView.setImeOptions(EditorInfo.IME_ACTION_DONE);
searchView.setQueryHint(getContext().getString(R.string.strFilter));
if(!connToInternet) {
return;
@ -195,7 +197,9 @@ public class MilestonesFragment extends Fragment {
@Override
public boolean onQueryTextChange(String newText) {
adapter.getFilter().filter(newText);
if(mRecyclerView.getAdapter() != null) {
adapter.getFilter().filter(newText);
}
return false;
}
});

View File

@ -7,7 +7,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProviders;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
@ -89,6 +89,7 @@ public class MyRepositoriesFragment extends Fragment {
final String instanceUrl = tinyDb.getString("instanceUrl");
final String loginUid = tinyDb.getString("loginUid");
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
final String userLogin = tinyDb.getString("userLogin");
final SwipeRefreshLayout swipeRefresh = v.findViewById(R.id.pullToRefresh);
@ -140,13 +141,13 @@ public class MyRepositoriesFragment extends Fragment {
@Override
public void run() {
swipeRefresh.setRefreshing(false);
MyRepositoriesViewModel.loadMyReposList(instanceUrl, Authorization.returnAuthentication(getContext(), loginUid, instanceToken), loginUid);
MyRepositoriesViewModel.loadMyReposList(instanceUrl, Authorization.returnAuthentication(getContext(), loginUid, instanceToken), userLogin);
}
}, 50);
}
});
fetchDataAsync(instanceUrl, Authorization.returnAuthentication(getContext(), loginUid, instanceToken), loginUid);
fetchDataAsync(instanceUrl, Authorization.returnAuthentication(getContext(), loginUid, instanceToken), userLogin);
}
else {
@ -164,16 +165,17 @@ public class MyRepositoriesFragment extends Fragment {
final String instanceUrl = tinyDb.getString("instanceUrl");
final String loginUid = tinyDb.getString("loginUid");
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
final String userLogin = tinyDb.getString("userLogin");
MyRepositoriesViewModel.loadMyReposList(instanceUrl, Authorization.returnAuthentication(getContext(), loginUid, instanceToken), loginUid);
MyRepositoriesViewModel.loadMyReposList(instanceUrl, Authorization.returnAuthentication(getContext(), loginUid, instanceToken), userLogin);
}
private void fetchDataAsync(String instanceUrl, String instanceToken, String username) {
private void fetchDataAsync(String instanceUrl, String instanceToken, String userLogin) {
MyRepositoriesViewModel myRepoModel = ViewModelProviders.of(this).get(MyRepositoriesViewModel.class);
MyRepositoriesViewModel myRepoModel = new ViewModelProvider(this).get(MyRepositoriesViewModel.class);
myRepoModel.getCurrentUserRepositories(instanceUrl, instanceToken, username).observe(this, new Observer<List<UserRepositories>>() {
myRepoModel.getCurrentUserRepositories(instanceUrl, instanceToken, userLogin).observe(this, new Observer<List<UserRepositories>>() {
@Override
public void onChanged(@Nullable List<UserRepositories> myReposListMain) {
adapter = new MyReposListAdapter(getContext(), myReposListMain);
@ -203,6 +205,7 @@ public class MyRepositoriesFragment extends Fragment {
MenuItem searchItem = menu.findItem(R.id.action_search);
androidx.appcompat.widget.SearchView searchView = (androidx.appcompat.widget.SearchView) searchItem.getActionView();
searchView.setImeOptions(EditorInfo.IME_ACTION_DONE);
searchView.setQueryHint(getContext().getString(R.string.strFilter));
if(!connToInternet) {
return;
@ -216,7 +219,9 @@ public class MyRepositoriesFragment extends Fragment {
@Override
public boolean onQueryTextChange(String newText) {
adapter.getFilter().filter(newText);
if(mRecyclerView.getAdapter() != null) {
adapter.getFilter().filter(newText);
}
return false;
}
});

View File

@ -104,7 +104,7 @@ public class OrganizationInfoFragment extends Fragment {
if (response.code() == 200) {
assert orgInfo != null;
Picasso.get().load(orgInfo.getAvatar_url()).transform(new RoundedTransformation(100, 0)).resize(200, 200).centerCrop().into(orgAvatar);
Picasso.get().load(orgInfo.getAvatar_url()).transform(new RoundedTransformation(8, 0)).resize(180, 180).centerCrop().into(orgAvatar);
orgDescInfo.setText(orgInfo.getDescription());
orgWebsiteInfo.setText(orgInfo.getWebsite());
orgLocationInfo.setText(orgInfo.getLocation());

View File

@ -6,7 +6,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProviders;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
@ -141,7 +141,7 @@ public class OrganizationsFragment extends Fragment {
private void fetchDataAsync(String instanceUrl, String instanceToken) {
OrganizationListViewModel orgModel = ViewModelProviders.of(this).get(OrganizationListViewModel.class);
OrganizationListViewModel orgModel = new ViewModelProvider(this).get(OrganizationListViewModel.class);
orgModel.getUserOrgs(instanceUrl, instanceToken).observe(this, new Observer<List<UserOrganizations>>() {
@Override
@ -173,6 +173,7 @@ public class OrganizationsFragment extends Fragment {
MenuItem searchItem = menu.findItem(R.id.action_search);
androidx.appcompat.widget.SearchView searchView = (androidx.appcompat.widget.SearchView) searchItem.getActionView();
searchView.setImeOptions(EditorInfo.IME_ACTION_DONE);
searchView.setQueryHint(getContext().getString(R.string.strFilter));
if(!connToInternet) {
return;
@ -186,7 +187,9 @@ public class OrganizationsFragment extends Fragment {
@Override
public boolean onQueryTextChange(String newText) {
adapter.getFilter().filter(newText);
if(mRecyclerView.getAdapter() != null) {
adapter.getFilter().filter(newText);
}
return false;
}
});

View File

@ -5,7 +5,7 @@ import android.os.Bundle;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProviders;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
@ -109,7 +109,7 @@ public class ProfileEmailsFragment extends Fragment {
private void fetchDataAsync(String instanceUrl, String instanceToken) {
ProfileEmailsViewModel profileEmailModel = ViewModelProviders.of(this).get(ProfileEmailsViewModel.class);
ProfileEmailsViewModel profileEmailModel = new ViewModelProvider(this).get(ProfileEmailsViewModel.class);
profileEmailModel.getEmailsList(instanceUrl, instanceToken).observe(this, new Observer<List<Emails>>() {
@Override

View File

@ -6,7 +6,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProviders;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
@ -108,7 +108,7 @@ public class ProfileFollowersFragment extends Fragment {
private void fetchDataAsync(String instanceUrl, String instanceToken) {
ProfileFollowersViewModel pfModel = ViewModelProviders.of(this).get(ProfileFollowersViewModel.class);
ProfileFollowersViewModel pfModel = new ViewModelProvider(this).get(ProfileFollowersViewModel.class);
pfModel.getFollowersList(instanceUrl, instanceToken).observe(this, new Observer<List<UserInfo>>() {
@Override

View File

@ -6,7 +6,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProviders;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
@ -108,7 +108,7 @@ public class ProfileFollowingFragment extends Fragment {
private void fetchDataAsync(String instanceUrl, String instanceToken) {
ProfileFollowingViewModel pfModel = ViewModelProviders.of(this).get(ProfileFollowingViewModel.class);
ProfileFollowingViewModel pfModel = new ViewModelProvider(this).get(ProfileFollowingViewModel.class);
pfModel.getFollowingList(instanceUrl, instanceToken).observe(this, new Observer<List<UserInfo>>() {
@Override

View File

@ -48,7 +48,7 @@ public class ProfileFragment extends Fragment {
TextView userEmail = v.findViewById(R.id.userEmail);
userFullName.setText(tinyDb.getString("userFullname"));
Picasso.get().load(tinyDb.getString("userAvatar")).transform(new RoundedTransformation(100, 0)).resize(180, 180).centerCrop().into(userAvatar);
Picasso.get().load(tinyDb.getString("userAvatar")).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(userAvatar);
userLogin.setText(getString(R.string.usernameWithAt, tinyDb.getString("userLogin")));
userEmail.setText(tinyDb.getString("userEmail"));

View File

@ -6,7 +6,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProviders;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
@ -141,7 +141,7 @@ public class ReleasesFragment extends Fragment {
private void fetchDataAsync(String instanceUrl, String instanceToken, String owner, String repo) {
ReleasesViewModel releasesModel = ViewModelProviders.of(this).get(ReleasesViewModel.class);
ReleasesViewModel releasesModel = new ViewModelProvider(this).get(ReleasesViewModel.class);
releasesModel.getReleasesList(instanceUrl, instanceToken, owner, repo).observe(this, new Observer<List<Releases>>() {
@Override

View File

@ -8,6 +8,8 @@ import android.view.ViewGroup;
import android.widget.TextView;
import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
import org.mian.gitnex.R;
import org.mian.gitnex.actions.RepositoryActions;
import org.mian.gitnex.util.TinyDB;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@ -24,11 +26,19 @@ public class RepoBottomSheetFragment extends BottomSheetDialogFragment {
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.repo_bottom_sheet_layout, container, false);
final TinyDB tinyDb = new TinyDB(getContext());
TextView createLabel = v.findViewById(R.id.createLabel);
TextView createIssue = v.findViewById(R.id.createNewIssue);
TextView createMilestone = v.findViewById(R.id.createNewMilestone);
TextView addCollaborator = v.findViewById(R.id.addCollaborator);
TextView createRelease = v.findViewById(R.id.createRelease);
TextView openWebRepo = v.findViewById(R.id.openWebRepo);
TextView newFile = v.findViewById(R.id.newFile);
TextView starRepository = v.findViewById(R.id.starRepository);
TextView unStarRepository = v.findViewById(R.id.unStarRepository);
TextView watchRepository = v.findViewById(R.id.watchRepository);
TextView unWatchRepository = v.findViewById(R.id.unWatchRepository);
createLabel.setOnClickListener(new View.OnClickListener() {
@Override
@ -38,13 +48,19 @@ public class RepoBottomSheetFragment extends BottomSheetDialogFragment {
}
});
createIssue.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
bmListener.onButtonClicked("newIssue");
dismiss();
}
});
if(tinyDb.getBoolean("hasIssues")) {
createIssue.setVisibility(View.VISIBLE);
createIssue.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
bmListener.onButtonClicked("newIssue");
dismiss();
}
});
}
else {
createIssue.setVisibility(View.GONE);
}
createMilestone.setOnClickListener(new View.OnClickListener() {
@Override
@ -70,6 +86,88 @@ public class RepoBottomSheetFragment extends BottomSheetDialogFragment {
}
});
openWebRepo.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
bmListener.onButtonClicked("openWebRepo");
dismiss();
}
});
newFile.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
bmListener.onButtonClicked("newFile");
dismiss();
}
});
if(tinyDb.getInt("repositoryStarStatus") == 204) { // star a repo
starRepository.setVisibility(View.GONE);
unStarRepository.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
RepositoryActions.unStarRepository(getContext());
tinyDb.putInt("repositoryStarStatus", 404);
dismiss();
}
});
}
else if(tinyDb.getInt("repositoryStarStatus") == 404) {
unStarRepository.setVisibility(View.GONE);
starRepository.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
RepositoryActions.starRepository(getContext());
tinyDb.putInt("repositoryStarStatus", 204);
dismiss();
}
});
}
if(tinyDb.getBoolean("repositoryWatchStatus")) { // watch a repo
watchRepository.setVisibility(View.GONE);
unWatchRepository.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
RepositoryActions.unWatchRepository(getContext());
tinyDb.putBoolean("repositoryWatchStatus", false);
dismiss();
}
});
}
else {
unWatchRepository.setVisibility(View.GONE);
watchRepository.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
RepositoryActions.watchRepository(getContext());
tinyDb.putBoolean("repositoryWatchStatus", true);
dismiss();
}
});
}
return v;
}

View File

@ -1,26 +1,31 @@
package org.mian.gitnex.fragments;
import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import okhttp3.OkHttpClient;
import io.noties.markwon.AbstractMarkwonPlugin;
import io.noties.markwon.Markwon;
import io.noties.markwon.core.CorePlugin;
import io.noties.markwon.core.MarkwonTheme;
import io.noties.markwon.ext.strikethrough.StrikethroughPlugin;
import io.noties.markwon.ext.tables.TablePlugin;
import io.noties.markwon.ext.tasklist.TaskListPlugin;
import io.noties.markwon.html.HtmlPlugin;
import io.noties.markwon.image.AsyncDrawable;
import io.noties.markwon.image.DefaultMediaDecoder;
import io.noties.markwon.image.ImageItem;
import io.noties.markwon.image.ImagesPlugin;
import io.noties.markwon.image.SchemeHandler;
import io.noties.markwon.image.gif.GifMediaDecoder;
import io.noties.markwon.image.svg.SvgMediaDecoder;
import io.noties.markwon.linkify.LinkifyPlugin;
import retrofit2.Call;
import retrofit2.Callback;
import ru.noties.markwon.AbstractMarkwonPlugin;
import ru.noties.markwon.Markwon;
import ru.noties.markwon.core.CorePlugin;
import ru.noties.markwon.core.MarkwonTheme;
import ru.noties.markwon.ext.strikethrough.StrikethroughPlugin;
import ru.noties.markwon.ext.tables.TablePlugin;
import ru.noties.markwon.ext.tables.TableTheme;
import ru.noties.markwon.ext.tasklist.TaskListPlugin;
import ru.noties.markwon.html.HtmlPlugin;
import ru.noties.markwon.image.ImagesPlugin;
import ru.noties.markwon.image.gif.GifPlugin;
import ru.noties.markwon.image.okhttp.OkHttpImagesPlugin;
import android.text.Spanned;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
@ -42,6 +47,8 @@ import org.mian.gitnex.util.TinyDB;
import org.ocpsoft.prettytime.PrettyTime;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Collections;
import java.util.Locale;
import java.util.Objects;
@ -208,6 +215,8 @@ public class RepoInfoFragment extends Fragment {
private void getRepoInfo(String instanceUrl, String token, final String owner, String repo, final String locale, final String timeFormat) {
final TinyDB tinyDb = new TinyDB(getContext());
Call<UserRepositories> call = RetrofitClient
.getInstance(instanceUrl)
.getApiInterface()
@ -220,53 +229,64 @@ public class RepoInfoFragment extends Fragment {
UserRepositories repoInfo = response.body();
if (response.isSuccessful()) {
if (isAdded()) {
if (response.code() == 200) {
if (response.isSuccessful()) {
assert repoInfo != null;
repoNameInfo.setText(repoInfo.getName());
repoOwnerInfo.setText(owner);
repoDescriptionInfo.setText(repoInfo.getDescription());
repoWebsiteInfo.setText(repoInfo.getWebsite());
repoSizeInfo.setText(AppUtil.formatFileSize(repoInfo.getSize()));
repoDefaultBranchInfo.setText(repoInfo.getDefault_branch());
repoSshUrlInfo.setText(repoInfo.getSsh_url());
repoCloneUrlInfo.setText(repoInfo.getClone_url());
repoRepoUrlInfo.setText(repoInfo.getHtml_url());
repoForksCountInfo.setText(repoInfo.getForks_count());
if (response.code() == 200) {
switch (timeFormat) {
case "pretty": {
PrettyTime prettyTime = new PrettyTime(new Locale(locale));
String createdTime = prettyTime.format(repoInfo.getCreated_at());
repoCreatedAtInfo.setText(createdTime);
repoCreatedAtInfo.setOnClickListener(new ClickListener(TimeHelper.customDateFormatForToastDateFormat(repoInfo.getCreated_at()), getContext()));
break;
assert repoInfo != null;
repoNameInfo.setText(repoInfo.getName());
repoOwnerInfo.setText(owner);
repoDescriptionInfo.setText(repoInfo.getDescription());
repoWebsiteInfo.setText(repoInfo.getWebsite());
repoSizeInfo.setText(AppUtil.formatFileSize(repoInfo.getSize()));
repoDefaultBranchInfo.setText(repoInfo.getDefault_branch());
repoSshUrlInfo.setText(repoInfo.getSsh_url());
repoCloneUrlInfo.setText(repoInfo.getClone_url());
repoRepoUrlInfo.setText(repoInfo.getHtml_url());
repoForksCountInfo.setText(repoInfo.getForks_count());
if(repoInfo.getHas_issues() != null) {
tinyDb.putBoolean("hasIssues", repoInfo.getHas_issues());
}
case "normal": {
DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd '" + getResources().getString(R.string.timeAtText) + "' HH:mm", new Locale(locale));
String createdTime = formatter.format(repoInfo.getCreated_at());
repoCreatedAtInfo.setText(createdTime);
break;
else {
tinyDb.putBoolean("hasIssues", true);
}
case "normal1": {
DateFormat formatter = new SimpleDateFormat("dd-MM-yyyy '" + getResources().getString(R.string.timeAtText) + "' HH:mm", new Locale(locale));
String createdTime = formatter.format(repoInfo.getCreated_at());
repoCreatedAtInfo.setText(createdTime);
break;
switch (timeFormat) {
case "pretty": {
PrettyTime prettyTime = new PrettyTime(new Locale(locale));
String createdTime = prettyTime.format(repoInfo.getCreated_at());
repoCreatedAtInfo.setText(createdTime);
repoCreatedAtInfo.setOnClickListener(new ClickListener(TimeHelper.customDateFormatForToastDateFormat(repoInfo.getCreated_at()), getContext()));
break;
}
case "normal": {
DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd '" + getResources().getString(R.string.timeAtText) + "' HH:mm", new Locale(locale));
String createdTime = formatter.format(repoInfo.getCreated_at());
repoCreatedAtInfo.setText(createdTime);
break;
}
case "normal1": {
DateFormat formatter = new SimpleDateFormat("dd-MM-yyyy '" + getResources().getString(R.string.timeAtText) + "' HH:mm", new Locale(locale));
String createdTime = formatter.format(repoInfo.getCreated_at());
repoCreatedAtInfo.setText(createdTime);
break;
}
}
mProgressBar.setVisibility(View.GONE);
pageContent.setVisibility(View.VISIBLE);
}
mProgressBar.setVisibility(View.GONE);
pageContent.setVisibility(View.VISIBLE);
}
else {
Log.e("onFailure", String.valueOf(response.code()));
}
}
else {
Log.e("onFailure", String.valueOf(response.code()));
}
}
@ -292,12 +312,51 @@ public class RepoInfoFragment extends Fragment {
@Override
public void onResponse(@NonNull Call<String> call, @NonNull retrofit2.Response<String> response) {
if (response.code() == 200) {
if (isAdded()) {
final Markwon markwon = Markwon.builder(Objects.requireNonNull(getContext()))
if (response.code() == 200) {
final Markwon markwon = Markwon.builder(Objects.requireNonNull(getContext()))
.usePlugin(CorePlugin.create())
.usePlugin(OkHttpImagesPlugin.create(new OkHttpClient()))
.usePlugin(ImagesPlugin.createWithAssets(getContext()))
.usePlugin(ImagesPlugin.create(new ImagesPlugin.ImagesConfigure() {
@Override
public void configureImages(@NonNull ImagesPlugin plugin) {
plugin.addSchemeHandler(new SchemeHandler() {
@NonNull
@Override
public ImageItem handle(@NonNull String raw, @NonNull Uri uri) {
final int resourceId = getContext().getResources().getIdentifier(
raw.substring("drawable://".length()),
"drawable",
getContext().getPackageName());
final Drawable drawable = getContext().getDrawable(resourceId);
assert drawable != null;
return ImageItem.withResult(drawable);
}
@NonNull
@Override
public Collection<String> supportedSchemes() {
return Collections.singleton("drawable");
}
});
plugin.placeholderProvider(new ImagesPlugin.PlaceholderProvider() {
@Nullable
@Override
public Drawable providePlaceholder(@NonNull AsyncDrawable drawable) {
return null;
}
});
plugin.addMediaDecoder(GifMediaDecoder.create(false));
plugin.addMediaDecoder(SvgMediaDecoder.create(getContext().getResources()));
plugin.addMediaDecoder(SvgMediaDecoder.create());
plugin.defaultMediaDecoder(DefaultMediaDecoder.create(getContext().getResources()));
plugin.defaultMediaDecoder(DefaultMediaDecoder.create());
}
}))
.usePlugin(new AbstractMarkwonPlugin() {
@Override
public void configureTheme(@NonNull MarkwonTheme.Builder builder) {
@ -310,40 +369,39 @@ public class RepoInfoFragment extends Fragment {
.usePlugin(TablePlugin.create(getContext()))
.usePlugin(TaskListPlugin.create(getContext()))
.usePlugin(HtmlPlugin.create())
.usePlugin(GifPlugin.create())
.usePlugin(StrikethroughPlugin.create())
.usePlugin(LinkifyPlugin.create())
.build();
CharSequence bodyWithMD = null;
if (response.body() != null) {
bodyWithMD = markwon.toMarkdown(response.body());
Spanned bodyWithMD = null;
if (response.body() != null) {
bodyWithMD = markwon.toMarkdown(response.body());
}
assert bodyWithMD != null;
markwon.setParsedMarkdown(repoFileContents, bodyWithMD);
} else if (response.code() == 401) {
AlertDialogs.authorizationTokenRevokedDialog(ctx, getResources().getString(R.string.alertDialogTokenRevokedTitle),
getResources().getString(R.string.alertDialogTokenRevokedMessage),
getResources().getString(R.string.alertDialogTokenRevokedCopyNegativeButton),
getResources().getString(R.string.alertDialogTokenRevokedCopyPositiveButton));
} else if (response.code() == 403) {
Toasty.info(ctx, ctx.getString(R.string.authorizeError));
} else if (response.code() == 404) {
fileContentsFrameHeader.setVisibility(View.GONE);
fileContentsFrame.setVisibility(View.GONE);
} else {
Toasty.info(getContext(), getString(R.string.genericError));
}
repoFileContents.setText(bodyWithMD);
}
else if(response.code() == 401) {
AlertDialogs.authorizationTokenRevokedDialog(ctx, getResources().getString(R.string.alertDialogTokenRevokedTitle),
getResources().getString(R.string.alertDialogTokenRevokedMessage),
getResources().getString(R.string.alertDialogTokenRevokedCopyNegativeButton),
getResources().getString(R.string.alertDialogTokenRevokedCopyPositiveButton));
}
else if(response.code() == 403) {
Toasty.info(ctx, ctx.getString(R.string.authorizeError));
}
else if(response.code() == 404) {
fileContentsFrameHeader.setVisibility(View.GONE);
fileContentsFrame.setVisibility(View.GONE);
}
else {
Toasty.info(getContext(), getString(R.string.genericError));
}
}

View File

@ -6,7 +6,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProviders;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
@ -123,7 +123,7 @@ public class RepositoriesByOrgFragment extends Fragment {
private void fetchDataAsync(String instanceUrl, String instanceToken, String owner) {
RepositoriesByOrgViewModel orgRepoModel = ViewModelProviders.of(this).get(RepositoriesByOrgViewModel.class);
RepositoriesByOrgViewModel orgRepoModel = new ViewModelProvider(this).get(RepositoriesByOrgViewModel.class);
orgRepoModel.getRepositoriesByOrg(instanceUrl, instanceToken, owner).observe(this, new Observer<List<UserRepositories>>() {
@Override
@ -155,6 +155,7 @@ public class RepositoriesByOrgFragment extends Fragment {
MenuItem searchItem = menu.findItem(R.id.action_search);
androidx.appcompat.widget.SearchView searchView = (androidx.appcompat.widget.SearchView) searchItem.getActionView();
searchView.setImeOptions(EditorInfo.IME_ACTION_DONE);
searchView.setQueryHint(getContext().getString(R.string.strFilter));
if(!connToInternet) {
return;
@ -168,7 +169,9 @@ public class RepositoriesByOrgFragment extends Fragment {
@Override
public boolean onQueryTextChange(String newText) {
adapter.getFilter().filter(newText);
if(mRecyclerView.getAdapter() != null) {
adapter.getFilter().filter(newText);
}
return false;
}
});

View File

@ -6,7 +6,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProviders;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
@ -144,7 +144,7 @@ public class RepositoriesFragment extends Fragment {
private void fetchDataAsync(String instanceUrl, String instanceToken) {
RepositoriesListViewModel repoModel = ViewModelProviders.of(this).get(RepositoriesListViewModel.class);
RepositoriesListViewModel repoModel = new ViewModelProvider(this).get(RepositoriesListViewModel.class);
repoModel.getUserRepositories(instanceUrl, instanceToken).observe(this, new Observer<List<UserRepositories>>() {
@Override
@ -176,6 +176,7 @@ public class RepositoriesFragment extends Fragment {
MenuItem searchItem = menu.findItem(R.id.action_search);
androidx.appcompat.widget.SearchView searchView = (androidx.appcompat.widget.SearchView) searchItem.getActionView();
searchView.setImeOptions(EditorInfo.IME_ACTION_DONE);
searchView.setQueryHint(getContext().getString(R.string.strFilter));
if(!connToInternet) {
return;
@ -189,7 +190,9 @@ public class RepositoriesFragment extends Fragment {
@Override
public boolean onQueryTextChange(String newText) {
adapter.getFilter().filter(newText);
if(mRecyclerView.getAdapter() != null) {
adapter.getFilter().filter(newText);
}
return false;
}
});

View File

@ -30,7 +30,7 @@ public class SettingsFragment extends Fragment {
private Context ctx = null;
private static String[] langList = {"English", "French", "German", "Russian"};
private static String[] langList = {"Arabic", "Chinese", "English", "Finnish", "French", "German", "Italian", "Persian", "Russian", "Serbian"};
private static int langSelectedChoice = 0;
private static String[] timeList = {"Pretty", "Normal"};
@ -68,7 +68,7 @@ public class SettingsFragment extends Fragment {
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.addCategory(Intent.CATEGORY_BROWSABLE);
intent.setData(Uri.parse(getResources().getString(R.string.appRepoContributingLink)));
intent.setData(Uri.parse(getResources().getString(R.string.crowdInLink)));
startActivity(intent);
}
});
@ -185,10 +185,6 @@ public class SettingsFragment extends Fragment {
tinyDb.putInt("codeBlockId", i);
switch (codeBlockList[i]) {
case "Green - Black":
tinyDb.putInt("codeBlockColor", getResources().getColor(R.color.colorLightGreen));
tinyDb.putInt("codeBlockBackground", getResources().getColor(R.color.black));
break;
case "White - Black":
tinyDb.putInt("codeBlockColor", getResources().getColor(R.color.white));
tinyDb.putInt("codeBlockBackground", getResources().getColor(R.color.black));
@ -248,8 +244,14 @@ public class SettingsFragment extends Fragment {
tinyDb.putInt("langId", i);
switch (langList[i]) {
case "English":
tinyDb.putString("locale", "en");
case "Arabic":
tinyDb.putString("locale", "ar");
break;
case "Chinese":
tinyDb.putString("locale", "zh");
break;
case "Finnish":
tinyDb.putString("locale", "fi");
break;
case "French":
tinyDb.putString("locale", "fr");
@ -257,9 +259,18 @@ public class SettingsFragment extends Fragment {
case "German":
tinyDb.putString("locale", "de");
break;
case "Italian":
tinyDb.putString("locale", "it");
break;
case "Persian":
tinyDb.putString("locale", "fa");
break;
case "Russian":
tinyDb.putString("locale", "ru");
break;
case "Serbian":
tinyDb.putString("locale", "sr");
break;
default:
tinyDb.putString("locale", "en");
break;
@ -309,16 +320,10 @@ public class SettingsFragment extends Fragment {
tinyDb.putString("timeStr", timeList[i]);
tinyDb.putInt("timeId", i);
switch (timeList[i]) {
case "Pretty":
tinyDb.putString("dateFormat", "pretty");
break;
case "Normal":
tinyDb.putString("dateFormat", "normal");
break;
default:
tinyDb.putString("dateFormat", "pretty");
break;
if ("Normal".equals(timeList[i])) {
tinyDb.putString("dateFormat", "normal");
} else {
tinyDb.putString("dateFormat", "pretty");
}
dialogInterfaceTime.dismiss();

View File

@ -13,9 +13,13 @@ import org.mian.gitnex.activities.AddRemoveAssigneesActivity;
import org.mian.gitnex.activities.AddRemoveLabelsActivity;
import org.mian.gitnex.activities.EditIssueActivity;
import org.mian.gitnex.activities.ReplyToIssueActivity;
import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.util.TinyDB;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import android.content.ClipboardManager;
import android.content.ClipData;
import java.util.Objects;
/**
* Author M M Arif
@ -37,6 +41,7 @@ public class SingleIssueBottomSheetFragment extends BottomSheetDialogFragment {
TextView closeIssue = v.findViewById(R.id.closeIssue);
TextView reOpenIssue = v.findViewById(R.id.reOpenIssue);
TextView addRemoveAssignees = v.findViewById(R.id.addRemoveAssignees);
TextView copyIssueUrl = v.findViewById(R.id.copyIssueUrl);
replyToIssue.setOnClickListener(new View.OnClickListener() {
@Override
@ -78,6 +83,32 @@ public class SingleIssueBottomSheetFragment extends BottomSheetDialogFragment {
}
});
copyIssueUrl.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// get url of repo
String repoFullName = tinyDB.getString("repoFullName");
String instanceUrlWithProtocol = "https://" + tinyDB.getString("instanceUrlRaw");
if(!tinyDB.getString("instanceUrlWithProtocol").isEmpty()) {
instanceUrlWithProtocol = tinyDB.getString("instanceUrlWithProtocol");
}
// get issue Url
String issueUrl = instanceUrlWithProtocol + "/" + repoFullName + "/issues/" + tinyDB.getString("issueNumber");
// copy to clipboard
ClipboardManager clipboard = (ClipboardManager) Objects.requireNonNull(getContext()).getSystemService(android.content.Context.CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText("issueUrl", issueUrl);
clipboard.setPrimaryClip(clip);
dismiss();
Toasty.info(getContext(), getContext().getString(R.string.copyIssueUrlToastMsg));
}
});
if(tinyDB.getString("issueState").equals("open")) { // close issue
reOpenIssue.setVisibility(View.GONE);

View File

@ -7,7 +7,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProviders;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
@ -166,7 +166,7 @@ public class StarredRepositoriesFragment extends Fragment {
private void fetchDataAsync(String instanceUrl, String instanceToken) {
StarredRepositoriesViewModel starredRepoModel = ViewModelProviders.of(this).get(StarredRepositoriesViewModel.class);
StarredRepositoriesViewModel starredRepoModel = new ViewModelProvider(this).get(StarredRepositoriesViewModel.class);
starredRepoModel.getUserStarredRepositories(instanceUrl, instanceToken).observe(this, new Observer<List<UserRepositories>>() {
@Override
@ -198,6 +198,7 @@ public class StarredRepositoriesFragment extends Fragment {
MenuItem searchItem = menu.findItem(R.id.action_search);
androidx.appcompat.widget.SearchView searchView = (androidx.appcompat.widget.SearchView) searchItem.getActionView();
searchView.setImeOptions(EditorInfo.IME_ACTION_DONE);
searchView.setQueryHint(getContext().getString(R.string.strFilter));
if(!connToInternet) {
return;
@ -211,7 +212,9 @@ public class StarredRepositoriesFragment extends Fragment {
@Override
public boolean onQueryTextChange(String newText) {
adapter.getFilter().filter(newText);
if(mRecyclerView.getAdapter() != null) {
adapter.getFilter().filter(newText);
}
return false;
}
});

View File

@ -6,7 +6,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProviders;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
@ -124,7 +124,7 @@ public class TeamsByOrgFragment extends Fragment {
private void fetchDataAsync(String instanceUrl, String instanceToken, String owner) {
TeamsByOrgViewModel teamModel = ViewModelProviders.of(this).get(TeamsByOrgViewModel.class);
TeamsByOrgViewModel teamModel = new ViewModelProvider(this).get(TeamsByOrgViewModel.class);
teamModel.getTeamsByOrg(instanceUrl, instanceToken, owner).observe(this, new Observer<List<Teams>>() {
@Override
@ -156,6 +156,7 @@ public class TeamsByOrgFragment extends Fragment {
MenuItem searchItem = menu.findItem(R.id.action_search);
androidx.appcompat.widget.SearchView searchView = (androidx.appcompat.widget.SearchView) searchItem.getActionView();
searchView.setImeOptions(EditorInfo.IME_ACTION_DONE);
searchView.setQueryHint(getContext().getString(R.string.strFilter));
if(!connToInternet) {
return;
@ -169,7 +170,9 @@ public class TeamsByOrgFragment extends Fragment {
@Override
public boolean onQueryTextChange(String newText) {
adapter.getFilter().filter(newText);
if(mRecyclerView.getAdapter() != null) {
adapter.getFilter().filter(newText);
}
return false;
}
});

View File

@ -3,6 +3,9 @@ package org.mian.gitnex.interfaces;
import com.google.gson.JsonElement;
import org.mian.gitnex.models.AddEmail;
import org.mian.gitnex.models.Branches;
import org.mian.gitnex.models.ExploreRepositories;
import org.mian.gitnex.models.Files;
import org.mian.gitnex.models.NewFile;
import org.mian.gitnex.models.UpdateIssueAssignee;
import org.mian.gitnex.models.UpdateIssueState;
import org.mian.gitnex.models.Collaborators;
@ -25,6 +28,7 @@ import org.mian.gitnex.models.UserOrganizations;
import org.mian.gitnex.models.UserRepositories;
import org.mian.gitnex.models.UserSearch;
import org.mian.gitnex.models.UserTokens;
import org.mian.gitnex.models.WatchRepository;
import java.util.List;
import retrofit2.Call;
import retrofit2.http.Body;
@ -98,7 +102,7 @@ public interface ApiInterface {
Call<Issues> replyCommentToIssue(@Header("Authorization") String token, @Path("owner") String ownerName, @Path("repo") String repoName, @Path("index") int issueIndex, @Body Issues jsonStr);
@GET("repos/{owner}/{repo}/milestones") // get milestones by repo
Call<List<Milestones>> getMilestones(@Header("Authorization") String token, @Path("owner") String ownerName, @Path("repo") String repoName);
Call<List<Milestones>> getMilestones(@Header("Authorization") String token, @Path("owner") String ownerName, @Path("repo") String repoName, @Query("state") String state);
@GET("repos/{owner}/{repo}/branches") // get branches
Call<List<Branches>> getBranches(@Header("Authorization") String token, @Path("owner") String ownerName, @Path("repo") String repoName);
@ -204,4 +208,43 @@ public interface ApiInterface {
@GET("admin/users") // get all users
Call<List<UserInfo>> adminGetUsers(@Header("Authorization") String token);
}
@GET("repos/{owner}/{repo}/stargazers") // get all repo stars
Call<List<UserInfo>> getRepoStargazers(@Header("Authorization") String token, @Path("owner") String ownerName, @Path("repo") String repoName);
@GET("repos/{owner}/{repo}/subscribers") // get all repo watchers
Call<List<UserInfo>> getRepoWatchers(@Header("Authorization") String token, @Path("owner") String ownerName, @Path("repo") String repoName);
@GET("repos/search") // get all the repos which match the query string
Call<ExploreRepositories> queryRepos(@Header("Authorization") String token, @Query("q") String searchKeyword, @Query("private") Boolean repoTypeInclude, @Query("sort") String sort, @Query("order") String order);
@POST("repos/{owner}/{repo}/contents/{file}") // create new file
Call<JsonElement> createNewFile(@Header("Authorization") String token, @Path("owner") String ownerName, @Path("repo") String repoName, @Path("file") String fileName, @Body NewFile jsonStr);
@GET("repos/{owner}/{repo}/contents") // get all the files and dirs of a repository
Call<List<Files>> getFiles(@Header("Authorization") String token, @Path("owner") String ownerName, @Path("repo") String repoName);
@GET("repos/{owner}/{repo}/contents/{file}") // get single file contents
Call<Files> getSingleFileContents(@Header("Authorization") String token, @Path("owner") String ownerName, @Path("repo") String repoName, @Path("file") String file);
@GET("repos/{owner}/{repo}/contents/{fileDir}") // get all the sub files and dirs of a repository
Call<List<Files>> getDirFiles(@Header("Authorization") String token, @Path("owner") String ownerName, @Path("repo") String repoName, @Path("fileDir") String fileDir);
@GET("user/starred/{owner}/{repo}") // check star status of a repository
Call<JsonElement> checkRepoStarStatus(@Header("Authorization") String token, @Path("owner") String ownerName, @Path("repo") String repoName);
@PUT("user/starred/{owner}/{repo}") // star a repository
Call<JsonElement> starRepository(@Header("Authorization") String token, @Path("owner") String ownerName, @Path("repo") String repoName);
@DELETE("user/starred/{owner}/{repo}") // un star a repository
Call<JsonElement> unStarRepository(@Header("Authorization") String token, @Path("owner") String ownerName, @Path("repo") String repoName);
@GET("repos/{owner}/{repo}/subscription") // check watch status of a repository
Call<WatchRepository> checkRepoWatchStatus(@Header("Authorization") String token, @Path("owner") String ownerName, @Path("repo") String repoName);
@PUT("repos/{owner}/{repo}/subscription") // watch a repository
Call<JsonElement> watchRepository(@Header("Authorization") String token, @Path("owner") String ownerName, @Path("repo") String repoName);
@DELETE("repos/{owner}/{repo}/subscription") // un watch a repository
Call<JsonElement> unWatchRepository(@Header("Authorization") String token, @Path("owner") String ownerName, @Path("repo") String repoName);
}

View File

@ -0,0 +1,22 @@
package org.mian.gitnex.models;
import java.util.ArrayList;
/**
* Author M M Arif
*/
public class ExploreRepositories {
private ArrayList<UserRepositories> data;
private Boolean ok;
public ArrayList<UserRepositories> getSearchedData() {
return data;
}
public Boolean getOk() {
return ok;
}
}

View File

@ -0,0 +1,74 @@
package org.mian.gitnex.models;
/**
* Author M M Arif
*/
public class Files {
private String name;
private String path;
private String sha;
private String type;
private int size;
private String encoding;
private String content;
private String target;
private String url;
private String html_url;
private String git_url;
private String download_url;
private String submodule_git_url;
public String getName() {
return name;
}
public String getPath() {
return path;
}
public String getSha() {
return sha;
}
public String getType() {
return type;
}
public int getSize() {
return size;
}
public String getEncoding() {
return encoding;
}
public String getContent() {
return content;
}
public String getTarget() {
return target;
}
public String getUrl() {
return url;
}
public String getHtml_url() {
return html_url;
}
public String getGit_url() {
return git_url;
}
public String getDownload_url() {
return download_url;
}
public String getSubmodule_git_url() {
return submodule_git_url;
}
}

View File

@ -0,0 +1,99 @@
package org.mian.gitnex.models;
/**
* Author M M Arif
*/
public class NewFile {
private String branch;
private String content;
private String message;
private String new_branch;
private authorObject author;
private committerObject committer;
public String getBranch() {
return branch;
}
public void setBranch(String branch) {
this.branch = branch;
}
public String getContents() {
return content;
}
public void setContents(String contents) {
this.content = contents;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public String getNew_branch() {
return new_branch;
}
public void setNew_branch(String new_branch) {
this.new_branch = new_branch;
}
public class authorObject {
private String email;
private String name;
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class committerObject {
private String email;
private String name;
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public NewFile(String branch, String content, String message, String new_branch) {
this.branch = branch;
this.content = content;
this.message = message;
this.new_branch = new_branch;
}
}

View File

@ -27,7 +27,8 @@ public class UserRepositories {
private String ssh_url;
private String website;
private String forks_count;
private Boolean has_issues;
private String avatar_url;
public int getId() {
return id;
@ -96,4 +97,12 @@ public class UserRepositories {
public String getForks_count() {
return forks_count;
}
public Boolean getHas_issues() {
return has_issues;
}
public String getAvatar_url() {
return avatar_url;
}
}

View File

@ -0,0 +1,39 @@
package org.mian.gitnex.models;
/**
* Author M M Arif
*/
public class WatchRepository {
private Boolean subscribed;
private Boolean ignored;
private String reason;
private String created_at;
private String url;
private String repository_url;
public Boolean getSubscribed() {
return subscribed;
}
public Boolean getIgnored() {
return ignored;
}
public String getReason() {
return reason;
}
public String getCreated_at() {
return created_at;
}
public String getUrl() {
return url;
}
public String getRepository_url() {
return repository_url;
}
}

View File

@ -7,9 +7,11 @@ import android.content.res.Configuration;
import android.content.res.Resources;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.util.Base64;
import android.util.DisplayMetrics;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.text.DecimalFormat;
import java.util.Calendar;
import java.util.Locale;
@ -77,6 +79,10 @@ public class AppUtil {
return str.matches("^[\\w.-]+$");
}
public Boolean checkStringsWithDash(String str) { // [a-zA-Z0-9-_. ]
return str.matches("^[\\w-]+$");
}
public Boolean checkIntegers(String str) {
return str.matches("\\d+");
}
@ -180,4 +186,28 @@ public class AppUtil {
}
public String encodeBase64(String str) {
String base64Str = str;
if(!str.equals("")) {
byte[] data = str.getBytes(StandardCharsets.UTF_8);
base64Str = Base64.encodeToString(data, Base64.DEFAULT);
}
return base64Str;
}
public String decodeBase64(String str) {
String base64Str = str;
if(!str.equals("")) {
byte[] data = Base64.decode(base64Str, Base64.DEFAULT);
base64Str = new String(data, StandardCharsets.UTF_8);
}
return base64Str;
}
}

View File

@ -0,0 +1,117 @@
package org.mian.gitnex.viewmodels;
import android.content.Context;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
import org.mian.gitnex.R;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.models.Files;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
/**
* Author M M Arif
*/
public class FilesViewModel extends ViewModel {
private static MutableLiveData<List<Files>> filesList;
private static MutableLiveData<List<Files>> filesList2;
public LiveData<List<Files>> getFilesList(String instanceUrl, String token, String owner, String repo, Context ctx) {
filesList = new MutableLiveData<>();
loadFilesList(instanceUrl, token, owner, repo, ctx);
return filesList;
}
private static void loadFilesList(String instanceUrl, String token, String owner, String repo, final Context ctx) {
Call<List<Files>> call = RetrofitClient
.getInstance(instanceUrl)
.getApiInterface()
.getFiles(token, owner, repo);
call.enqueue(new Callback<List<Files>>() {
@Override
public void onResponse(@NonNull Call<List<Files>> call, @NonNull Response<List<Files>> response) {
if (response.isSuccessful()) {
Collections.sort(response.body(), new Comparator<Files>() {
@Override
public int compare(Files byType1, Files byType2) {
return byType1.getType().compareTo(byType2.getType());
}
});
filesList.postValue(response.body());
} else {
Toasty.info(ctx, ctx.getString(R.string.noDataFilesTab));
Log.i("onResponse", String.valueOf(response.code()));
}
}
@Override
public void onFailure(@NonNull Call<List<Files>> call, Throwable t) {
Log.i("onFailure", t.toString());
}
});
}
public LiveData<List<Files>> getFilesList2(String instanceUrl, String token, String owner, String repo, String filesDir, Context ctx) {
filesList2 = new MutableLiveData<>();
loadFilesList2(instanceUrl, token, owner, repo, filesDir, ctx);
return filesList2;
}
private static void loadFilesList2(String instanceUrl, String token, String owner, String repo, String filesDir, final Context ctx) {
Call<List<Files>> call = RetrofitClient
.getInstance(instanceUrl)
.getApiInterface()
.getDirFiles(token, owner, repo, filesDir);
call.enqueue(new Callback<List<Files>>() {
@Override
public void onResponse(@NonNull Call<List<Files>> call, @NonNull Response<List<Files>> response) {
if (response.isSuccessful()) {
Collections.sort(response.body(), new Comparator<Files>() {
@Override
public int compare(Files byType1, Files byType2) {
return byType1.getType().compareTo(byType2.getType());
}
});
filesList2.postValue(response.body());
} else {
Toasty.info(ctx, ctx.getString(R.string.noDataFilesTab));
Log.i("onResponse", String.valueOf(response.code()));
}
}
@Override
public void onFailure(@NonNull Call<List<Files>> call, Throwable t) {
Log.i("onFailure", t.toString());
}
});
}
}

View File

@ -20,20 +20,20 @@ public class MilestonesViewModel extends ViewModel {
private static MutableLiveData<List<Milestones>> milestonesList;
public LiveData<List<Milestones>> getMilestonesList(String instanceUrl, String token, String owner, String repo) {
public LiveData<List<Milestones>> getMilestonesList(String instanceUrl, String token, String owner, String repo, String msState) {
milestonesList = new MutableLiveData<>();
loadMilestonesList(instanceUrl, token, owner, repo);
loadMilestonesList(instanceUrl, token, owner, repo, msState);
return milestonesList;
}
public static void loadMilestonesList(String instanceUrl, String token, String owner, String repo) {
public static void loadMilestonesList(String instanceUrl, String token, String owner, String repo, String msState) {
Call<List<Milestones>> call = RetrofitClient
.getInstance(instanceUrl)
.getApiInterface()
.getMilestones(token, owner, repo);
.getMilestones(token, owner, repo, msState);
call.enqueue(new Callback<List<Milestones>>() {

View File

@ -0,0 +1,60 @@
package org.mian.gitnex.viewmodels;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.models.UserInfo;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
/**
* Author M M Arif
*/
public class RepoStargazersViewModel extends ViewModel {
private static MutableLiveData<List<UserInfo>> stargazersList;
public LiveData<List<UserInfo>> getRepoStargazers(String instanceUrl, String token, String repoOwner, String repoName) {
stargazersList = new MutableLiveData<>();
loadRepoStargazers(instanceUrl, token, repoOwner, repoName);
return stargazersList;
}
public static void loadRepoStargazers(String instanceUrl, String token, String repoOwner, String repoName) {
Call<List<UserInfo>> call = RetrofitClient
.getInstance(instanceUrl)
.getApiInterface()
.getRepoStargazers(token, repoOwner, repoName);
call.enqueue(new Callback<List<UserInfo>>() {
@Override
public void onResponse(@NonNull Call<List<UserInfo>> call, @NonNull Response<List<UserInfo>> response) {
if(response.isSuccessful()) {
if(response.code() == 200) {
stargazersList.postValue(response.body());
}
}
}
@Override
public void onFailure(@NonNull Call<List<UserInfo>> call, Throwable t) {
Log.i("onFailure", t.toString());
}
});
}
}

View File

@ -0,0 +1,60 @@
package org.mian.gitnex.viewmodels;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.models.UserInfo;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
/**
* Author M M Arif
*/
public class RepoWatchersViewModel extends ViewModel {
private static MutableLiveData<List<UserInfo>> watchersList;
public LiveData<List<UserInfo>> getRepoWatchers(String instanceUrl, String token, String repoOwner, String repoName) {
watchersList = new MutableLiveData<>();
loadRepoWatchers(instanceUrl, token, repoOwner, repoName);
return watchersList;
}
public static void loadRepoWatchers(String instanceUrl, String token, String repoOwner, String repoName) {
Call<List<UserInfo>> call = RetrofitClient
.getInstance(instanceUrl)
.getApiInterface()
.getRepoWatchers(token, repoOwner, repoName);
call.enqueue(new Callback<List<UserInfo>>() {
@Override
public void onResponse(@NonNull Call<List<UserInfo>> call, @NonNull Response<List<UserInfo>> response) {
if(response.isSuccessful()) {
if(response.code() == 200) {
watchersList.postValue(response.body());
}
}
}
@Override
public void onFailure(@NonNull Call<List<UserInfo>> call, Throwable t) {
Log.i("onFailure", t.toString());
}
});
}
}

View File

@ -0,0 +1,5 @@
<vector android:height="16dp" android:tint="#FFFFFF"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="16dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M21.99,4c0,-1.1 -0.89,-2 -1.99,-2H4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h14l4,4 -0.01,-18z"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector android:height="20dp" android:tint="#FFFFFF"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="20dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M21.99,4c0,-1.1 -0.89,-2 -1.99,-2H4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h14l4,4 -0.01,-18z"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M16,1L4,1c-1.1,0 -2,0.9 -2,2v14h2L4,3h12L16,1zM19,5L8,5c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h11c1.1,0 2,-0.9 2,-2L21,7c0,-1.1 -0.9,-2 -2,-2zM19,21L8,21L8,7h11v14z"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M6,2c-1.1,0 -1.99,0.9 -1.99,2L4,20c0,1.1 0.89,2 1.99,2L18,22c1.1,0 2,-0.9 2,-2L20,8l-6,-6L6,2zM13,9L13,3.5L18.5,9L13,9z"/>
</vector>

View File

@ -0,0 +1,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:width="512dp"
android:height="512dp"
android:viewportWidth="16"
android:viewportHeight="16"
tools:ignore="VectorRaster">
<path
android:fillColor="#FFFFFF"
android:pathData="m13.707,3.293 l-3,-3c-0.1875,-0.1875 -0.4419,-0.293 -0.707,-0.293h-7c-0.5522,0 -1,0.4478 -1,1v14c0,0.5527 0.4478,1 1,1h10c0.5522,0 1,-0.4473 1,-1v-11c0,-0.2651 -0.1055,-0.5195 -0.293,-0.707zM8,12h-3v-2h3zM11,9h-6v-2h6zM11,4c-0.5523,0 -1,-0.4478 -1,-1v-2l3,3z"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M10,18h4v-2h-4v2zM3,6v2h18L21,6L3,6zM6,13h12v-2L6,11v2z"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M10,4H4c-1.1,0 -1.99,0.9 -1.99,2L2,18c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V8c0,-1.1 -0.9,-2 -2,-2h-8l-2,-2z"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M14,4l2.29,2.29 -2.88,2.88 1.42,1.42 2.88,-2.88L20,10L20,4zM10,4L4,4v6l2.29,-2.29 4.71,4.7L11,20h2v-8.41l-5.29,-5.3z"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M19,4L5,4c-1.11,0 -2,0.9 -2,2v12c0,1.1 0.89,2 2,2h4v-2L5,18L5,8h14v10h-4v2h4c1.1,0 2,-0.9 2,-2L21,6c0,-1.1 -0.89,-2 -2,-2zM12,10l-4,4h3v6h2v-6h3l-4,-4z"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM13,19h-2v-2h2v2zM15.07,11.25l-0.9,0.92C13.45,12.9 13,13.5 13,15h-2v-0.5c0,-1.1 0.45,-2.1 1.17,-2.83l1.24,-1.26c0.37,-0.36 0.59,-0.86 0.59,-1.41 0,-1.1 -0.9,-2 -2,-2s-2,0.9 -2,2L8,9c0,-2.21 1.79,-4 4,-4s4,1.79 4,4c0,0.88 -0.36,1.68 -0.93,2.25z"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M22,9.24l-7.19,-0.62L12,2 9.19,8.63 2,9.24l5.46,4.73L5.82,21 12,17.27 18.18,21l-1.63,-7.03L22,9.24zM12,15.4l-3.76,2.27 1,-4.28 -3.32,-2.88 4.38,-0.38L12,6.1l1.71,4.04 4.38,0.38 -3.32,2.88 1,4.28L12,15.4z"/>
</vector>

View File

@ -0,0 +1,6 @@
<vector android:autoMirrored="true" android:height="24dp"
android:viewportHeight="511.999" android:viewportWidth="511.999"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FFFFFFFF" android:pathData="M508.745,246.041c-4.574,-6.257 -113.557,-153.206 -252.748,-153.206S7.818,239.784 3.249,246.035c-4.332,5.936 -4.332,13.987 0,19.923c4.569,6.257 113.557,153.206 252.748,153.206s248.174,-146.95 252.748,-153.201C513.083,260.028 513.083,251.971 508.745,246.041zM255.997,385.406c-102.529,0 -191.33,-97.533 -217.617,-129.418c26.253,-31.913 114.868,-129.395 217.617,-129.395c102.524,0 191.319,97.516 217.617,129.418C447.361,287.923 358.746,385.406 255.997,385.406z"/>
<path android:fillColor="#FFFFFFFF" android:pathData="M255.997,154.725c-55.842,0 -101.275,45.433 -101.275,101.275s45.433,101.275 101.275,101.275s101.275,-45.433 101.275,-101.275S311.839,154.725 255.997,154.725zM255.997,323.516c-37.23,0 -67.516,-30.287 -67.516,-67.516s30.287,-67.516 67.516,-67.516s67.516,30.287 67.516,67.516S293.227,323.516 255.997,323.516z"/>
</vector>

View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@android:id/background"
android:top="2dp"
android:bottom="2dp"
android:right="1dp"
android:left="1dp">
<shape>
<corners android:radius="15dp"/>
<solid android:color="@color/divider"/>
</shape>
</item>
<item
android:id="@android:id/progress"
android:top="3dp"
android:bottom="3dp"
android:left="1dp"
android:right="1dp">
<scale android:scaleWidth="100%">
<shape>
<corners android:radius="15dp" />
</shape>
</scale>
</item>
</layer-list>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<corners android:radius="35dp"/>
<corners android:radius="5dp"/>
</shape>

Binary file not shown.

Binary file not shown.

View File

@ -10,7 +10,6 @@
android:layout_height="wrap_content">
<androidx.appcompat.widget.Toolbar
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/toolbar"
android:layout_width="match_parent"
@ -72,7 +71,7 @@
android:textSize="20sp"
android:visibility="gone" />
<ProgressBar xmlns:android="http://schemas.android.com/apk/res/android"
<ProgressBar
android:id="@+id/progress_bar"
style="@style/Base.Widget.AppCompat.ProgressBar"
android:layout_width="match_parent"

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