Compare commits

...

267 Commits
2.2.2 ... 2.5.0

Author SHA1 Message Date
3ddf978bf0 Merge pull request 'prepare release 2.5' (#434) from prepare-release-2.5 into release-2.5
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/434
2020-04-21 16:02:15 +00:00
bb8cc3ff6e prepare release 2.5 2020-04-21 19:19:16 +05:00
e9eef8fcbf [Backport] Crowdin [2020-04-21] (#432)
Merge branch 'release-2.5' into backport_431

Update from Crowdin

Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/432
Reviewed-by: M M Arif <mmarif@swatian.com>
2020-04-21 13:54:07 +00:00
eba170f7e9 Shuffle tabs, add images (#430)
update images
workaround for #414 (shuffle tabs)

Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/430
Reviewed-by: 6543 <6543@noreply.gitea.io>
2020-04-21 08:50:51 +00:00
c2b316446c #427 Dismiss bottom sheet on subscribe/unsubscribe to issue & Fix (#429)
Dismiss bottom sheet on subscribe/unsubscribe to issue: Does not really fix the issue as there is way to handle this without a proper call.
And dismiss does not work properly either.

But added few improvements and fixed close/reopen issue along the way.

Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/429
Reviewed-by: 6543 <6543@noreply.gitea.io>
2020-04-18 14:21:48 +00:00
c3f4cbb186 Merge pull request 'Rc release' (#426) from prepare-rc-release into master
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/426
2020-04-18 05:21:39 +00:00
57ecf3b7d2 Rc release 2020-04-18 10:19:43 +05:00
03a9cd1bba Adding ability to login again when version check failes. (#417)
add own error message for this

Merge branch 'master' into login-fix

Merge branch 'master' into login-fix

Merge branch 'master' into login-fix

Adding ability to login again when version check failes.

Co-authored-by: 6543 <6543@obermui.de>
Co-authored-by: 6543 <6543@noreply.gitea.io>
Co-authored-by: opyale <example@example.com>
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/417
Reviewed-by: M M Arif <mmarif@swatian.com>
2020-04-18 04:51:58 +00:00
aa85b99e84 FIX IssueComments moddel (#425)
Reformat Code

FIX IssueComments moddel

reformate Code

TimeHelper.formatTime dont crash on null date object

Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/425
Reviewed-by: M M Arif <mmarif@swatian.com>
2020-04-18 04:50:36 +00:00
0c6c596208 Integrate crash reporting (#418)
Disable minify to get proper logs

Enable it by default

Integrate crash reporting

Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/418
Reviewed-by: 6543 <6543@noreply.gitea.io>
2020-04-17 23:39:49 +00:00
30165f27ba Merge pull request 'Fix crash caused by res shrinking and minification' (#421) from 420-fix-release-crash into master
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/421
2020-04-17 10:12:59 +00:00
b7abe65508 Fix crash caused by res shrinking and minification 2020-04-17 15:10:32 +05:00
31723008ed [CI] publish signed builds from master to nextcloud (#416)
publish builds from master

Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/416
Reviewed-by: M M Arif <mmarif@swatian.com>
2020-04-15 16:09:29 +00:00
a544e2ef56 Crowdin [2020-04-14] (#411)
Merge branch 'master' into crowdin-update

Update Crowdin 2020-04-14

Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/411
Reviewed-by: M M Arif <mmarif@swatian.com>
2020-04-15 06:33:38 +00:00
13dbbe3ec7 Fixing toasty bug. (#412)
Fixing toasty bug.

Co-authored-by: opyale <example@example.com>
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/412
Reviewed-by: 6543 <6543@noreply.gitea.io>
2020-04-14 22:41:40 +00:00
9cbcb1f87b Merge pull request 'Prepare 2.5.0 rc release' (#410) from rc-release-fdroid into master
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/410
2020-04-14 21:31:36 +00:00
e7554819fd Prepare 2.5.0 rc release 2020-04-15 02:27:58 +05:00
7caecadb32 Refactor issues (#380)
new strings for tabs

Merge branch 'refactor-issues' of gitea.com:gitnex/GitNex into refactor-issues

Fix conflicts and files refactors

Merge branch 'master' into refactor-issues

Merge branch 'master' into refactor-issues

refactored closed issues in new tab

Added gitea ver check, minor ui fixes

Merge branch 'master' into refactor-issues

# Conflicts:
#	app/src/main/java/org/mian/gitnex/adapters/IssuesAdapter.java

Refactored open issues

Added parent fragment

Co-authored-by: 6543 <6543@noreply.gitea.io>
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/380
2020-04-14 20:55:04 +00:00
b8d8b34b0e Show ContributorsTab only if you have permission to (#402)
add isRepoAdmin

extend Adapters

add check to RepoDetails

refactor var names

reformat code

Co-authored-by: 6543 <6543@obermui.de>
Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/402
Reviewed-by: M M Arif <mmarif@swatian.com>
2020-04-14 19:25:36 +00:00
ab47e409e9 update libs, enhance release builds (#408)
Merge branch 'master' into update-libs-enhance-release-build

update libs, enhance release builds

Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/408
2020-04-14 08:50:12 +00:00
344284c1c1 Improving issue template. (#401)
Final changes.

Merge branch 'master' into bug-desc-improve

Merge branch 'master' into bug-desc-improve

Removing unnecessary bar.

Simplifying stuff.

Some more examples.

Further improvements.

Further improvements.

Improving issue template.

Co-authored-by: opyale <example@example.com>
Co-authored-by: 6543 <6543@noreply.gitea.io>
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/401
Reviewed-by: 6543 <6543@noreply.gitea.io>
Reviewed-by: M M Arif <mmarif@swatian.com>
2020-04-13 15:56:31 +00:00
b10df63c8a Merge pull request 'Adjusting size of text views in organizations list.' (#406) from opyale/GitNex:size-adj into master
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/406
Reviewed-by: M M Arif <mmarif@swatian.com>
2020-04-13 15:55:17 +00:00
4cb0253b38 Adjusting size of text views in organizations list. 2020-04-13 17:31:39 +02:00
539c5be4b5 Themes for source code in file viewer (#403)
reformat code

move from else-if to switch-case

Merge branch 'master' into 396-themes-file-veiwer

Merge branch 'master' into 396-themes-file-veiwer

Make string translatable false

Themes for source code in file viewer

Co-authored-by: 6543 <6543@obermui.de>
Co-authored-by: 6543 <6543@noreply.gitea.io>
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/403
Reviewed-by: 6543 <6543@noreply.gitea.io>
2020-04-13 15:23:31 +00:00
008ffaa553 Merge pull request 'Fix of views being gone randomly' (#404) from 400-milestone-bug into master
Merging via app
2020-04-13 10:40:05 +00:00
9a5a774d8c Merge branch 'master' into 400-milestone-bug 2020-04-13 10:20:18 +00:00
2e452eaa81 Fix version API auth check (#399)
Merge branch 'master' into 389_alternate_version-api-auth

rm comment

get gitea Version Authentificated

Co-authored-by: M M Arif <mmarif@swatian.com>
Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/399
Reviewed-by: M M Arif <mmarif@swatian.com>
2020-04-13 08:01:56 +00:00
3b84ec46d1 Fix of views being gone randomly 2020-04-13 12:48:23 +05:00
4123e03f7d Applying changes of LabelWidthCalculator to LabelsAdapter. (#398)
Trying to find a compromise.

make them great again ;)

Applying changes of LabelWidthCalculator to LabelsAdapter.

Co-authored-by: opyale <example@example.com>
Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/398
Reviewed-by: 6543 <6543@noreply.gitea.io>
Reviewed-by: M M Arif <mmarif@swatian.com>
2020-04-13 07:25:39 +00:00
3a524c9f5d Remember-login-type (#394)
Merge branch 'master' into 372-remember-login-type

# Conflicts:
#	app/src/main/java/org/mian/gitnex/activities/LoginActivity.java

Use strings instead of boolean

Remember login type

Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/394
2020-04-12 19:15:20 +00:00
e709aba3c2 Remember login type (#392)
Merge branch 'master' into 372-remember-login-type

Remember login type

Co-authored-by: 6543 <6543@noreply.gitea.io>
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/392
Reviewed-by: 6543 <6543@noreply.gitea.io>
2020-04-12 19:04:02 +00:00
14bca1f4c4 Merge pull request 'Adding more reliable calculation of label width.' (#393) from opyale/GitNex:label-width-calc into master
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/393
Reviewed-by: M M Arif <mmarif@swatian.com>
2020-04-12 18:53:44 +00:00
a7213add30 Adding more reliable calculation of label width. 2020-04-12 20:33:41 +02:00
df2bc91e9f Setting Manrope as default font. (#379)
Revert "store default if user didnt touch Font settings"

This reverts commit 9c5f9731

store default if user didnt touch Font settings

Setting translatable to false

Last changes.

Defaulting to Manrope in strings.xml

Default to Manrope in settings.

Changes in default value.

Automatic formatting.

Merge remote-tracking branch 'remotes/main/master' into manrope

# Conflicts:
#	app/src/main/java/org/mian/gitnex/activities/BaseActivity.java

Manrope just literally as default font.

Reformatting code.

Making optimizations.

Moving initialization to BaseActivity

Merge remote-tracking branch 'remotes/main/master' into manrope

Setting Manrope as default font.

Co-authored-by: opyale <example@example.com>
Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/379
Reviewed-by: 6543 <6543@noreply.gitea.io>
Reviewed-by: M M Arif <mmarif@swatian.com>
2020-04-12 15:19:33 +00:00
145043a515 Extend Merge Options (#217)
Merge branch 'master' into extend-merge-dialog

Minor fixes

format

? an AndroidStudio suggestion ?

Signed-off-by: 6543 <6543@obermui.de>

add Title Text and some Fixes

add version check

Merge branch 'master' into extend-merge-dialog

Merge branch 'master' into extend-merge-dialog

use translation and revormat

make Merge Options Translateble
gitea locale revs:
* pulls.merge_pull_request
* pulls.rebase_merge_pull_request
* pulls.rebase_merge_commit_pull_request
* pulls.squash_merge_pull_request

Fix menu item

Make merge options work

Merge branch 'master' into merge-options

work - but UGLY UI

use enum for merge-modes

Co-authored-by: M M Arif <mmarif@swatian.com>
Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/217
2020-04-11 20:20:26 +00:00
adb8a8bf04 Fix fab hide scroll issue and clean up (#381)
Merge branch 'fix-fab-scroll-issue' of gitea.com:gitnex/GitNex into fix-fab-scroll-issue

Merge branch 'master' into fix-fab-scroll-issue

Merge branch 'master' into fix-fab-scroll-issue

Fix fab hide scroll issue and clean up

Co-authored-by: 6543 <6543@noreply.gitea.io>
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/381
Reviewed-by: 6543 <6543@noreply.gitea.io>
2020-04-11 20:17:24 +00:00
398cceed2f Merge pull request 'Close/reopen milestone' (#386) from 329-close-open-milestone into master
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/386
Reviewed-by: 6543 <6543@noreply.gitea.io>
2020-04-11 06:59:40 +00:00
1acbd7dc9f Merge branch 'master' into 329-close-open-milestone 2020-04-11 06:44:30 +00:00
f5d5264ef7 Implement auto switcher for light and dark theme (#388)
Remove import and add author

Implement auto switcher for light and dark theme. other ui fixes

Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/388
Reviewed-by: 6543 <6543@noreply.gitea.io>
2020-04-11 06:06:39 +00:00
0caaa63b06 Close/reopen milestone 2020-04-08 23:31:27 +05:00
79944241fe Merge pull request 'Minor improvement and fixes for repo info tab' (#382) from fixes-repo-info into master
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/382
2020-04-07 21:23:38 +00:00
8b7c5e2873 Minor improvement and fix for repo info tab 2020-04-08 02:21:47 +05:00
e310a16bad Improving design of "Repository Meta" (#362)
Merge branch 'master' into details-design

Always open "Repository Meta"

Fixing bugs.

Merge remote-tracking branch 'remotes/main/master' into details-design

Typo removal.

Do not show pull requests when API returns null.

Replacing size by watchers

Removing unused imports.

Moving time formatting into TimeHelper.

Changing website icon and renaming button and dialog text.

Further contentDescription

Adding contentDescription

Adding support for "timeFormat"

Merge remote-tracking branch 'remotes/main/master' into details-design

Full support for translation.

Partially supporting translation.

Adding "view additional information".

Adding additional information.

Adding forks count.

First design changes.

Improving usability by including whole header in "Details".

Co-authored-by: opyale <example@example.com>
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/362
Reviewed-by: M M Arif <mmarif@swatian.com>
2020-04-07 21:17:12 +00:00
e07ee1aceb Enabling counter badges by default. (#378)
Merge remote-tracking branch 'remotes/main/master' into counter-badges

# Conflicts:
#	app/src/main/java/org/mian/gitnex/fragments/SettingsFragment.java

Moving to BaseActivity

Enabling counter badges by default.

Co-authored-by: opyale <example@example.com>
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/378
Reviewed-by: M M Arif <mmarif@swatian.com>
2020-04-07 20:45:40 +00:00
73950f9f2a Crowdin [2020-04-07] + add Polish (#377)
add Polish to settings and reformat code

add Polish locales

Crowdin Update

Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/377
Reviewed-by: M M Arif <mmarif@swatian.com>
2020-04-07 20:39:08 +00:00
7387c29077 Replacing bottom sheet item by floating action button. (#360)
Merge branch 'fab-button-issues' of https://gitea.com/opyale/GitNex into fab-button-issues

Merge remote-tracking branch 'remotes/main/master' into fab-button-issues

Merge branch 'master' into fab-button-issues

Adding onScrollListener.

Reply icon

Generalizing padding of floating action button.

Merge branch 'master' into fab-button-issues

Improving proportions.

Replacing bottom sheet item by floating action button and cleaning up code.

Co-authored-by: opyale <example@example.com>
Co-authored-by: anonTree1417 <example@example.com>
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/360
Reviewed-by: M M Arif <mmarif@swatian.com>
2020-04-07 20:06:39 +00:00
9bca299107 Merge pull request 'fix' (#375) from 6543/GitNex:issue-subscribe-take-theme-into-account into master
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/375
Reviewed-by: M M Arif <mmarif@swatian.com>
2020-04-07 13:44:47 +00:00
ee88ee86cd Merge pull request 'Fix repos loading on switching accounts' (#371) from fix-repos-load-on-login into master
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/371
Reviewed-by: 6543 <6543@noreply.gitea.io>
2020-04-07 13:43:38 +00:00
ce51b9264a fix
Signed-off-by: 6543 <6543@obermui.de>
2020-04-07 15:18:14 +02:00
831e9d36ec Fix repos loading on switching accounts 2020-04-07 11:05:42 +05:00
da90005e42 hide ReleaseCounter Badge on old Gitea instances (#367)
Hide Release Count on old Gitea Instances

fix compareVersion

Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/367
Reviewed-by: M M Arif <mmarif@swatian.com>
2020-04-07 04:15:56 +00:00
d46db0475f Improving usability by including whole header in "Details". (#361)
Merge branch 'master' into usability-details

Improving usability by including whole header in "Details".

Co-authored-by: opyale <example@example.com>
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/361
Reviewed-by: M M Arif <mmarif@swatian.com>
2020-04-06 19:00:18 +00:00
9b9173e33b [Doc] update issue-template add pull-template (#359)
fix

add sugestions

fix Nr

fix what atom did wrong (automatism)

Add PR template

make link from contributing to the code-standards

Update issue_template

Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/359
Reviewed-by: M M Arif <mmarif@swatian.com>
2020-04-06 09:38:02 +00:00
1dc61af683 Add Issue Subscribtion (#203)
rename Context

move things to IssueActions

rm unused API func

get Context only one time

add repoWatch into tinyDB

add maginal Issue Un-/Subscription support

add Issue Subscribtion

 * api
 * layout

Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/203
Reviewed-by: M M Arif <mmarif@swatian.com>
2020-04-05 09:54:34 +00:00
d2490bf6f9 Crowdin [2020-04-04] + add Spanish (#353)
add spanish to config

Merge branch 'master' into add-lang-spanish

Update 2020-04-04

adde Spanish (42% translated)

Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/353
Reviewed-by: M M Arif <mmarif@swatian.com>
2020-04-04 19:29:44 +00:00
1da54e3d35 [UI] Add Pull & Release Counter Badge to TabLable (#350)
fix cp error

fix

reformat code

remove issuesCounter

check if API return new objects, make settings option more generic

Merge branch 'master' into 218-PR-Tab_OpenNumber

add Release Counter

Rename Issue Badge and add Pull Badge

Upgrade Gradle and delete a useles commend

Json Responce: add OpenPullCount and ReleaseCount

Co-authored-by: 6543 <6543@obermui.de>
Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/350
Reviewed-by: M M Arif <mmarif@swatian.com>
2020-04-04 19:20:25 +00:00
c402046699 Introduce snackbar for toast messages (#352)
Merge branch 'master' into 302-snackbar

Added snackbar to login screen

Co-authored-by: 6543 <6543@noreply.gitea.io>
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/352
2020-04-04 19:19:44 +00:00
36ebfff529 Merge pull request 'On Repo Lists: change comment-icon to issue-icon' (#351) from iconchange into master
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/351
Reviewed-by: M M Arif <mmarif@swatian.com>
2020-04-04 06:41:55 +00:00
fe0654b9eb On Repo Lists: change comment-icon to issue-icon 2020-04-04 03:40:08 +02:00
9b3a9aada7 Adding caching to picasso service (#345)
Merge remote-tracking branch 'remotes/main/master' into picasso-img-cache

Some improvements including size management and easy customization.

Improvements to picasso cache

Making PicassoCache public

Moving PicassoCache to helpers/

Merge branch 'master' into picasso-img-cache

Adding options for customisation.

(Hopefully) final bug fixes.

Additional fixes.

Hotfix.

Prevent NullPointerException.

Formatting stuff.

Removing unnecessary permission.

Adding permission.

Adding PicassoCache.

Using max-stale now.

Adding caching to picasso service

Co-authored-by: anonTree1417 <example@example.com>
Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/345
Reviewed-by: 6543 <6543@noreply.gitea.io>
Reviewed-by: M M Arif <mmarif@swatian.com>
2020-04-03 17:02:46 +00:00
9e77e27177 Share comment of an issue (#348)
cleanup

Use html_url to fix issue/pr separation

Share comment of an issue

Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/348
Reviewed-by: 6543 <6543@noreply.gitea.io>
2020-04-03 16:48:22 +00:00
51c281ca30 Merge pull request 'update libs and clean up' (#346) from update-libs into master
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/346
2020-04-03 06:29:57 +00:00
b9ca041c5b update libs and clean up 2020-04-03 11:28:24 +05:00
1d8dc445ec Merge pull request 'Support for self-signed certificates' (#318) from anonTree1417/GitNex:self-signed into master
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/318
Reviewed-by: 6543 <6543@noreply.gitea.io>
Reviewed-by: M M Arif <mmarif@swatian.com>
2020-04-03 06:16:01 +00:00
63865fefec Merge remote-tracking branch 'remotes/main/master' into self-signed
# Conflicts:
#	app/src/main/java/org/mian/gitnex/activities/LoginActivity.java
2020-04-02 23:07:20 +02:00
8234ad77e3 Merge pull request 'Fix #341 - Store UserName on Login first' (#343) from 6543/GitNex:fix-341 into master
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/343
2020-04-02 20:11:18 +00:00
120c83a943 Merge branch 'master' into fix-341 2020-04-02 18:11:23 +00:00
59e8f6f94a Fixing popup bug. 2020-04-02 19:11:23 +02:00
fc532989e5 Fix repos load on initial login and clean ups 2020-04-02 22:04:54 +05:00
ae0009f553 Merge remote-tracking branch 'remotes/main/master' into self-signed
# Conflicts:
#	app/src/main/java/org/mian/gitnex/clients/RetrofitClient.java
2020-04-02 18:50:26 +02:00
7fe583c816 Move WebInterace Calls to own Interface (#338)
optimize imports

Merge branch 'master' into moveWebInteraceCalls-2-ownInterface

Merge branch 'master' into moveWebInteraceCalls-2-ownInterface

move WebInterface calls to own interface

rename WEB api for getting PullDiff

Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/338
Reviewed-by: M M Arif <mmarif@swatian.com>
2020-04-02 16:00:03 +00:00
70581cd330 Updates to settings screen 2020-04-02 20:49:26 +05:00
20ce31fed8 add eng mesage 2020-04-02 17:17:53 +02:00
f53f122a15 add saveUserName step on login 2020-04-02 17:17:00 +02:00
c6125f83c7 Merge remote-tracking branch 'remotes/main/master' into self-signed
# Conflicts:
#	app/src/main/java/org/mian/gitnex/adapters/ExploreRepositoriesAdapter.java
#	app/src/main/java/org/mian/gitnex/adapters/IssueCommentsAdapter.java
#	app/src/main/java/org/mian/gitnex/adapters/IssuesAdapter.java
#	app/src/main/java/org/mian/gitnex/adapters/MyReposListAdapter.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
2020-04-02 10:45:52 +02:00
8853b33c11 Merge pull request 'remove pointless if statements' (#340) from 6543/GitNex:refactor1 into master
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/340
Reviewed-by: M M Arif <mmarif@swatian.com>
2020-04-02 08:12:45 +00:00
733acd0e0b Merge pull request 'Switch to bottomsheets for popup menus' (#333) from 304-popup-menus-to-bottomsheets into master
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/333
Reviewed-by: 6543 <6543@noreply.gitea.io>
2020-04-02 08:05:56 +00:00
b9eee16294 Adding resources. 2020-04-02 03:12:44 +02:00
abdfe8d9d1 Adding option to delete certificates. 2020-04-02 02:59:00 +02:00
f4c4b837de remove pointless if statements 2020-04-02 01:16:07 +02:00
ee0392e208 Very small improvements 2020-04-01 21:58:42 +02:00
b2f34f819c Removing library and commenting out logger. 2020-04-01 18:58:52 +02:00
faaa4db88b Removing option "ONCE" 2020-04-01 18:39:39 +02:00
4217db3e31 Add author to readme 2020-04-01 21:16:59 +05:00
d2f77cfcd0 Fix minor formattings, other improvements 2020-04-01 20:28:14 +05:00
9f6d8239f6 Adding author 2020-04-01 14:38:34 +02:00
0dda996444 Adding Picasso support for self-signed certificates. 2020-04-01 13:26:32 +02:00
c02d7f2df7 Merge branch 'master' of https://gitea.com/gitnex/GitNex into self-signed 2020-04-01 12:00:25 +02:00
9988649714 cleanup 2020-04-01 14:51:37 +05:00
1e52649b76 Added to labels, issue comment 2020-04-01 14:44:38 +05:00
ca37ad661d Changed repos list menus to bottom sheets 2020-04-01 11:38:14 +05:00
11b8bb8d83 Merge pull request 'Add placeholders for images' (#331) from improve-images-loading into master
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/331
Reviewed-by: 6543 <6543@noreply.gitea.io>
2020-04-01 06:09:02 +00:00
786ac3999a Merge branch 'master' into improve-images-loading 2020-03-31 20:40:08 +00:00
e5a656ce57 Many improvements and bug fixes. 2020-03-31 22:09:42 +02:00
5fdbc98d6e Text to resource. 2020-03-31 21:21:49 +02:00
b4996c0e6d Even more reformatting. 2020-03-31 21:14:49 +02:00
28d97f2d67 Merge branch 'master' of https://gitea.com/gitnex/GitNex into self-signed 2020-03-31 21:10:47 +02:00
a53a5d55bf Reformatting applied. 2020-03-31 21:04:53 +02:00
2125d38a66 Adding information at error and resetting button. 2020-03-31 21:04:08 +02:00
b46ad33dd3 Adjusting proportions of issue labels. (#325)
Merge remote-tracking branch 'remotes/main/master' into fab-issue

Adjusting sizes in LabelsAdapter

Adjusting proportions of issue labels.

Co-authored-by: anonTree1417 <example@example.com>
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/325
Reviewed-by: M M Arif <mmarif@swatian.com>
2020-03-31 18:53:36 +00:00
dd2339ec34 Small design changes (#327)
Merge remote-tracking branch 'remotes/main/master' into add-styling

Restoring branches_list.xml

Small design changes.

Co-authored-by: anonTree1417 <example@example.com>
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/327
Reviewed-by: M M Arif <mmarif@swatian.com>
Reviewed-by: 6543 <6543@noreply.gitea.io>
2020-03-31 18:49:39 +00:00
0e365a6d49 Add placeholders for images 2020-03-31 23:46:42 +05:00
d1fe5bdda9 Merge branches 'add-styling', 'self-signed' and 'style-changes' of https://gitea.com/anonTree1417/GitNex into self-signed 2020-03-31 20:25:03 +02:00
5ee872dc6e Merge remote-tracking branch 'remotes/main/master' into self-signed
# Conflicts:
#	app/build.gradle
#	app/src/main/AndroidManifest.xml
#	app/src/main/res/values/strings.xml
2020-03-31 20:20:18 +02:00
d87bd3a8f7 Merge remote-tracking branch 'remotes/main/master' into add-styling 2020-03-31 20:09:06 +02:00
22010d953a Adjusting sizes in LabelsAdapter 2020-03-31 18:43:52 +02:00
f12219ace7 Restoring branches_list.xml 2020-03-31 16:52:39 +02:00
d2190ad189 Moving classes to helpers/ 2020-03-31 16:44:11 +02:00
e1ccb4e404 Fixed formatting. 2020-03-31 16:41:50 +02:00
39ad052ad5 Merge pull request 'Add Discord badge' (#330) from 6543/GitNex:readme-discord into master
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/330
Reviewed-by: M M Arif <mmarif@swatian.com>
2020-03-31 13:25:52 +00:00
0f9025f925 Merge pull request 'Repository Commits' (#308) from 13-repo-commits into master
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/308
Reviewed-by: 6543 <6543@noreply.gitea.io>
2020-03-31 05:11:33 +00:00
60781ac4c3 Small design changes. 2020-03-31 05:14:24 +02:00
6b2be06eda Adjusting proportions of issue labels. 2020-03-31 04:04:11 +02:00
c2505d66b5 Merge branch 'master' into 13-repo-commits 2020-03-30 23:12:07 +00:00
9f30299cfa add Discord badge 2020-03-31 00:12:50 +02:00
2b6d22ed94 Modifying license headers. 2020-03-30 23:25:49 +02:00
aa697d11ad Adding, customizing and modifying MemorizingTrustManager. 2020-03-30 23:01:54 +02:00
6e0880e6d8 Handle reserved names & patterns on repo creation (#315)
correct var names

working solution

code format ...

first draft

Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/315
Reviewed-by: M M Arif <mmarif@swatian.com>
2020-03-29 18:57:19 +00:00
0820dc3480 Merge branch 'master' into 13-repo-commits
# Conflicts:
#	app/src/main/res/values/strings.xml
2020-03-29 19:27:56 +05:00
2fd291527f Enhance user ux to focus on input and trigger keyboard (#314)
Merge branch 'master' into 305-triiger-keyboard

Enhance user ux to focus on input and trigger keyboard

Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/314
Reviewed-by: 6543 <6543@noreply.gitea.io>
2020-03-29 14:24:38 +00:00
d923585d9a Merge pull request 'Code style project wise' (#313) from 216-code-style into master
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/313
Reviewed-by: 6543 <6543@noreply.gitea.io>
2020-03-29 14:18:54 +00:00
e89f12f61e Merge pull request 'Changelog popup' (#296) from 262-changelog-popup into master
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/296
2020-03-29 14:18:20 +00:00
25c6a9558f simplify code 2020-03-29 16:04:04 +02:00
667d98329c Merge branch 'master' into 262-changelog-popup 2020-03-29 13:45:39 +00:00
3955b64efb Add to readme 2020-03-29 16:18:16 +05:00
6e7e3ef690 Code style as whichever is availability in idea 2020-03-29 11:09:51 +05:00
9717589427 Merge pull request 'Fix http protocol' (#311) from 307-fix-open-repo-url into master
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/311
2020-03-28 17:21:12 +00:00
2bda0dbe7e fix http protocol for open repo url 2020-03-28 21:08:11 +05:00
d52ff1557f Fix login issue with internet access. Better solution to check internet connection
with broadcast receiver. Prioritize token login.
2020-03-28 19:49:08 +05:00
6842ba1410 Remove commits tab, moved under branch. Commits are under branches now.
Fixes search ui along the way
2020-03-28 17:44:45 +05:00
21aae88e62 Refactor naming convention for better findings 2020-03-28 15:52:09 +05:00
ea9025296a final implementation and ui completion of commits list 2020-03-27 23:59:24 +05:00
e963d3483b Merge branch 'master' into 262-changelog-popup 2020-03-25 19:48:49 +05:00
c8164c56d0 Initial work on commits list using paging library 2020-03-25 19:43:40 +05:00
162e86f0c0 Merge pull request 'Fix encoding on login' (#306) from fix-encoding into master
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/306
2020-03-24 08:36:24 +00:00
fec0945be9 Fix encoding on login 2020-03-24 13:33:35 +05:00
c3c0749a7a show when update/install app 2020-03-21 23:52:52 +05:00
a9b8e15812 use StandardCharsets instead 2020-03-19 18:54:20 +05:00
c57d39e3f4 Merge branch 'master' into 262-changelog-popup 2020-03-19 18:52:57 +05:00
154065d43c Merge pull request 'hotfix for #297' (#298) from a671916c/GitNex:master into master
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/298
Reviewed-by: M M Arif <mmarif@swatian.com>
2020-03-18 18:24:35 +00:00
0e7df87a60 hotfix for #297 2020-03-18 18:30:18 +01:00
e40eb5e6a1 changelog popup initial working draft 2020-03-17 20:56:37 +05:00
17e9e43454 Merge pull request 'Create repository from organization menu, refactors too' (#295) from 257-add-create-repo-to-org-menu into master
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/295
2020-03-17 10:39:31 +00:00
2b976f58ba Check if data really exists 2020-03-17 15:36:26 +05:00
7e8d2c6ec2 Create repository from organization menu, refactors too 2020-03-17 15:32:03 +05:00
b5b69f377e Merge pull request 'Show only issues' (#294) from 224-show-issues-only into master
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/294
2020-03-17 07:24:13 +00:00
614e053796 Show only issues 2020-03-17 12:19:59 +05:00
da16439975 Merge pull request 'Fix divider color in themes' (#293) from fix-divider-color-in-themes into master
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/293
2020-03-16 20:11:03 +00:00
6cb06d918d Fix divider color in themes 2020-03-17 01:07:23 +05:00
8df11645e8 Add file size to Files (#292)
Merge branch 'master' into 290-file-size

# Conflicts:
#	app/src/main/res/values/strings.xml

Generic word for size text

Add file size to Files

Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/292
2020-03-16 20:01:49 +00:00
ef9a0d57c2 Merge pull request 'Share feature and some refactor to easily manage source code files' (#291) from 282-share-feature into master
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/291
2020-03-16 19:56:40 +00:00
79bd96f6a2 Share feature and some refactor to easily manage source code files 2020-03-17 00:28:03 +05:00
c2e80199ca Merge pull request 'Fix breadcrumb navigation' (#288) from 287-fix-files-breadcrumb-listner into master
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/288
2020-03-16 14:45:42 +00:00
8921543ef5 Fix breadcrumb navigation 2020-03-16 19:30:41 +05:00
e35846ab51 Merge pull request 'update libs, fix required bugs after update libs, bump app ver' (#286) from update-libs into master
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/286
2020-03-16 09:33:45 +00:00
375c12b192 update libs, fix required bugs after update libs, bump app ver 2020-03-16 14:25:15 +05:00
fe22d8ab42 Merge pull request 'crowdin update' (#284) from 6543/GitNex:crowdin_2020-03-15 into master
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/284
Reviewed-by: M M Arif <mmarif@swatian.com>
2020-03-15 18:44:08 +00:00
d16b1580dd crowdin update 2020-03-15 19:36:59 +01:00
c47c81e71f Prepare release 2.4.0 (#283)
Remove Translucent background

Fix missing theme colors, layouts using standard

Fix toolbar color

Prepare 2.4.0 release

Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/283
2020-03-15 15:09:26 +00:00
c981ec2f16 Fixes for 2.4 release (#281)
Fix unnecessary reset for repositories

merge screen background color

Merge branch 'master' into fixes-2.4

Add bottom margin for smaller devices

Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/281
2020-03-14 14:22:50 +00:00
26429ca6e7 Crowdin [2020-03-11] (#277)
update

update from crowdin

Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/277
2020-03-13 19:51:29 +00:00
d06a439382 Merge pull request 'Add page and limit params to required API calls' (#279) from 273-add-page-limit-param into master
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/279
2020-03-13 19:30:11 +00:00
e7433fd67d Merge pull request '[Fileviewer] Download files, Don't render specific files' (#275) from 254-download-files into master
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/275
2020-03-13 19:29:24 +00:00
0467686cc3 Enhance diff view to not render all files (#274)
Merge branch 'master' into 269-dont-render-files

exlucde certain bin files

Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/274
2020-03-13 19:28:29 +00:00
b0d5161c22 Merge pull request 'fix background color' (#280) from fixes-2.4 into master
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/280
2020-03-13 14:32:57 +00:00
64839fdc44 fix background color 2020-03-13 19:30:43 +05:00
d441833952 Add page and limit params to required API calls 2020-03-12 19:56:56 +05:00
a2672560da Merge branch 'master' into 254-download-files 2020-03-11 15:29:37 +00:00
f7d5ee9e7a Update for issue 267 2020-03-09 21:13:40 +05:00
3a481084b6 Merge branch 'master' into 254-download-files
# Conflicts:
#	app/src/main/java/org/mian/gitnex/activities/FileViewActivity.java
2020-03-08 19:24:41 +05:00
4ac1f4f486 Single issue ui enhancements (#272)
Merge branch 'master' into 270-single-issue-ui-enhancements

improve single issue title

Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/272
Reviewed-by: 6543 <6543@noreply.gitea.io>
2020-03-08 14:14:46 +00:00
d2f5f09c75 Merge pull request 'Theme and Icons' (#260) from light-theme into master
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/260
Reviewed-by: 6543 <6543@noreply.gitea.io>
2020-03-08 13:52:25 +00:00
181a94edbe download file and ask for permissions to write into storage 2020-03-08 12:46:31 +05:00
5b8c485883 Fix variable name 2020-03-08 10:54:33 +05:00
3794d7ff2b wip on download files 2020-03-08 10:53:00 +05:00
9a9b836c40 Fix file diff background 2020-03-07 13:30:45 +05:00
900b060c31 Use only one statement for new theme. 2020-03-07 01:07:54 +05:00
61f953d70d Fixes layout issue with themes, added pdf night mode switch in settings 2020-03-06 18:46:22 +05:00
14addf5ed0 added theme selection to settings, updated login layout. 2020-03-06 01:56:42 +05:00
b012a7058d Fixes to color styles and layouts 2020-03-05 20:23:15 +05:00
51ab3f7a92 updated all the layouts and activities 2020-03-05 00:37:28 +05:00
a8cc4c00b8 worked on repo info, files tabs and files activity 2020-03-04 21:15:57 +05:00
d557999a38 Merge branch 'master' into light-theme 2020-03-04 19:58:03 +05:00
1008b8611d Added custom attr to more files 2020-03-04 19:54:21 +05:00
3f4db112b1 Refactor assignee(s) API calls (#199)
Merge branch 'master' into refactor_issues_call

Remove credits, add donators (#268)

Merge branch 'master' into 264-remove-credits

Merge pull request 'Support for c header files' (#266) from 265-files-support-in-file-viewer into master

Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/266

Remove credits, add donators

support for c header files

Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/268

Merge pull request 'Support for c header files' (#266) from 265-files-support-in-file-viewer into master

Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/266

support for c header files

fix

Merge branch 'master' into refactor_issues_call

Support pdf files in file viewer (#259)

auto convert EOL

this fix it for me

fix layout

implement support for pdf files in file viewer

Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/259
Reviewed-by: 6543 <6543@noreply.gitea.io>

Make DueDate optional on MilestoneCreaton (#252)

Merge branch 'master' into milestone-DueDate-optional_240

add check again if gitea is older than 1.10.0 ...

Crowdin [2020-01-04] + add Latvian (#253)

update Translators

add Latvian

update Crowdin

Co-authored-by: 6543 <6543@obermui.de>

make DueDate optional on MilestoneCreaton

Co-authored-by: 6543 <6543@obermui.de>

Crowdin [2020-01-04] + add Latvian (#253)

update Translators

add Latvian

update Crowdin

Co-authored-by: 6543 <6543@obermui.de>

Merge branch '51-custom-fonts' of gitnex/GitNex into master

Reviewed-by: 6543 <6543@noreply.gitea.io>

Implement across the whole app

Implementation of custom fonts app wide

Merge branch 'crowdin_2019-12-25' of gitnex/GitNex into master

add user to the “new issue” assignees dialog

refactor.start()

update from crowdin

Merge branch 'backport-243' of gitnex/GitNex into master

backport url slashes fix

Merge branch 'fix-238' of gitnex/GitNex into master

fix

Merge branch 'backport-235' of gitnex/GitNex into master

backport fix #235

Merge branch 'backport-232' of gitnex/GitNex into master

show all issues and prs

Merge branch '206-repos-in-explore-screen' of gitnex/GitNex into master

Load default list of explore repositories

Merge branch '225-backport' of gitnex/GitNex into master

copy and support files backport - #225

Merge branch '226-backport' of gitnex/GitNex into master

fix alignments backport

Co-authored-by: M M Arif <mmarif@swatian.com>
Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/199
2020-02-24 18:50:51 +00:00
5720c5f613 Remove credits, add donators (#268)
Merge branch 'master' into 264-remove-credits

Merge pull request 'Support for c header files' (#266) from 265-files-support-in-file-viewer into master

Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/266

Remove credits, add donators

support for c header files

Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/268
2020-02-21 05:58:36 +00:00
e0b25c77a0 Merge pull request 'Support for c header files' (#266) from 265-files-support-in-file-viewer into master
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/266
2020-02-21 05:54:53 +00:00
2c163fdc9c support for c header files 2020-02-20 10:24:14 +05:00
acdb9ce682 updates to other files 2020-02-20 10:19:52 +05:00
dbcd80eace updated settings, star and my repos layouts 2020-02-04 19:19:39 +05:00
8b75cac9d8 New spinner style 2020-02-03 00:14:38 +05:00
1293e8be27 Support pdf files in file viewer (#259)
auto convert EOL

this fix it for me

fix layout

implement support for pdf files in file viewer

Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/259
Reviewed-by: 6543 <6543@noreply.gitea.io>
2020-01-30 18:00:31 +00:00
50671907ba changed checkbox style and input background 2020-01-29 19:31:27 +05:00
ec62e3cebf Make DueDate optional on MilestoneCreaton (#252)
Merge branch 'master' into milestone-DueDate-optional_240

add check again if gitea is older than 1.10.0 ...

Crowdin [2020-01-04] + add Latvian (#253)

update Translators

add Latvian

update Crowdin

Co-authored-by: 6543 <6543@obermui.de>

make DueDate optional on MilestoneCreaton

Co-authored-by: 6543 <6543@obermui.de>
2020-01-14 12:52:34 +00:00
36774620db initial work on adding new theme 2020-01-07 17:27:05 +05:00
b3e67113f5 Crowdin [2020-01-04] + add Latvian (#253)
update Translators

add Latvian

update Crowdin

Co-authored-by: 6543 <6543@obermui.de>
2020-01-05 12:07:29 +00:00
d8de0effef Merge branch '51-custom-fonts' of gitnex/GitNex into master
Reviewed-by: 6543 <6543@noreply.gitea.io>
2020-01-02 14:40:28 +00:00
0533fd9ae5 Implement across the whole app 2020-01-02 12:51:10 +05:00
6d7308210b Implementation of custom fonts app wide 2020-01-02 01:03:53 +05:00
e9dcfc57f7 Merge branch 'crowdin_2019-12-25' of gitnex/GitNex into master 2019-12-26 02:07:36 +00:00
ab6f5d3364 update from crowdin 2019-12-25 20:48:52 +01:00
e422e3e254 Merge branch 'backport-243' of gitnex/GitNex into master 2019-12-25 19:18:17 +00:00
a00d76d0e2 backport url slashes fix 2019-12-26 00:14:33 +05:00
f68c26b70d Merge branch 'fix-238' of gitnex/GitNex into master 2019-12-24 19:22:14 +00:00
25cc2f27ee fix 2019-12-24 17:09:24 +01:00
72ccc06226 Merge branch 'backport-235' of gitnex/GitNex into master 2019-12-13 13:38:09 +00:00
9a66ea0fb6 backport fix #235 2019-12-13 13:55:58 +05:00
aab9ae9e35 Merge branch 'backport-232' of gitnex/GitNex into master 2019-12-04 18:41:19 +00:00
d922c21f70 show all issues and prs 2019-12-04 23:38:53 +05:00
6e02fc1827 Merge branch '206-repos-in-explore-screen' of gitnex/GitNex into master 2019-12-03 16:27:18 +00:00
536665be5f Load default list of explore repositories 2019-12-03 18:20:26 +05:00
29cc8a2ad4 Merge branch '225-backport' of gitnex/GitNex into master 2019-12-02 15:00:37 +00:00
7d4d7cfa69 copy and support files backport - #225 2019-12-02 19:58:36 +05:00
48638e93be Merge branch '226-backport' of gitnex/GitNex into master 2019-12-02 14:55:12 +00:00
584c08ff70 fix alignments backport 2019-12-02 19:52:11 +05:00
13a0b55612 Merge branch 'prepare-release-2.3' of gitnex/GitNex into master 2019-11-29 12:33:00 +00:00
94d4dbf440 add new sponsors 2019-11-29 17:31:19 +05:00
82034273c4 Crowdin [2019-11-29] + smal doc (#220) 2019-11-29 12:29:44 +00:00
cf22a5d5fa Merge branch 'allowRestrictedApi' of Unpublished/GitNex into master 2019-11-27 20:06:29 +00:00
fde33dbc3e Allow login if api is restricted 2019-11-27 20:27:31 +01:00
85a7fddc49 Merge branch '171-screens' of gitnex/GitNex into master 2019-11-27 18:05:55 +00:00
25fbc4b017 Add screens, update readme, f-droid desc 2019-11-27 22:55:09 +05:00
fc02b652f5 [Crowdin] 2019-11-27 + add Portuguese/Brazilian (#211) 2019-11-27 17:05:32 +00:00
a32e11c172 Merge branch '10-merge-pr' of gitnex/GitNex into master 2019-11-27 17:03:49 +00:00
51dc31ef15 merge pull request activity and call 2019-11-27 20:09:26 +05:00
5b4cb3ff8e Added interface and model 2019-11-25 19:19:13 +05:00
0daf0d1110 Merge branch '207-move-version-to-main-activity' of gitnex/GitNex into master 2019-11-25 13:14:33 +00:00
533be20f46 Move Gitea version to main activity 2019-11-25 18:12:44 +05:00
8b88dca833 Merge branch '205-refactor-version-code' of gitnex/GitNex into master 2019-11-25 13:06:52 +00:00
94d6334e52 refactor versions 2019-11-25 18:04:34 +05:00
79f6a2435b Crowdin [2019-11-25] + add Ukrainian (#204) 2019-11-25 12:12:11 +00:00
9f5eceff0e Repository PR List (#198) 2019-11-24 12:42:57 +00:00
f9550ad115 Merge branch '119-app-tokens' of gitnex/GitNex into master 2019-11-16 05:18:41 +00:00
7e8a2722ac Fix creating multiple tokens. The changes were from upstream API 2019-11-16 00:39:09 +05:00
51da8b9c4d Merge branch 'refactor-donate-credit-pages' of gitnex/GitNex into master 2019-11-14 17:00:24 +00:00
29fb2631cb refactored credit activtiy 2019-11-14 21:58:38 +05:00
126d1d0896 Refactor sponsors activity 2019-11-13 23:23:20 +05:00
b6c0e94ee9 Offline mode (#190) 2019-11-13 15:52:49 +00:00
80445952b1 Crowdin [2019-11-09] (#194) 2019-11-13 13:49:51 +00:00
d61fb8a0c6 Merge branch 'crowdin_2019-11-07' of gitnex/GitNex into master 2019-11-07 14:05:22 +00:00
51c88e9f45 update from crowdin 2019-11-07 13:31:35 +01:00
463961800f [File View] add highlight sourcecode (#187) 2019-11-05 08:34:22 +00:00
04073ac873 tocken name with Device ID (#184) 2019-11-01 06:01:30 +00:00
26b93a4280 Merge branch '182-fix-date-layout' of gitnex/GitNex into master 2019-10-31 14:29:48 +00:00
71be20b1b9 increase space for date and time 2019-10-31 18:23:36 +05:00
9f833259f7 Add limit to explore API 2019-10-31 18:16:11 +05:00
d184bdca12 Merge branch '175-fileview-support-images' of gitnex/GitNex into master 2019-10-30 18:00:03 +00:00
15b320f4bd Images support in file viewer. Android Q support. 2019-10-30 19:04:49 +05:00
fdc1514f5f Merge branch 'change-in-search-176' of gitnex/GitNex into master 2019-10-29 06:32:39 +00:00
67f4283cb9 Use search and magnify icon 2019-10-29 11:28:59 +05:00
fc2b09b91c Crowdin [2019-10-28] + Turkish support (#177) 2019-10-29 05:34:01 +00:00
eb38df745c Merge branch '94-login-via-token' of gitnex/GitNex into master 2019-10-26 18:38:58 +00:00
8787f8d9eb store loginUid on login 2019-10-26 18:01:14 +05:00
7e3eef90d2 radio buttons style to match the theme. error toast on failure 2019-10-25 23:19:16 +05:00
c4b0b596d3 fixes in fdroid repository description file 2019-10-25 10:55:00 +05:00
2aaf0eb103 refactor the strings and reuse them in login screen files 2019-10-25 08:38:35 +05:00
f9d51094e4 done with token logins, refactor some code 2019-10-24 22:42:09 +05:00
96ab992264 implement login via token 2019-10-24 20:48:00 +05:00
bc2b609585 Merge branch '166-improve-edit-button-api-calls' of gitnex/GitNex into master 2019-10-22 16:42:03 +00:00
2a05d4e24b improve edit button on tap 2019-10-22 21:37:11 +05:00
fb9d101283 Merge branch 'app-color-scheme' of gitnex/GitNex into master 2019-10-22 16:03:55 +00:00
ef2f5a9667 change color scheme 2019-10-22 21:00:55 +05:00
d14ecd9c68 Version Check before try to Login (#147) 2019-10-22 15:27:33 +00:00
d29b1901c0 Merge branch '158-fix-email-login' of gitnex/GitNex into master 2019-10-21 16:46:28 +00:00
6d7fcd8430 Fix login with email for my repositories 2019-10-21 20:39:42 +05:00
b6ca7bf2a4 Merge branch 'fix-empty-repo-bug' of gitnex/GitNex into master 2019-10-18 13:44:29 +00:00
67add714b3 Merge branch 'prepare-release-2.2' of gitnex/GitNex into master 2019-10-18 06:47:22 +00:00
405 changed files with 19285 additions and 5929 deletions

View File

@ -24,6 +24,32 @@ steps:
commands: commands:
- ./gradlew build - ./gradlew build
- name: sign
image: nextcloudci/android:android-49
environment:
TOKEN:
from_secret: BOT_TOKEN
KS_PASS:
from_secret: KS_PASS
KEY_PASS:
from_secret: KEY_PASS
OUTPUT: signed.apk
GITEA: https://gitea.com
KS_FILE: ci_keystore.jks
KS_REPO:
from_secret: KS_REPO
commands:
- ./scripts/sign-build.sh
- name: publish
image: vividboarder/drone-webdav
environment:
WEBDAV_USERNAME: GitNexBot
WEBDAV_PASSWORD:
from_secret: NC_TOKEN
PLUGIN_FILE: signed.apk
PLUGIN_DESTINATION: https://cloud.swatian.com/remote.php/dav/files/GitNexBot/GitNex-Builds/latest.apk
trigger: trigger:
event: event:
- push - push

1
.gitattributes vendored Normal file
View File

@ -0,0 +1 @@
* text=auto eol=lf

31
.gitea/issue_template.md Normal file
View File

@ -0,0 +1,31 @@
## # What do you want to address?
(This step is required; examples are shown below)
- [ ] Bug
- [ ] Feature
- [ ] Suggestion
## # Describe your matter briefly
(This step is required)
##### What did you expect? (Useful when addressing bugs)
---
_(This step is optional)_
##### Some additional details (Useful, when we are trying to reproduce a bug)
---
_(This step is optional; an example is shown below)_
* The version of **Gitea** you are using:
* The version of **GitNex** you are using:
* The type of certificate you are using (self-signed, signed):
* How you used to log in (via password or token):
##### We would appreciate some screenshots or stacktrace's, but this is also not required.
---
_(Screenshots and stacktrace's can go here)_
#### Thank you for your time.

View File

@ -0,0 +1,8 @@
Please check the following:
1. Make sure you are targeting the `master` branch, pull requests on release branches are only allowed for bug fixes.
2. Read contributing guidelines: [CONTRIBUTING.md](https://gitea.com/GitNex/GitNex/src/branch/master/CONTRIBUTING.md)
3. Please follow the [Code-Standards](https://gitea.com/gitnex/GitNex/wiki/Code-Standards)
4. Describe what your pull request does and which issue youre targeting (create one if does not exist)
**You MUST delete the content above including this line before posting, otherwise your pull request will be invalid.**

4
.gitignore vendored
View File

@ -8,6 +8,9 @@
*.ap_ *.ap_
*.aab *.aab
# Release dir
app/release/*
# Files for the ART/Dalvik VM # Files for the ART/Dalvik VM
*.dex *.dex
@ -48,6 +51,7 @@ captures/
.idea/dictionaries .idea/dictionaries
.idea/libraries .idea/libraries
.idea/caches .idea/caches
!.idea/codeStyles
# Keystore files # Keystore files
# Uncomment the following lines if you do not want to check your keystore files in. # Uncomment the following lines if you do not want to check your keystore files in.

159
.idea/codeStyles/Project.xml generated Normal file
View File

@ -0,0 +1,159 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<JavaCodeStyleSettings>
<option name="IMPORT_LAYOUT_TABLE">
<value>
<package name="android" withSubpackages="true" static="false" />
<package name="androidx" withSubpackages="true" static="false" />
<package name="com" withSubpackages="true" static="false" />
<package name="junit" withSubpackages="true" static="false" />
<package name="net" withSubpackages="true" static="false" />
<package name="org" withSubpackages="true" static="false" />
<package name="java" withSubpackages="true" static="false" />
<package name="javax" withSubpackages="true" static="false" />
<package name="" withSubpackages="true" static="false" />
<package name="" withSubpackages="true" static="true" />
</value>
</option>
</JavaCodeStyleSettings>
<codeStyleSettings language="JAVA">
<option name="RIGHT_MARGIN" value="220" />
<option name="KEEP_LINE_BREAKS" value="false" />
<option name="KEEP_FIRST_COLUMN_COMMENT" value="false" />
<option name="KEEP_CONTROL_STATEMENT_IN_ONE_LINE" value="false" />
<option name="BLANK_LINES_BEFORE_METHOD_BODY" value="1" />
<option name="BLANK_LINES_AROUND_FIELD_IN_INTERFACE" value="1" />
<option name="BLANK_LINES_AFTER_CLASS_HEADER" value="1" />
<option name="BLANK_LINES_AFTER_ANONYMOUS_CLASS_HEADER" value="1" />
<option name="BLANK_LINES_BEFORE_CLASS_END" value="1" />
<option name="ELSE_ON_NEW_LINE" value="true" />
<option name="CATCH_ON_NEW_LINE" value="true" />
<option name="FINALLY_ON_NEW_LINE" value="true" />
<option name="SPACE_BEFORE_IF_PARENTHESES" value="false" />
<option name="SPACE_BEFORE_WHILE_PARENTHESES" value="false" />
<option name="SPACE_BEFORE_FOR_PARENTHESES" value="false" />
<option name="SPACE_BEFORE_TRY_PARENTHESES" value="false" />
<option name="SPACE_BEFORE_CATCH_PARENTHESES" value="false" />
<option name="SPACE_BEFORE_SWITCH_PARENTHESES" value="false" />
<option name="SPACE_BEFORE_SYNCHRONIZED_PARENTHESES" value="false" />
<option name="IF_BRACE_FORCE" value="3" />
<option name="WRAP_ON_TYPING" value="1" />
<indentOptions>
<option name="USE_TAB_CHARACTER" value="true" />
<option name="SMART_TABS" value="true" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="XML">
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="4" />
</indentOptions>
<arrangement>
<rules>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:android</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:id</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:name</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>name</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>style</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>ANDROID_ATTRIBUTE_ORDER</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>.*</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
</rules>
</arrangement>
</codeStyleSettings>
</code_scheme>
</component>

5
.idea/codeStyles/codeStyleConfig.xml generated Normal file
View File

@ -0,0 +1,5 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
</state>
</component>

View File

@ -7,6 +7,11 @@ Patches, enhancements, features are always welcome. The PR should focus on the s
Please ask if you are not sure about the scope of work to be submitted to avoid waste of time spent on the work. Please ask if you are not sure about the scope of work to be submitted to avoid waste of time spent on the work.
**Code Standards**
Please follow the code standards, this will help other developers to understand your code too.
It also helps maintaining the code afterwards.
It is documented in the Wiki: [Code-Standards](https://gitea.com/gitnex/GitNex/wiki/Code-Standards)
**How to submit a 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. 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.

View File

@ -3,20 +3,34 @@ This part lists all PUBLIC individuals having contributed content to the code.
* M M Arif (mmarif) * M M Arif (mmarif)
* 6543 * 6543
* Unpublished
# Translators # Translators
This part lists all PUBLIC individuals having contributed content to the translation. This part lists all PUBLIC individuals having contributed content to the translation.
*Entries are in alphabetical order* *Entries are in alphabetical order*
* 6543 * 6543
* acrylicpaintboy
* Antoine GIRARD (sapk)
* BaRaN6161_TURK
* ButterflyOfFire (BoFFire) * ButterflyOfFire (BoFFire)
* dadosch
* erardiflorian
* IndeedNotJames * IndeedNotJames
* jaqra
* Lafriks
* ljoonal
* Lunny Xiao (xiaolunwen) * Lunny Xiao (xiaolunwen)
* lxs
* Marcos de Oliveira (markkrj)
* mmarif * mmarif
* Nadezhda Moiseeva (digitalkiller) * Nadezhda Moiseeva (digitalkiller)
* Oleg Popenkov (FanHamMer)
* PsychotherapistSam * PsychotherapistSam
* Rodion Borisov (vintproykt) * Rodion Borisov (vintproykt)
* s4ne
* valeriezhao1013 * valeriezhao1013
* Vladislav Glinsky (cl0ne)
* Voyvode * Voyvode
**Thank you for all your work** :+1: **Thank you for all your work** :+1:

View File

@ -2,6 +2,7 @@
[![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) [![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) [![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) [![Crowdin](https://badges.crowdin.net/gitnex/localized.svg)](https://crowdin.com/project/gitnex)
[![Join the Discord chat at https://discord.gg/FbSS4rf](https://img.shields.io/discord/632219664587685908.svg)](https://discord.gg/FbSS4rf)
[<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="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) [<img alt="Donate using Liberapay" src="https://liberapay.com/assets/widgets/donate.svg" height="40"/>](https://liberapay.com/mmarif/donate)
@ -19,7 +20,7 @@ No trackers are used and source code is available here for anyone to audit.
[<img alt='Download APK' src='https://gitnex.com/img/download-apk.png' height="80"/>](https://gitea.com/gitnex/GitNex/releases) [<img alt='Download APK' src='https://gitnex.com/img/download-apk.png' height="80"/>](https://gitea.com/gitnex/GitNex/releases)
## Note about Gitea version ## Note about Gitea version
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. Please make sure that you are on latest stable release or later for better app experience.
Check the versions [compatibility page](https://gitea.com/gitnex/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.
@ -29,12 +30,12 @@ Option 1 - Download the source code, open it in Android Studio and build it ther
Option 2 - Open terminal(Linux) and cd to the project dir. Run `./gradlew build`. Option 2 - Open terminal(Linux) and cd to the project dir. Run `./gradlew build`.
## Features ## Features
- My Repositories - File and directory browser
- Repositories list - Create files
- Organizations list - Explore repositories
- Create repository
- Create organization
- Issues list - Issues list
- Pull requests
- Merge pull request
- [MANY MORE](https://gitea.com/gitnex/GitNex/wiki/Features) - [MANY MORE](https://gitea.com/gitnex/GitNex/wiki/Features)
## Contributing ## Contributing
@ -83,6 +84,14 @@ Open source libraries
- Abumoallim/android-multi-select-dialog - Abumoallim/android-multi-select-dialog
- Pes/materialcolorpicker - Pes/materialcolorpicker
- Hendraanggrian/socialview - Hendraanggrian/socialview
- Fython/BreadcrumbsView - HamidrezaAmz/BreadcrumbsView
- Chrisbanes/PhotoView
- Pddstudio/highlightjs-android
- Apache/commons-io
- Caverock/androidsvg
- Droidsonroids.gif/android-gif-drawable
- Barteksc/AndroidPdfViewer
- Mikepenz/fastadapter
- Ge0rg/MemorizingTrustManager
[Follow me on Fediverse - mastodon.social/@mmarif](https://mastodon.social/@mmarif) [Follow me on Fediverse - mastodon.social/@mmarif](https://mastodon.social/@mmarif)

View File

@ -1,18 +1,19 @@
apply plugin: 'com.android.application' apply plugin: 'com.android.application'
android { android {
compileSdkVersion 28 compileSdkVersion 29
defaultConfig { defaultConfig {
applicationId "org.mian.gitnex" applicationId "org.mian.gitnex"
minSdkVersion 21 minSdkVersion 21
targetSdkVersion 28 targetSdkVersion 29
versionCode 70 versionCode 250
versionName "2.2.0" versionName "2.5.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
} }
buildTypes { buildTypes {
release { release {
minifyEnabled false minifyEnabled false
shrinkResources false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
} }
} }
@ -20,33 +21,43 @@ android {
//checkReleaseBuilds false //checkReleaseBuilds false
abortOnError false abortOnError false
} }
compileOptions {
targetCompatibility = "8"
sourceCompatibility = "8"
}
}
configurations {
cleanedAnnotations
compile.exclude group: 'org.jetbrains', module: 'annotations'
} }
dependencies { dependencies {
def lifecycle_version = "2.2.0-beta01" def lifecycle_version = "2.2.0"
final def markwon_version = "4.1.1" def markwon_version = '4.3.1'
def fastadapter = "3.3.1"
def acra = "5.5.0"
implementation fileTree(include: ['*.jar'], dir: 'libs') implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'androidx.appcompat:appcompat:1.1.0' implementation "androidx.appcompat:appcompat:1.1.0"
implementation 'com.google.android.material:material:1.1.0-beta01' implementation "com.google.android.material:material:1.2.0-alpha06"
implementation 'androidx.constraintlayout:constraintlayout:1.1.3' implementation "androidx.constraintlayout:constraintlayout:1.1.3"
implementation 'androidx.legacy:legacy-support-v4:1.0.0' implementation "androidx.legacy:legacy-support-v4:1.0.0"
testImplementation 'junit:junit:4.12' testImplementation "junit:junit:4.13"
androidTestImplementation 'androidx.test:runner:1.2.0' androidTestImplementation "androidx.test:runner:1.2.0"
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' androidTestImplementation "androidx.test.espresso:espresso-core:3.2.0"
implementation 'com.github.vihtarb:tooltip:0.2.0' implementation "com.github.vihtarb:tooltip:0.2.0"
implementation 'com.squareup.okhttp3:okhttp:3.12.1' implementation 'com.squareup.okhttp3:okhttp:4.5.0'
implementation 'com.google.code.gson:gson:2.8.5' implementation "com.google.code.gson:gson:2.8.6"
implementation 'com.squareup.picasso:picasso:2.71828' implementation "com.squareup.picasso:picasso:2.71828"
implementation 'com.amulyakhare:com.amulyakhare.textdrawable:1.0.1' implementation "com.amulyakhare:com.amulyakhare.textdrawable:1.0.1"
implementation 'com.squareup.retrofit2:retrofit:2.5.0' implementation 'com.squareup.retrofit2:retrofit:2.8.1'
implementation 'com.squareup.retrofit2:converter-gson:2.5.0' implementation 'com.squareup.retrofit2:converter-gson:2.8.1'
implementation 'com.squareup.retrofit2:converter-scalars:2.5.0' implementation 'com.squareup.retrofit2:converter-scalars:2.8.1'
implementation 'com.squareup.okhttp3:logging-interceptor:3.12.1' implementation 'com.squareup.okhttp3:logging-interceptor:4.5.0'
implementation 'org.ocpsoft.prettytime:prettytime:4.0.1.Final' implementation 'org.ocpsoft.prettytime:prettytime:4.0.4.Final'
implementation "com.vdurmont:emoji-java:4.0.0" implementation "com.vdurmont:emoji-java:5.1.1"
implementation "com.pes.materialcolorpicker:library:1.2.5" implementation "com.pes.materialcolorpicker:library:1.2.5"
implementation "io.noties.markwon:core:$markwon_version" implementation "io.noties.markwon:core:$markwon_version"
implementation "io.noties.markwon:ext-latex:$markwon_version" implementation "io.noties.markwon:ext-latex:$markwon_version"
implementation "io.noties.markwon:ext-strikethrough:$markwon_version" implementation "io.noties.markwon:ext-strikethrough:$markwon_version"
@ -61,13 +72,22 @@ dependencies {
implementation "io.noties.markwon:simple-ext:$markwon_version" implementation "io.noties.markwon:simple-ext:$markwon_version"
implementation "io.noties.markwon:syntax-highlight:$markwon_version" implementation "io.noties.markwon:syntax-highlight:$markwon_version"
implementation "com.caverock:androidsvg:1.4" implementation "com.caverock:androidsvg:1.4"
implementation "pl.droidsonroids.gif:android-gif-drawable:1.2.14" implementation "pl.droidsonroids.gif:android-gif-drawable:1.2.19"
implementation "com.hendraanggrian.appcompat:socialview:0.2" implementation "com.hendraanggrian.appcompat:socialview:0.2"
implementation "com.hendraanggrian.appcompat:socialview-commons:0.2" implementation "com.hendraanggrian.appcompat:socialview-commons:0.2"
implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version" implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-viewmodel:$lifecycle_version" implementation "androidx.lifecycle:lifecycle-viewmodel:$lifecycle_version"
implementation "com.github.HamidrezaAmz:BreadcrumbsView:0.2.9" implementation "com.github.HamidrezaAmz:BreadcrumbsView:0.2.9"
implementation "commons-io:commons-io:20030203.000550"
implementation "com.github.chrisbanes:PhotoView:2.3.0"
implementation "com.pddstudio:highlightjs-android:1.5.0"
implementation "com.github.barteksc:android-pdf-viewer:3.2.0-beta.1"
//noinspection GradleDependency
implementation "com.mikepenz:fastadapter:$fastadapter"
implementation "com.mikepenz:fastadapter-commons:$fastadapter"
implementation "com.mikepenz:fastadapter-extensions:$fastadapter"
implementation "ch.acra:acra-mail:$acra"
implementation "ch.acra:acra-limiter:$acra"
implementation "ch.acra:acra-notification:$acra"
} }

View File

@ -1,7 +1,12 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="org.mian.gitnex"> package="org.mian.gitnex">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application <application
android:allowBackup="true" android:allowBackup="true"
android:icon="@mipmap/app_logo" android:icon="@mipmap/app_logo"
@ -9,12 +14,13 @@
android:networkSecurityConfig="@xml/network_security_config" android:networkSecurityConfig="@xml/network_security_config"
android:roundIcon="@mipmap/app_logo_round" android:roundIcon="@mipmap/app_logo_round"
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/AppTheme"> tools:targetApi="n">
<activity android:name=".activities.MergePullRequestActivity" />
<activity <activity
android:name=".activities.FileViewActivity" android:name=".activities.FileViewActivity"
android:theme="@style/AppTheme.NoActionBar"></activity> android:theme="@style/AppTheme.NoActionBar" />
<activity <activity
android:name=".activities.NewFileActivity" android:name=".activities.CreateFileActivity"
android:theme="@style/AppTheme.NoActionBar" /> android:theme="@style/AppTheme.NoActionBar" />
<activity <activity
android:name=".activities.RepoWatchersActivity" android:name=".activities.RepoWatchersActivity"
@ -35,16 +41,16 @@
<activity android:name=".activities.ProfileEmailActivity" /> <activity android:name=".activities.ProfileEmailActivity" />
<activity android:name=".activities.AddCollaboratorToRepositoryActivity" /> <activity android:name=".activities.AddCollaboratorToRepositoryActivity" />
<activity android:name=".activities.CreateTeamByOrgActivity" /> <activity android:name=".activities.CreateTeamByOrgActivity" />
<activity android:name=".activities.OrgTeamMembersActivity" /> <activity android:name=".activities.OrganizationTeamMembersActivity" />
<activity <activity
android:name=".activities.OrgDetailActivity" android:name=".activities.OrganizationDetailActivity"
android:label="@string/title_activity_org_detail" android:label="@string/title_activity_org_detail"
android:theme="@style/AppTheme.NoActionBar" /> android:theme="@style/AppTheme.NoActionBar" />
<activity android:name=".activities.SponsorsActivity" /> <activity android:name=".activities.SponsorsActivity" />
<activity android:name=".activities.CreditsActivity" /> <activity android:name=".activities.CreditsActivity" />
<activity android:name=".activities.CreateLabelActivity" /> <activity android:name=".activities.CreateLabelActivity" />
<activity android:name=".activities.CreateIssueActivity" /> <activity android:name=".activities.CreateIssueActivity" />
<activity android:name=".activities.NewMilestoneActivity" /> <activity android:name=".activities.CreateMilestoneActivity" />
<activity android:name=".activities.ReplyToIssueActivity" /> <activity android:name=".activities.ReplyToIssueActivity" />
<activity <activity
android:name=".activities.IssueDetailActivity" android:name=".activities.IssueDetailActivity"
@ -53,7 +59,7 @@
android:name=".activities.RepoDetailActivity" android:name=".activities.RepoDetailActivity"
android:label="@string/title_activity_repo_detail" android:label="@string/title_activity_repo_detail"
android:theme="@style/AppTheme.NoActionBar" /> android:theme="@style/AppTheme.NoActionBar" />
<activity android:name=".activities.MainActivity"> <activity android:name=".activities.MainActivity" android:theme="@android:style/Theme.NoTitleBar">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
@ -62,13 +68,13 @@
</activity> </activity>
<activity <activity
android:name=".activities.LoginActivity" android:name=".activities.LoginActivity"
android:launchMode="singleTask" /> android:launchMode="singleTask" android:theme="@android:style/Theme.NoTitleBar"/>
<activity android:name=".activities.NewRepoActivity" /> <activity android:name=".activities.CreateRepoActivity" />
<activity android:name=".activities.NewOrganizationActivity" /> <activity android:name=".activities.CreateOrganizationActivity" />
<activity android:name=".activities.OpenRepoInBrowserActivity" /> <activity android:name=".activities.OpenRepoInBrowserActivity" />
<activity android:name=".activities.FileDiffActivity" />
<activity android:name=".activities.CommitsActivity" />
<activity android:name=".helpers.ssl.MemorizingActivity" android:theme="@android:style/Theme.Material.Dialog" />
</application> </application>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
</manifest> </manifest>

Binary file not shown.

View File

@ -35,7 +35,7 @@ public class CollaboratorActions {
Call<Collaborators> call; Call<Collaborators> call;
call = RetrofitClient call = RetrofitClient
.getInstance(instanceUrl) .getInstance(instanceUrl, context)
.getApiInterface() .getApiInterface()
.deleteCollaborator(Authorization.returnAuthentication(context, loginUid, instanceToken), repoOwner, repoName, userName); .deleteCollaborator(Authorization.returnAuthentication(context, loginUid, instanceToken), repoOwner, repoName, userName);
@ -105,7 +105,7 @@ public class CollaboratorActions {
Call<Permission> call; Call<Permission> call;
call = RetrofitClient call = RetrofitClient
.getInstance(instanceUrl) .getInstance(instanceUrl, context)
.getApiInterface() .getApiInterface()
.addCollaborator(Authorization.returnAuthentication(context, loginUid, instanceToken), repoOwner, repoName, userName, permissionString); .addCollaborator(Authorization.returnAuthentication(context, loginUid, instanceToken), repoOwner, repoName, userName, permissionString);

View File

@ -2,6 +2,8 @@ package org.mian.gitnex.actions;
import android.content.Context; import android.content.Context;
import android.util.Log; import android.util.Log;
import android.view.View;
import android.widget.TextView;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import org.mian.gitnex.R; import org.mian.gitnex.R;
import org.mian.gitnex.activities.ReplyToIssueActivity; import org.mian.gitnex.activities.ReplyToIssueActivity;
@ -22,9 +24,9 @@ import retrofit2.Callback;
public class IssueActions { public class IssueActions {
public static void editIssueComment(final Context context, final int commentId, final String commentBody) { public static void editIssueComment(final Context ctx, final int commentId, final String commentBody) {
final TinyDB tinyDb = new TinyDB(context); final TinyDB tinyDb = new TinyDB(ctx);
final String instanceUrl = tinyDb.getString("instanceUrl"); final String instanceUrl = tinyDb.getString("instanceUrl");
final String loginUid = tinyDb.getString("loginUid"); final String loginUid = tinyDb.getString("loginUid");
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token"); final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
@ -37,9 +39,9 @@ public class IssueActions {
Call<IssueComments> call; Call<IssueComments> call;
call = RetrofitClient call = RetrofitClient
.getInstance(instanceUrl) .getInstance(instanceUrl, ctx)
.getApiInterface() .getApiInterface()
.patchIssueComment(Authorization.returnAuthentication(context, loginUid, instanceToken), repoOwner, repoName, commentId, commentBodyJson); .patchIssueComment(Authorization.returnAuthentication(ctx, loginUid, instanceToken), repoOwner, repoName, commentId, commentBodyJson);
call.enqueue(new Callback<IssueComments>() { call.enqueue(new Callback<IssueComments>() {
@ -50,32 +52,32 @@ public class IssueActions {
if(response.code() == 200) { if(response.code() == 200) {
tinyDb.putBoolean("commentEdited", true); tinyDb.putBoolean("commentEdited", true);
Toasty.info(context, context.getString(R.string.editCommentUpdatedText)); Toasty.info(ctx, ctx.getString(R.string.editCommentUpdatedText));
((ReplyToIssueActivity)context).finish(); ((ReplyToIssueActivity)ctx).finish();
} }
} }
else if(response.code() == 401) { else if(response.code() == 401) {
AlertDialogs.authorizationTokenRevokedDialog(context, context.getResources().getString(R.string.alertDialogTokenRevokedTitle), AlertDialogs.authorizationTokenRevokedDialog(ctx, ctx.getResources().getString(R.string.alertDialogTokenRevokedTitle),
context.getResources().getString(R.string.alertDialogTokenRevokedMessage), ctx.getResources().getString(R.string.alertDialogTokenRevokedMessage),
context.getResources().getString(R.string.alertDialogTokenRevokedCopyNegativeButton), ctx.getResources().getString(R.string.alertDialogTokenRevokedCopyNegativeButton),
context.getResources().getString(R.string.alertDialogTokenRevokedCopyPositiveButton)); ctx.getResources().getString(R.string.alertDialogTokenRevokedCopyPositiveButton));
} }
else if(response.code() == 403) { else if(response.code() == 403) {
Toasty.info(context, context.getString(R.string.authorizeError)); Toasty.info(ctx, ctx.getString(R.string.authorizeError));
} }
else if(response.code() == 404) { else if(response.code() == 404) {
Toasty.info(context, context.getString(R.string.apiNotFound)); Toasty.info(ctx, ctx.getString(R.string.apiNotFound));
} }
else { else {
Toasty.info(context, context.getString(R.string.genericError)); Toasty.info(ctx, ctx.getString(R.string.genericError));
} }
@ -89,9 +91,9 @@ public class IssueActions {
} }
public static void closeReopenIssue(final Context context, final int issueIndex, final String issueState) { public static void closeReopenIssue(final Context ctx, final int issueIndex, final String issueState) {
final TinyDB tinyDb = new TinyDB(context); final TinyDB tinyDb = new TinyDB(ctx);
final String instanceUrl = tinyDb.getString("instanceUrl"); final String instanceUrl = tinyDb.getString("instanceUrl");
final String loginUid = tinyDb.getString("loginUid"); final String loginUid = tinyDb.getString("loginUid");
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token"); final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
@ -104,9 +106,9 @@ public class IssueActions {
Call<JsonElement> call; Call<JsonElement> call;
call = RetrofitClient call = RetrofitClient
.getInstance(instanceUrl) .getInstance(instanceUrl, ctx)
.getApiInterface() .getApiInterface()
.closeReopenIssue(Authorization.returnAuthentication(context, loginUid, instanceToken), repoOwner, repoName, issueIndex, issueStatJson); .closeReopenIssue(Authorization.returnAuthentication(ctx, loginUid, instanceToken), repoOwner, repoName, issueIndex, issueStatJson);
call.enqueue(new Callback<JsonElement>() { call.enqueue(new Callback<JsonElement>() {
@ -118,36 +120,43 @@ public class IssueActions {
tinyDb.putBoolean("resumeIssues", true); tinyDb.putBoolean("resumeIssues", true);
tinyDb.putBoolean("resumeClosedIssues", true); tinyDb.putBoolean("resumeClosedIssues", true);
if(issueState.equals("closed")) { if(issueState.equals("closed")) {
Toasty.info(context, context.getString(R.string.issueStateClosed));
Toasty.info(ctx, ctx.getString(R.string.issueStateClosed));
tinyDb.putString("issueState", "closed");
} }
else if(issueState.equals("open")) { else if(issueState.equals("open")) {
Toasty.info(context, context.getString(R.string.issueStateReopened));
Toasty.info(ctx, ctx.getString(R.string.issueStateReopened));
tinyDb.putString("issueState", "open");
} }
} }
} }
else if(response.code() == 401) { else if(response.code() == 401) {
AlertDialogs.authorizationTokenRevokedDialog(context, context.getResources().getString(R.string.alertDialogTokenRevokedTitle), AlertDialogs.authorizationTokenRevokedDialog(ctx, ctx.getResources().getString(R.string.alertDialogTokenRevokedTitle),
context.getResources().getString(R.string.alertDialogTokenRevokedMessage), ctx.getResources().getString(R.string.alertDialogTokenRevokedMessage),
context.getResources().getString(R.string.alertDialogTokenRevokedCopyNegativeButton), ctx.getResources().getString(R.string.alertDialogTokenRevokedCopyNegativeButton),
context.getResources().getString(R.string.alertDialogTokenRevokedCopyPositiveButton)); ctx.getResources().getString(R.string.alertDialogTokenRevokedCopyPositiveButton));
} }
else if(response.code() == 403) { else if(response.code() == 403) {
Toasty.info(context, context.getString(R.string.authorizeError)); Toasty.info(ctx, ctx.getString(R.string.authorizeError));
} }
else if(response.code() == 404) { else if(response.code() == 404) {
Toasty.info(context, context.getString(R.string.apiNotFound)); Toasty.info(ctx, ctx.getString(R.string.apiNotFound));
} }
else { else {
Toasty.info(context, context.getString(R.string.genericError)); Toasty.info(ctx, ctx.getString(R.string.genericError));
} }
@ -161,4 +170,127 @@ public class IssueActions {
} }
public static void subscribe(final Context ctx, final TextView subscribeIssue, final TextView unsubscribeIssue) {
final TinyDB tinyDB = new TinyDB(ctx);
final String instanceUrl = tinyDB.getString("instanceUrl");
String repoFullName = tinyDB.getString("repoFullName");
String[] parts = repoFullName.split("/");
final String repoOwner = parts[0];
final String repoName = parts[1];
final String loginUid = tinyDB.getString("loginUid");
final String userLogin = tinyDB.getString("userLogin");
final String token = "token " + tinyDB.getString(loginUid + "-token");
final int issueNr = Integer.parseInt(tinyDB.getString("issueNumber"));
Call<Void> call;
call = RetrofitClient
.getInstance(instanceUrl, ctx)
.getApiInterface()
.addIssueSubscriber(token, repoOwner, repoName, issueNr, userLogin);
call.enqueue(new Callback<Void>() {
@Override
public void onResponse(@NonNull Call<Void> call, @NonNull retrofit2.Response<Void> response) {
if(response.isSuccessful()) {
if(response.code() == 201) {
unsubscribeIssue.setVisibility(View.VISIBLE);
subscribeIssue.setVisibility(View.GONE);
Toasty.info(ctx, ctx.getString(R.string.issueSubscribtion));
tinyDB.putString("issueSubscriptionState", "unsubscribeToIssue");
}
}
else if(response.code() == 401) {
AlertDialogs.authorizationTokenRevokedDialog(ctx, ctx.getResources().getString(R.string.alertDialogTokenRevokedTitle),
ctx.getResources().getString(R.string.alertDialogTokenRevokedMessage),
ctx.getResources().getString(R.string.alertDialogTokenRevokedCopyNegativeButton),
ctx.getResources().getString(R.string.alertDialogTokenRevokedCopyPositiveButton));
}
else {
Toasty.info(ctx, ctx.getString(R.string.issueSubscribtionError));
}
}
@Override
public void onFailure(@NonNull Call<Void> call, @NonNull Throwable t) {
Toasty.info(ctx, ctx.getString(R.string.issueSubscribtionError));
}
});
}
public static void unsubscribe(final Context ctx, final TextView subscribeIssue, final TextView unsubscribeIssue) {
final TinyDB tinyDB = new TinyDB(ctx);
final String instanceUrl = tinyDB.getString("instanceUrl");
String repoFullName = tinyDB.getString("repoFullName");
String[] parts = repoFullName.split("/");
final String repoOwner = parts[0];
final String repoName = parts[1];
final String loginUid = tinyDB.getString("loginUid");
final String userLogin = tinyDB.getString("userLogin");
final String token = "token " + tinyDB.getString(loginUid + "-token");
final int issueNr = Integer.parseInt(tinyDB.getString("issueNumber"));
Call<Void> call;
call = RetrofitClient
.getInstance(instanceUrl, ctx)
.getApiInterface()
.delIssueSubscriber(token, repoOwner, repoName, issueNr, userLogin);
call.enqueue(new Callback<Void>() {
@Override
public void onResponse(@NonNull Call<Void> call, @NonNull retrofit2.Response<Void> response) {
if(response.isSuccessful()) {
if(response.code() == 201) {
unsubscribeIssue.setVisibility(View.GONE);
subscribeIssue.setVisibility(View.VISIBLE);
Toasty.info(ctx, ctx.getString(R.string.issueUnsubscribtion));
tinyDB.putString("issueSubscriptionState", "subscribeToIssue");
}
}
else if(response.code() == 401) {
AlertDialogs.authorizationTokenRevokedDialog(ctx, ctx.getResources().getString(R.string.alertDialogTokenRevokedTitle),
ctx.getResources().getString(R.string.alertDialogTokenRevokedMessage),
ctx.getResources().getString(R.string.alertDialogTokenRevokedCopyNegativeButton),
ctx.getResources().getString(R.string.alertDialogTokenRevokedCopyPositiveButton));
}
else {
Toasty.info(ctx, ctx.getString(R.string.issueUnsubscribtionError));
}
}
@Override
public void onFailure(@NonNull Call<Void> call, @NonNull Throwable t) {
Toasty.info(ctx, ctx.getString(R.string.issueUnsubscribtionError));
}
});
}
} }

View File

@ -0,0 +1,143 @@
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.models.Milestones;
import org.mian.gitnex.util.TinyDB;
import org.mian.gitnex.viewmodels.MilestonesViewModel;
import retrofit2.Call;
import retrofit2.Callback;
/**
* Author M M Arif
*/
public class MilestoneActions {
static final private String TAG = "MilestoneActions : ";
public static void closeMilestone(final Context ctx, int milestoneId_) {
final TinyDB tinyDB = new TinyDB(ctx);
final String instanceUrl = tinyDB.getString("instanceUrl");
String repoFullName = tinyDB.getString("repoFullName");
String[] parts = repoFullName.split("/");
final String repoOwner = parts[0];
final String repoName = parts[1];
final String loginUid = tinyDB.getString("loginUid");
final String token = "token " + tinyDB.getString(loginUid + "-token");
Milestones milestoneStateJson = new Milestones("closed");
Call<JsonElement> call;
call = RetrofitClient
.getInstance(instanceUrl, ctx)
.getApiInterface()
.closeReopenMilestone(token, repoOwner, repoName, milestoneId_, milestoneStateJson);
call.enqueue(new Callback<JsonElement>() {
@Override
public void onResponse(@NonNull Call<JsonElement> call, @NonNull retrofit2.Response<JsonElement> response) {
if(response.isSuccessful()) {
Toasty.info(ctx, ctx.getString(R.string.milestoneStatusUpdate));
MilestonesViewModel.loadMilestonesList(instanceUrl, Authorization.returnAuthentication(ctx, loginUid, token), repoOwner, repoName, "all", ctx);
}
else if(response.code() == 401) {
AlertDialogs.authorizationTokenRevokedDialog(ctx, ctx.getResources().getString(R.string.alertDialogTokenRevokedTitle),
ctx.getResources().getString(R.string.alertDialogTokenRevokedMessage),
ctx.getResources().getString(R.string.alertDialogTokenRevokedCopyNegativeButton),
ctx.getResources().getString(R.string.alertDialogTokenRevokedCopyPositiveButton));
}
else {
Toasty.info(ctx, ctx.getString(R.string.genericError));
}
}
@Override
public void onFailure(@NonNull Call<JsonElement> call, @NonNull Throwable t) {
Log.e(TAG, t.toString());
}
});
}
public static void openMilestone(final Context ctx, int milestoneId_) {
final TinyDB tinyDB = new TinyDB(ctx);
final String instanceUrl = tinyDB.getString("instanceUrl");
String repoFullName = tinyDB.getString("repoFullName");
String[] parts = repoFullName.split("/");
final String repoOwner = parts[0];
final String repoName = parts[1];
final String loginUid = tinyDB.getString("loginUid");
final String token = "token " + tinyDB.getString(loginUid + "-token");
Milestones milestoneStateJson = new Milestones("open");
Call<JsonElement> call;
call = RetrofitClient
.getInstance(instanceUrl, ctx)
.getApiInterface()
.closeReopenMilestone(token, repoOwner, repoName, milestoneId_, milestoneStateJson);
call.enqueue(new Callback<JsonElement>() {
@Override
public void onResponse(@NonNull Call<JsonElement> call, @NonNull retrofit2.Response<JsonElement> response) {
if(response.isSuccessful()) {
Toasty.info(ctx, ctx.getString(R.string.milestoneStatusUpdate));
MilestonesViewModel.loadMilestonesList(instanceUrl, Authorization.returnAuthentication(ctx, loginUid, token), repoOwner, repoName, "all", ctx);
}
else if(response.code() == 401) {
AlertDialogs.authorizationTokenRevokedDialog(ctx, ctx.getResources().getString(R.string.alertDialogTokenRevokedTitle),
ctx.getResources().getString(R.string.alertDialogTokenRevokedMessage),
ctx.getResources().getString(R.string.alertDialogTokenRevokedCopyNegativeButton),
ctx.getResources().getString(R.string.alertDialogTokenRevokedCopyPositiveButton));
}
else {
Toasty.info(ctx, ctx.getString(R.string.genericError));
}
}
@Override
public void onFailure(@NonNull Call<JsonElement> call, @NonNull Throwable t) {
Log.e(TAG, t.toString());
}
});
}
}

View File

@ -33,7 +33,7 @@ public class RepositoryActions {
Call<JsonElement> call; Call<JsonElement> call;
call = RetrofitClient call = RetrofitClient
.getInstance(instanceUrl) .getInstance(instanceUrl, context)
.getApiInterface() .getApiInterface()
.starRepository(Authorization.returnAuthentication(context, loginUid, instanceToken), repoOwner, repoName); .starRepository(Authorization.returnAuthentication(context, loginUid, instanceToken), repoOwner, repoName);
@ -98,7 +98,7 @@ public class RepositoryActions {
Call<JsonElement> call; Call<JsonElement> call;
call = RetrofitClient call = RetrofitClient
.getInstance(instanceUrl) .getInstance(instanceUrl, context)
.getApiInterface() .getApiInterface()
.unStarRepository(Authorization.returnAuthentication(context, loginUid, instanceToken), repoOwner, repoName); .unStarRepository(Authorization.returnAuthentication(context, loginUid, instanceToken), repoOwner, repoName);
@ -163,7 +163,7 @@ public class RepositoryActions {
Call<JsonElement> call; Call<JsonElement> call;
call = RetrofitClient call = RetrofitClient
.getInstance(instanceUrl) .getInstance(instanceUrl, context)
.getApiInterface() .getApiInterface()
.watchRepository(Authorization.returnAuthentication(context, loginUid, instanceToken), repoOwner, repoName); .watchRepository(Authorization.returnAuthentication(context, loginUid, instanceToken), repoOwner, repoName);
@ -228,7 +228,7 @@ public class RepositoryActions {
Call<JsonElement> call; Call<JsonElement> call;
call = RetrofitClient call = RetrofitClient
.getInstance(instanceUrl) .getInstance(instanceUrl, context)
.getApiInterface() .getApiInterface()
.unWatchRepository(Authorization.returnAuthentication(context, loginUid, instanceToken), repoOwner, repoName); .unWatchRepository(Authorization.returnAuthentication(context, loginUid, instanceToken), repoOwner, repoName);

View File

@ -1,7 +1,6 @@
package org.mian.gitnex.activities; package org.mian.gitnex.activities;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.DividerItemDecoration; import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
@ -14,6 +13,7 @@ import android.util.Log;
import android.view.KeyEvent; import android.view.KeyEvent;
import android.view.View; import android.view.View;
import android.view.inputmethod.EditorInfo; import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.ProgressBar; import android.widget.ProgressBar;
import android.widget.TextView; import android.widget.TextView;
@ -23,7 +23,6 @@ import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.helpers.Authorization; import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.models.UserSearch; import org.mian.gitnex.models.UserSearch;
import org.mian.gitnex.models.UserInfo; import org.mian.gitnex.models.UserInfo;
import org.mian.gitnex.util.AppUtil;
import org.mian.gitnex.util.TinyDB; import org.mian.gitnex.util.TinyDB;
import java.util.List; import java.util.List;
@ -31,7 +30,7 @@ import java.util.List;
* Author M M Arif * Author M M Arif
*/ */
public class AddCollaboratorToRepositoryActivity extends AppCompatActivity { public class AddCollaboratorToRepositoryActivity extends BaseActivity {
private View.OnClickListener onClickListener; private View.OnClickListener onClickListener;
final Context ctx = this; final Context ctx = this;
@ -42,11 +41,15 @@ public class AddCollaboratorToRepositoryActivity extends AppCompatActivity {
private RecyclerView mRecyclerView; private RecyclerView mRecyclerView;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected int getLayoutResourceId(){
super.onCreate(savedInstanceState); return R.layout.activity_add_collaborator_to_repository;
setContentView(R.layout.activity_add_collaborator_to_repository); }
boolean connToInternet = AppUtil.haveNetworkConnection(getApplicationContext()); @Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
TinyDB tinyDb = new TinyDB(getApplicationContext()); TinyDB tinyDb = new TinyDB(getApplicationContext());
final String instanceUrl = tinyDb.getString("instanceUrl"); final String instanceUrl = tinyDb.getString("instanceUrl");
@ -61,6 +64,10 @@ public class AddCollaboratorToRepositoryActivity extends AppCompatActivity {
mProgressBar = findViewById(R.id.progress_bar); mProgressBar = findViewById(R.id.progress_bar);
noData = findViewById(R.id.noData); noData = findViewById(R.id.noData);
addCollaboratorSearch.requestFocus();
assert imm != null;
imm.showSoftInput(addCollaboratorSearch, InputMethodManager.SHOW_IMPLICIT);
initCloseListener(); initCloseListener();
closeActivity.setOnClickListener(onClickListener); closeActivity.setOnClickListener(onClickListener);
@ -81,7 +88,7 @@ public class AddCollaboratorToRepositoryActivity extends AppCompatActivity {
public void loadUserSearchList(String instanceUrl, String token, String searchKeyword, final Context context, String loginUid) { public void loadUserSearchList(String instanceUrl, String token, String searchKeyword, final Context context, String loginUid) {
Call<UserSearch> call = RetrofitClient Call<UserSearch> call = RetrofitClient
.getInstance(instanceUrl) .getInstance(instanceUrl, getApplicationContext())
.getApiInterface() .getApiInterface()
.getUserBySearch(Authorization.returnAuthentication(getApplicationContext(), loginUid, token), searchKeyword, 10); .getUserBySearch(Authorization.returnAuthentication(getApplicationContext(), loginUid, token), searchKeyword, 10);
@ -101,7 +108,7 @@ public class AddCollaboratorToRepositoryActivity extends AppCompatActivity {
@Override @Override
public void onFailure(@NonNull Call<UserSearch> call, @NonNull Throwable t) { public void onFailure(@NonNull Call<UserSearch> call, @NonNull Throwable t) {
Log.i("onFailure", t.getMessage()); Log.i("onFailure", t.toString());
} }
}); });

View File

@ -1,13 +1,11 @@
package org.mian.gitnex.activities; package org.mian.gitnex.activities;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Context; import android.content.Context;
import android.graphics.Color; import android.graphics.Color;
import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.ColorDrawable;
import android.os.Bundle; import android.os.Bundle;
import android.util.Log; import android.util.Log;
import android.view.Window;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import org.mian.gitnex.R; import org.mian.gitnex.R;
import org.mian.gitnex.clients.RetrofitClient; import org.mian.gitnex.clients.RetrofitClient;
@ -18,7 +16,7 @@ import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.models.Collaborators; import org.mian.gitnex.models.Collaborators;
import org.mian.gitnex.models.Issues; import org.mian.gitnex.models.Issues;
import org.mian.gitnex.models.MultiSelectModel; import org.mian.gitnex.models.MultiSelectModel;
import org.mian.gitnex.models.UpdateIssueAssignee; import org.mian.gitnex.models.UpdateIssueAssignees;
import org.mian.gitnex.util.TinyDB; import org.mian.gitnex.util.TinyDB;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -29,7 +27,7 @@ import retrofit2.Callback;
* Author M M Arif * Author M M Arif
*/ */
public class AddRemoveAssigneesActivity extends AppCompatActivity { public class AddRemoveAssigneesActivity extends BaseActivity {
private ArrayList<MultiSelectModel> listOfCollaborators = new ArrayList<>(); private ArrayList<MultiSelectModel> listOfCollaborators = new ArrayList<>();
private ArrayList<Integer> issueAssigneesIds = new ArrayList<>(); private ArrayList<Integer> issueAssigneesIds = new ArrayList<>();
@ -38,11 +36,15 @@ public class AddRemoveAssigneesActivity extends AppCompatActivity {
final Context ctx = this; final Context ctx = this;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected int getLayoutResourceId(){
return R.layout.activity_add_remove_assignees;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
supportRequestWindowFeature(Window.FEATURE_NO_TITLE); //supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_add_remove_assignees);
getWindow().getDecorView().setBackground(new ColorDrawable(Color.TRANSPARENT)); getWindow().getDecorView().setBackground(new ColorDrawable(Color.TRANSPARENT));
@ -65,7 +67,7 @@ public class AddRemoveAssigneesActivity extends AppCompatActivity {
final TinyDB tinyDb = new TinyDB(getApplicationContext()); final TinyDB tinyDb = new TinyDB(getApplicationContext());
Call<List<Collaborators>> call = RetrofitClient Call<List<Collaborators>> call = RetrofitClient
.getInstance(instanceUrl) .getInstance(instanceUrl, getApplicationContext())
.getApiInterface() .getApiInterface()
.getCollaborators(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName); .getCollaborators(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName);
@ -90,7 +92,7 @@ public class AddRemoveAssigneesActivity extends AppCompatActivity {
// get current issue assignees // get current issue assignees
Call<Issues> callSingleIssueAssignees = RetrofitClient Call<Issues> callSingleIssueAssignees = RetrofitClient
.getInstance(instanceUrl) .getInstance(instanceUrl, getApplicationContext())
.getApiInterface() .getApiInterface()
.getIssueByIndex(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName, issueIndex); .getIssueByIndex(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName, issueIndex);
@ -234,14 +236,14 @@ public class AddRemoveAssigneesActivity extends AppCompatActivity {
private void updateIssueAssignees(final String instanceUrl, final String instanceToken, String repoOwner, String repoName, String loginUid, int issueIndex, List<String> issueAssigneesList) { private void updateIssueAssignees(final String instanceUrl, final String instanceToken, String repoOwner, String repoName, String loginUid, int issueIndex, List<String> issueAssigneesList) {
UpdateIssueAssignee updateAssigneeJson = new UpdateIssueAssignee(issueAssigneesList); UpdateIssueAssignees updateAssigneeJson = new UpdateIssueAssignees(issueAssigneesList);
Call<JsonElement> call3; Call<JsonElement> call3;
call3 = RetrofitClient call3 = RetrofitClient
.getInstance(instanceUrl) .getInstance(instanceUrl, getApplicationContext())
.getApiInterface() .getApiInterface()
.patchIssueAssignee(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName, issueIndex, updateAssigneeJson); .patchIssueAssignees(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName, issueIndex, updateAssigneeJson);
call3.enqueue(new Callback<JsonElement>() { call3.enqueue(new Callback<JsonElement>() {

View File

@ -1,7 +1,6 @@
package org.mian.gitnex.activities; package org.mian.gitnex.activities;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import retrofit2.Call; import retrofit2.Call;
import retrofit2.Callback; import retrofit2.Callback;
import android.content.Context; import android.content.Context;
@ -9,7 +8,6 @@ import android.graphics.Color;
import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.ColorDrawable;
import android.os.Bundle; import android.os.Bundle;
import android.util.Log; import android.util.Log;
import android.view.Window;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import org.mian.gitnex.R; import org.mian.gitnex.R;
import org.mian.gitnex.clients.RetrofitClient; import org.mian.gitnex.clients.RetrofitClient;
@ -27,7 +25,7 @@ import java.util.List;
* Author M M Arif * Author M M Arif
*/ */
public class AddRemoveLabelsActivity extends AppCompatActivity { public class AddRemoveLabelsActivity extends BaseActivity {
private ArrayList<MultiSelectModel> listOfLabels = new ArrayList<>(); private ArrayList<MultiSelectModel> listOfLabels = new ArrayList<>();
private ArrayList<Integer> issueLabelIds = new ArrayList<>(); private ArrayList<Integer> issueLabelIds = new ArrayList<>();
@ -36,10 +34,14 @@ public class AddRemoveLabelsActivity extends AppCompatActivity {
final Context ctx = this; final Context ctx = this;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected int getLayoutResourceId(){
return R.layout.activity_add_remove_labels;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
supportRequestWindowFeature(Window.FEATURE_NO_TITLE); //supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_add_remove_labels);
getWindow().getDecorView().setBackground(new ColorDrawable(Color.TRANSPARENT)); getWindow().getDecorView().setBackground(new ColorDrawable(Color.TRANSPARENT));
@ -62,7 +64,7 @@ public class AddRemoveLabelsActivity extends AppCompatActivity {
final TinyDB tinyDb = new TinyDB(getApplicationContext()); final TinyDB tinyDb = new TinyDB(getApplicationContext());
Call<List<Labels>> call = RetrofitClient Call<List<Labels>> call = RetrofitClient
.getInstance(instanceUrl) .getInstance(instanceUrl, getApplicationContext())
.getApiInterface() .getApiInterface()
.getlabels(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName); .getlabels(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName);
@ -87,7 +89,7 @@ public class AddRemoveLabelsActivity extends AppCompatActivity {
// get current issue labels // get current issue labels
Call<List<Labels>> callSingleIssueLabels = RetrofitClient Call<List<Labels>> callSingleIssueLabels = RetrofitClient
.getInstance(instanceUrl) .getInstance(instanceUrl, getApplicationContext())
.getApiInterface() .getApiInterface()
.getIssueLabels(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName, issueIndex); .getIssueLabels(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName, issueIndex);
@ -249,7 +251,7 @@ public class AddRemoveLabelsActivity extends AppCompatActivity {
Labels patchIssueLabels = new Labels(issueLabels); Labels patchIssueLabels = new Labels(issueLabels);
Call<JsonElement> call = RetrofitClient Call<JsonElement> call = RetrofitClient
.getInstance(instanceUrl) .getInstance(instanceUrl, getApplicationContext())
.getApiInterface() .getApiInterface()
.updateIssueLabels(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName, issueIndex, patchIssueLabels); .updateIssueLabels(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName, issueIndex, patchIssueLabels);

View File

@ -1,7 +1,6 @@
package org.mian.gitnex.activities; package org.mian.gitnex.activities;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar; import androidx.appcompat.widget.Toolbar;
import androidx.lifecycle.Observer; import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProviders; import androidx.lifecycle.ViewModelProviders;
@ -22,7 +21,7 @@ import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import org.mian.gitnex.R; import org.mian.gitnex.R;
import org.mian.gitnex.adapters.AdminGetUsersAdapter; import org.mian.gitnex.adapters.AdminGetUsersAdapter;
import org.mian.gitnex.fragments.AdminUsersBottomSheetFragment; import org.mian.gitnex.fragments.BottomSheetAdminUsersFragment;
import org.mian.gitnex.helpers.Authorization; import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.models.UserInfo; import org.mian.gitnex.models.UserInfo;
import org.mian.gitnex.util.AppUtil; import org.mian.gitnex.util.AppUtil;
@ -35,7 +34,7 @@ import java.util.Objects;
* Author M M Arif * Author M M Arif
*/ */
public class AdminGetUsersActivity extends AppCompatActivity implements AdminUsersBottomSheetFragment.BottomSheetListener { public class AdminGetUsersActivity extends BaseActivity implements BottomSheetAdminUsersFragment.BottomSheetListener {
private View.OnClickListener onClickListener; private View.OnClickListener onClickListener;
final Context ctx = this; final Context ctx = this;
@ -45,10 +44,14 @@ public class AdminGetUsersActivity extends AppCompatActivity implements AdminUse
private Boolean searchFilter = false; private Boolean searchFilter = false;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected int getLayoutResourceId(){
return R.layout.activity_admin_get_users;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_admin_get_users);
TinyDB tinyDb = new TinyDB(getApplicationContext()); TinyDB tinyDb = new TinyDB(getApplicationContext());
final String instanceUrl = tinyDb.getString("instanceUrl"); final String instanceUrl = tinyDb.getString("instanceUrl");
@ -168,7 +171,7 @@ public class AdminGetUsersActivity extends AppCompatActivity implements AdminUse
finish(); finish();
return true; return true;
case R.id.genericMenu: case R.id.genericMenu:
AdminUsersBottomSheetFragment bottomSheet = new AdminUsersBottomSheetFragment(); BottomSheetAdminUsersFragment bottomSheet = new BottomSheetAdminUsersFragment();
bottomSheet.show(getSupportFragmentManager(), "usersBottomSheet"); bottomSheet.show(getSupportFragmentManager(), "usersBottomSheet");
return true; return true;
default: default:

View File

@ -0,0 +1,109 @@
package org.mian.gitnex.activities;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import org.acra.ACRA;
import org.acra.BuildConfig;
import org.acra.annotation.AcraNotification;
import org.acra.config.CoreConfigurationBuilder;
import org.acra.config.LimiterConfigurationBuilder;
import org.acra.config.MailSenderConfigurationBuilder;
import org.acra.data.StringFormat;
import org.mian.gitnex.R;
import org.mian.gitnex.helpers.FontsOverride;
import org.mian.gitnex.helpers.TimeHelper;
import org.mian.gitnex.util.AppUtil;
import org.mian.gitnex.util.TinyDB;
/**
* Author M M Arif
*/
@AcraNotification(resIcon = R.mipmap.app_logo,
resTitle = R.string.crashTitle,
resChannelName = R.string.setCrashReports,
resText = R.string.crashMessage)
public abstract class BaseActivity extends AppCompatActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
final TinyDB tinyDb = new TinyDB(getApplicationContext());
if(tinyDb.getInt("themeId") == 1) {
setTheme(R.style.AppThemeLight);
}
else if(tinyDb.getInt("themeId") == 2) {
boolean timeSetterFlag = TimeHelper.timeBetweenHours(18, 6); // 6pm to 6am
if(timeSetterFlag) {
setTheme(R.style.AppTheme);
}
else {
setTheme(R.style.AppThemeLight);
}
}
else {
setTheme(R.style.AppTheme);
}
super.onCreate(savedInstanceState);
setContentView(getLayoutResourceId());
switch(tinyDb.getInt("customFontId", -1)) {
case 0:
FontsOverride.setDefaultFont(this, "DEFAULT", "fonts/roboto.ttf");
FontsOverride.setDefaultFont(this, "MONOSPACE", "fonts/roboto.ttf");
FontsOverride.setDefaultFont(this, "SERIF", "fonts/roboto.ttf");
FontsOverride.setDefaultFont(this, "SANS_SERIF", "fonts/roboto.ttf");
break;
case 2:
FontsOverride.setDefaultFont(this, "DEFAULT", "fonts/sourcecodeproregular.ttf");
FontsOverride.setDefaultFont(this, "MONOSPACE", "fonts/sourcecodeproregular.ttf");
FontsOverride.setDefaultFont(this, "SERIF", "fonts/sourcecodeproregular.ttf");
FontsOverride.setDefaultFont(this, "SANS_SERIF", "fonts/sourcecodeproregular.ttf");
break;
default:
FontsOverride.setDefaultFont(this, "DEFAULT", "fonts/manroperegular.ttf");
FontsOverride.setDefaultFont(this, "MONOSPACE", "fonts/manroperegular.ttf");
FontsOverride.setDefaultFont(this, "SERIF", "fonts/manroperegular.ttf");
FontsOverride.setDefaultFont(this, "SANS_SERIF", "fonts/manroperegular.ttf");
break;
}
// enabling counter badges by default
if(tinyDb.getString("enableCounterBadgesInit").isEmpty()) {
tinyDb.putBoolean("enableCounterBadges", true);
tinyDb.putString("enableCounterBadgesInit", "yes");
}
// enable crash reports by default
if(tinyDb.getString("crashReportingEnabledInit").isEmpty()) {
tinyDb.putBoolean("crashReportingEnabled", true);
tinyDb.putString("crashReportingEnabledInit", "yes");
}
if (tinyDb.getBoolean("crashReportingEnabled")) {
CoreConfigurationBuilder ACRABuilder = new CoreConfigurationBuilder(this);
ACRABuilder.setBuildConfigClass(BuildConfig.class).setReportFormat(StringFormat.KEY_VALUE_LIST);
ACRABuilder.getPluginConfigurationBuilder(MailSenderConfigurationBuilder.class).setReportAsFile(true).setMailTo(getResources().getString(R.string.appEmail)).setSubject(getResources().getString(R.string.crashReportEmailSubject, AppUtil.getAppBuildNo(getApplicationContext()))).setEnabled(true);
ACRABuilder.getPluginConfigurationBuilder(LimiterConfigurationBuilder.class).setEnabled(true);
ACRA.init(getApplication(), ACRABuilder);
}
}
protected abstract int getLayoutResourceId();
}

View File

@ -0,0 +1,325 @@
package org.mian.gitnex.activities;
import android.os.Bundle;
import android.os.Handler;
import android.text.method.ScrollingMovementMethod;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.Toolbar;
import androidx.recyclerview.widget.DefaultItemAnimator;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import com.mikepenz.fastadapter.IItemAdapter;
import com.mikepenz.fastadapter.adapters.ItemAdapter;
import com.mikepenz.fastadapter.commons.adapters.FastItemAdapter;
import com.mikepenz.fastadapter.listeners.ItemFilterListener;
import com.mikepenz.fastadapter_extensions.items.ProgressItem;
import com.mikepenz.fastadapter_extensions.scroll.EndlessRecyclerOnScrollListener;
import org.mian.gitnex.R;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.adapters.CommitsAdapter;
import org.mian.gitnex.models.Commits;
import org.mian.gitnex.util.TinyDB;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import static com.mikepenz.fastadapter.adapters.ItemAdapter.items;
/**
* Author M M Arif
*/
public class CommitsActivity extends BaseActivity implements ItemFilterListener<CommitsAdapter> {
private View.OnClickListener onClickListener;
private TextView noData;
private ProgressBar progressBar;
private SwipeRefreshLayout swipeRefreshLayout;
private String TAG = "CommitsActivity - ";
private int resultLimit = 50;
private boolean loadNextFlag = false;
private List<CommitsAdapter> items = new ArrayList<>();
private FastItemAdapter<CommitsAdapter> fastItemAdapter;
private ItemAdapter footerAdapter;
private EndlessRecyclerOnScrollListener endlessRecyclerOnScrollListener;
@Override
protected int getLayoutResourceId(){
return R.layout.activity_commits;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
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 branchName = getIntent().getStringExtra("branchName");
TextView toolbar_title = findViewById(R.id.toolbar_title);
toolbar_title.setMovementMethod(new ScrollingMovementMethod());
toolbar_title.setText(branchName);
ImageView closeActivity = findViewById(R.id.close);
noData = findViewById(R.id.noDataCommits);
progressBar = findViewById(R.id.progress_bar);
swipeRefreshLayout = findViewById(R.id.pullToRefresh);
RecyclerView recyclerView = findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(getApplicationContext()));
recyclerView.setHasFixedSize(true);
initCloseListener();
closeActivity.setOnClickListener(onClickListener);
fastItemAdapter = new FastItemAdapter<>();
fastItemAdapter.withSelectable(true);
footerAdapter = items();
//noinspection unchecked
fastItemAdapter.addAdapter(1, footerAdapter);
fastItemAdapter.getItemFilter().withFilterPredicate((IItemAdapter.Predicate<CommitsAdapter>) (item, constraint) -> item.getCommitTitle().toLowerCase().contains(Objects.requireNonNull(constraint).toString().toLowerCase()));
fastItemAdapter.getItemFilter().withItemFilterListener(this);
recyclerView.setLayoutManager(new LinearLayoutManager(getApplicationContext()));
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.setAdapter(fastItemAdapter);
endlessRecyclerOnScrollListener = new EndlessRecyclerOnScrollListener(footerAdapter) {
@Override
public void onLoadMore(final int currentPage) {
loadNext(instanceUrl, instanceToken, repoOwner, repoName, currentPage, branchName);
}
};
swipeRefreshLayout.setOnRefreshListener(() -> {
progressBar.setVisibility(View.VISIBLE);
fastItemAdapter.clear();
endlessRecyclerOnScrollListener.resetPageCount();
swipeRefreshLayout.setRefreshing(false);
});
recyclerView.addOnScrollListener(endlessRecyclerOnScrollListener);
loadInitial(instanceUrl, instanceToken, repoOwner, repoName, branchName);
assert savedInstanceState != null;
fastItemAdapter.withSavedInstanceState(savedInstanceState);
}
private void loadInitial(String instanceUrl, String token, String repoOwner, String repoName, String branchName) {
Call<List<Commits>> call = RetrofitClient
.getInstance(instanceUrl, getApplicationContext())
.getApiInterface()
.getRepositoryCommits(token, repoOwner, repoName, 1, branchName);
call.enqueue(new Callback<List<Commits>>() {
@Override
public void onResponse(@NonNull Call<List<Commits>> call, @NonNull Response<List<Commits>> response) {
if (response.isSuccessful()) {
assert response.body() != null;
if(response.body().size() > 0) {
if(response.body().size() == resultLimit) {
loadNextFlag = true;
}
for (int i = 0; i < response.body().size(); i++) {
items.add(new CommitsAdapter(getApplicationContext()).withNewItems(response.body().get(i).getCommit().getMessage(), response.body().get(i).getHtml_url(),
response.body().get(i).getCommit().getCommitter().getName(), response.body().get(i).getCommit().getCommitter().getDate()));
}
fastItemAdapter.add(items);
}
else {
noData.setVisibility(View.VISIBLE);
}
progressBar.setVisibility(View.GONE);
}
else {
Log.e(TAG, String.valueOf(response.code()));
}
}
@Override
public void onFailure(@NonNull Call<List<Commits>> call, @NonNull Throwable t) {
Log.e(TAG, t.toString());
}
});
}
private void loadNext(String instanceUrl, String token, String repoOwner, String repoName, final int currentPage, String branchName) {
footerAdapter.clear();
//noinspection unchecked
footerAdapter.add(new ProgressItem().withEnabled(false));
Handler handler = new Handler();
handler.postDelayed(() -> {
Call<List<Commits>> call = RetrofitClient
.getInstance(instanceUrl, getApplicationContext())
.getApiInterface()
.getRepositoryCommits(token, repoOwner, repoName, currentPage + 1, branchName);
call.enqueue(new Callback<List<Commits>>() {
@Override
public void onResponse(@NonNull Call<List<Commits>> call, @NonNull Response<List<Commits>> response) {
if (response.isSuccessful()) {
assert response.body() != null;
if (response.body().size() > 0) {
loadNextFlag = response.body().size() == resultLimit;
for (int i = 0; i < response.body().size(); i++) {
fastItemAdapter.add(fastItemAdapter.getAdapterItemCount(), new CommitsAdapter(getApplicationContext()).withNewItems(response.body().get(i).getCommit().getMessage(),
response.body().get(i).getHtml_url(), response.body().get(i).getCommit().getCommitter().getName(),
response.body().get(i).getCommit().getCommitter().getDate()));
}
footerAdapter.clear();
}
else {
footerAdapter.clear();
}
progressBar.setVisibility(View.GONE);
}
else {
Log.e(TAG, String.valueOf(response.code()));
}
}
@Override
public void onFailure(@NonNull Call<List<Commits>> call, @NonNull Throwable t) {
Log.e(TAG, t.toString());
}
});
}, 1000);
if(!loadNextFlag) {
footerAdapter.clear();
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.search_menu, menu);
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.setOnQueryTextListener(new androidx.appcompat.widget.SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
return false;
}
@Override
public boolean onQueryTextChange(String newText) {
fastItemAdapter.filter(newText);
return true;
}
});
endlessRecyclerOnScrollListener.enable();
return super.onCreateOptionsMenu(menu);
}
@Override
public void itemsFiltered(@Nullable CharSequence constraint, @Nullable List<CommitsAdapter> results) {
endlessRecyclerOnScrollListener.disable();
}
@Override
public void onReset() {
endlessRecyclerOnScrollListener.enable();
}
private void initCloseListener() {
onClickListener = view -> {
getIntent().removeExtra("branchName");
finish();
};
}
}

View File

@ -6,6 +6,7 @@ import android.graphics.drawable.GradientDrawable;
import android.os.Bundle; import android.os.Bundle;
import android.util.Log; import android.util.Log;
import android.view.View; import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView; import android.widget.AdapterView;
import android.widget.ArrayAdapter; import android.widget.ArrayAdapter;
import android.widget.Button; import android.widget.Button;
@ -13,7 +14,6 @@ import android.widget.EditText;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.Spinner; import android.widget.Spinner;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import org.mian.gitnex.R; import org.mian.gitnex.R;
import org.mian.gitnex.clients.RetrofitClient; import org.mian.gitnex.clients.RetrofitClient;
@ -33,7 +33,7 @@ import retrofit2.Callback;
* Author M M Arif * Author M M Arif
*/ */
public class NewFileActivity extends AppCompatActivity { public class CreateFileActivity extends BaseActivity {
public ImageView closeActivity; public ImageView closeActivity;
private View.OnClickListener onClickListener; private View.OnClickListener onClickListener;
@ -49,13 +49,19 @@ public class NewFileActivity extends AppCompatActivity {
List<Branches> branchesList = new ArrayList<>(); List<Branches> branchesList = new ArrayList<>();
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected int getLayoutResourceId(){
return R.layout.activity_new_file;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_new_file);
boolean connToInternet = AppUtil.haveNetworkConnection(getApplicationContext()); boolean connToInternet = AppUtil.haveNetworkConnection(getApplicationContext());
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
TinyDB tinyDb = new TinyDB(getApplicationContext()); TinyDB tinyDb = new TinyDB(getApplicationContext());
final String instanceUrl = tinyDb.getString("instanceUrl"); final String instanceUrl = tinyDb.getString("instanceUrl");
final String loginUid = tinyDb.getString("loginUid"); final String loginUid = tinyDb.getString("loginUid");
@ -71,6 +77,10 @@ public class NewFileActivity extends AppCompatActivity {
newFileBranchName = findViewById(R.id.newFileBranchName); newFileBranchName = findViewById(R.id.newFileBranchName);
newFileCommitMessage = findViewById(R.id.newFileCommitMessage); newFileCommitMessage = findViewById(R.id.newFileCommitMessage);
newFileName.requestFocus();
assert imm != null;
imm.showSoftInput(newFileName, InputMethodManager.SHOW_IMPLICIT);
initCloseListener(); initCloseListener();
closeActivity.setOnClickListener(onClickListener); closeActivity.setOnClickListener(onClickListener);
@ -204,7 +214,7 @@ public class NewFileActivity extends AppCompatActivity {
} }
Call<JsonElement> call = RetrofitClient Call<JsonElement> call = RetrofitClient
.getInstance(instanceUrl) .getInstance(instanceUrl, getApplicationContext())
.getApiInterface() .getApiInterface()
.createNewFile(token, repoOwner, repoName, fileName, createNewFileJsonStr); .createNewFile(token, repoOwner, repoName, fileName, createNewFileJsonStr);
@ -256,7 +266,7 @@ public class NewFileActivity extends AppCompatActivity {
private void getBranches(String instanceUrl, String instanceToken, String repoOwner, String repoName, String loginUid) { private void getBranches(String instanceUrl, String instanceToken, String repoOwner, String repoName, String loginUid) {
Call<List<Branches>> call = RetrofitClient Call<List<Branches>> call = RetrofitClient
.getInstance(instanceUrl) .getInstance(instanceUrl, getApplicationContext())
.getApiInterface() .getApiInterface()
.getBranches(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName); .getBranches(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName);

View File

@ -1,7 +1,6 @@
package org.mian.gitnex.activities; package org.mian.gitnex.activities;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import retrofit2.Call; import retrofit2.Call;
import retrofit2.Callback; import retrofit2.Callback;
import retrofit2.Response; import retrofit2.Response;
@ -12,6 +11,7 @@ import android.graphics.drawable.GradientDrawable;
import android.os.Bundle; import android.os.Bundle;
import android.util.Log; import android.util.Log;
import android.view.View; import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.ArrayAdapter; import android.widget.ArrayAdapter;
import android.widget.Button; import android.widget.Button;
import android.widget.DatePicker; import android.widget.DatePicker;
@ -45,7 +45,7 @@ import java.util.List;
* Author M M Arif * Author M M Arif
*/ */
public class CreateIssueActivity extends AppCompatActivity implements View.OnClickListener { public class CreateIssueActivity extends BaseActivity implements View.OnClickListener {
private View.OnClickListener onClickListener; private View.OnClickListener onClickListener;
MultiSelectDialog multiSelectDialog; MultiSelectDialog multiSelectDialog;
@ -68,15 +68,22 @@ public class CreateIssueActivity extends AppCompatActivity implements View.OnCli
private ArrayAdapter<Mention> defaultMentionAdapter; private ArrayAdapter<Mention> defaultMentionAdapter;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected int getLayoutResourceId(){
return R.layout.activity_create_issue;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_create_issue);
boolean connToInternet = AppUtil.haveNetworkConnection(getApplicationContext()); boolean connToInternet = AppUtil.haveNetworkConnection(getApplicationContext());
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
TinyDB tinyDb = new TinyDB(getApplicationContext()); TinyDB tinyDb = new TinyDB(getApplicationContext());
final String instanceUrl = tinyDb.getString("instanceUrl"); final String instanceUrl = tinyDb.getString("instanceUrl");
final String loginUid = tinyDb.getString("loginUid"); final String loginUid = tinyDb.getString("loginUid");
final String loginFullName = tinyDb.getString("userFullname");
String repoFullName = tinyDb.getString("repoFullName"); String repoFullName = tinyDb.getString("repoFullName");
String[] parts = repoFullName.split("/"); String[] parts = repoFullName.split("/");
final String repoOwner = parts[0]; final String repoOwner = parts[0];
@ -92,6 +99,10 @@ public class CreateIssueActivity extends AppCompatActivity implements View.OnCli
newIssueDescription = findViewById(R.id.newIssueDescription); newIssueDescription = findViewById(R.id.newIssueDescription);
labelsIdHolder = findViewById(R.id.labelsIdHolder); labelsIdHolder = findViewById(R.id.labelsIdHolder);
newIssueTitle.requestFocus();
assert imm != null;
imm.showSoftInput(newIssueTitle, InputMethodManager.SHOW_IMPLICIT);
defaultMentionAdapter = new MentionArrayAdapter<>(this); defaultMentionAdapter = new MentionArrayAdapter<>(this);
loadCollaboratorsList(); loadCollaboratorsList();
@ -109,7 +120,7 @@ public class CreateIssueActivity extends AppCompatActivity implements View.OnCli
getMilestones(instanceUrl, instanceToken, repoOwner, repoName, loginUid); getMilestones(instanceUrl, instanceToken, repoOwner, repoName, loginUid);
getLabels(instanceUrl, instanceToken, repoOwner, repoName, loginUid); getLabels(instanceUrl, instanceToken, repoOwner, repoName, loginUid);
getCollaborators(instanceUrl, instanceToken, repoOwner, repoName, loginUid); getCollaborators(instanceUrl, instanceToken, repoOwner, repoName, loginUid, loginFullName);
disableProcessButton(); disableProcessButton();
@ -217,7 +228,7 @@ public class CreateIssueActivity extends AppCompatActivity implements View.OnCli
final String repoName = parts[1]; final String repoName = parts[1];
Call<List<Collaborators>> call = RetrofitClient Call<List<Collaborators>> call = RetrofitClient
.getInstance(instanceUrl) .getInstance(instanceUrl, getApplicationContext())
.getApiInterface() .getApiInterface()
.getCollaborators(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName); .getCollaborators(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName);
@ -248,7 +259,7 @@ public class CreateIssueActivity extends AppCompatActivity implements View.OnCli
@Override @Override
public void onFailure(@NonNull Call<List<Collaborators>> call, @NonNull Throwable t) { public void onFailure(@NonNull Call<List<Collaborators>> call, @NonNull Throwable t) {
Log.i("onFailure", t.getMessage()); Log.i("onFailure", t.toString());
} }
}); });
@ -261,7 +272,7 @@ public class CreateIssueActivity extends AppCompatActivity implements View.OnCli
Call<JsonElement> call3; Call<JsonElement> call3;
call3 = RetrofitClient call3 = RetrofitClient
.getInstance(instanceUrl) .getInstance(instanceUrl, getApplicationContext())
.getApiInterface() .getApiInterface()
.createNewIssue(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName, createNewIssueJson); .createNewIssue(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName, createNewIssueJson);
@ -325,7 +336,7 @@ public class CreateIssueActivity extends AppCompatActivity implements View.OnCli
String msState = "open"; String msState = "open";
Call<List<Milestones>> call = RetrofitClient Call<List<Milestones>> call = RetrofitClient
.getInstance(instanceUrl) .getInstance(instanceUrl, getApplicationContext())
.getApiInterface() .getApiInterface()
.getMilestones(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName, msState); .getMilestones(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName, msState);
@ -339,13 +350,13 @@ public class CreateIssueActivity extends AppCompatActivity implements View.OnCli
List<Milestones> milestonesList_ = response.body(); List<Milestones> milestonesList_ = response.body();
milestonesList.add(new Milestones(0,"No milestone")); milestonesList.add(new Milestones(0,getString(R.string.issueCreatedNoMilestone)));
assert milestonesList_ != null; assert milestonesList_ != null;
if(milestonesList_.size() > 0) { if(milestonesList_.size() > 0) {
for (int i = 0; i < milestonesList_.size(); i++) { for (int i = 0; i < milestonesList_.size(); i++) {
//String mStone = getString(R.string.spinnerMilestoneText, milestonesList_.get(i).getTitle(), milestonesList_.get(i).getState()); //Don't translate "open" is a enum
if(milestonesList_.get(i).getState().equals(getString(R.string.issueStatusOpen))) { if(milestonesList_.get(i).getState().equals("open")) {
Milestones data = new Milestones( Milestones data = new Milestones(
milestonesList_.get(i).getId(), milestonesList_.get(i).getId(),
milestonesList_.get(i).getTitle() milestonesList_.get(i).getTitle()
@ -376,13 +387,15 @@ public class CreateIssueActivity extends AppCompatActivity implements View.OnCli
} }
private void getCollaborators(String instanceUrl, String instanceToken, String repoOwner, String repoName, String loginUid) { private void getCollaborators(String instanceUrl, String instanceToken, String repoOwner, String repoName, String loginUid, String loginFullName) {
Call<List<Collaborators>> call = RetrofitClient Call<List<Collaborators>> call = RetrofitClient
.getInstance(instanceUrl) .getInstance(instanceUrl, getApplicationContext())
.getApiInterface() .getApiInterface()
.getCollaborators(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName); .getCollaborators(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName);
listOfAssignees.add(new MultiSelectModel(-1, loginFullName));
call.enqueue(new Callback<List<Collaborators>>() { call.enqueue(new Callback<List<Collaborators>>() {
@Override @Override
@ -449,7 +462,7 @@ public class CreateIssueActivity extends AppCompatActivity implements View.OnCli
private void getLabels(String instanceUrl, String instanceToken, String repoOwner, String repoName, String loginUid) { private void getLabels(String instanceUrl, String instanceToken, String repoOwner, String repoName, String loginUid) {
Call<List<Labels>> call = RetrofitClient Call<List<Labels>> call = RetrofitClient
.getInstance(instanceUrl) .getInstance(instanceUrl, getApplicationContext())
.getApiInterface() .getApiInterface()
.getlabels(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName); .getlabels(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName);

View File

@ -2,7 +2,6 @@ package org.mian.gitnex.activities;
import androidx.annotation.ColorInt; import androidx.annotation.ColorInt;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
import retrofit2.Call; import retrofit2.Call;
import retrofit2.Callback; import retrofit2.Callback;
@ -12,6 +11,7 @@ import android.graphics.drawable.GradientDrawable;
import android.os.Bundle; import android.os.Bundle;
import android.util.Log; import android.util.Log;
import android.view.View; import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button; import android.widget.Button;
import android.widget.EditText; import android.widget.EditText;
import android.widget.ImageView; import android.widget.ImageView;
@ -28,12 +28,13 @@ import org.mian.gitnex.models.Labels;
import org.mian.gitnex.util.AppUtil; import org.mian.gitnex.util.AppUtil;
import org.mian.gitnex.util.TinyDB; import org.mian.gitnex.util.TinyDB;
import org.mian.gitnex.viewmodels.LabelsViewModel; import org.mian.gitnex.viewmodels.LabelsViewModel;
import java.util.Objects;
/** /**
* Author M M Arif * Author M M Arif
*/ */
public class CreateLabelActivity extends AppCompatActivity { public class CreateLabelActivity extends BaseActivity {
private View.OnClickListener onClickListener; private View.OnClickListener onClickListener;
private TextView colorPicker; private TextView colorPicker;
@ -42,9 +43,15 @@ public class CreateLabelActivity extends AppCompatActivity {
final Context ctx = this; final Context ctx = this;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected int getLayoutResourceId(){
return R.layout.activity_create_label;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_create_label);
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
final TinyDB tinyDb = new TinyDB(getApplicationContext()); final TinyDB tinyDb = new TinyDB(getApplicationContext());
String repoFullName = tinyDb.getString("repoFullName"); String repoFullName = tinyDb.getString("repoFullName");
@ -55,9 +62,9 @@ public class CreateLabelActivity extends AppCompatActivity {
final String loginUid = tinyDb.getString("loginUid"); final String loginUid = tinyDb.getString("loginUid");
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token"); final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
if(getIntent().getStringExtra("labelAction") != null && getIntent().getStringExtra("labelAction").equals("delete")) { if(getIntent().getStringExtra("labelAction") != null && Objects.requireNonNull(getIntent().getStringExtra("labelAction")).equals("delete")) {
deleteLabel(instanceUrl, instanceToken, repoOwner, repoName, Integer.valueOf(getIntent().getStringExtra("labelId")), loginUid); deleteLabel(instanceUrl, instanceToken, repoOwner, repoName, Integer.parseInt(Objects.requireNonNull(getIntent().getStringExtra("labelId"))), loginUid);
finish(); finish();
return; return;
@ -70,6 +77,10 @@ public class CreateLabelActivity extends AppCompatActivity {
labelName = findViewById(R.id.labelName); labelName = findViewById(R.id.labelName);
createLabelButton = findViewById(R.id.createLabelButton); createLabelButton = findViewById(R.id.createLabelButton);
labelName.requestFocus();
assert imm != null;
imm.showSoftInput(labelName, InputMethodManager.SHOW_IMPLICIT);
final ColorPicker cp = new ColorPicker(CreateLabelActivity.this, 235, 113, 33); final ColorPicker cp = new ColorPicker(CreateLabelActivity.this, 235, 113, 33);
initCloseListener(); initCloseListener();
@ -92,7 +103,7 @@ public class CreateLabelActivity extends AppCompatActivity {
} }
}); });
if(getIntent().getStringExtra("labelAction") != null && getIntent().getStringExtra("labelAction").equals("edit")) { if(getIntent().getStringExtra("labelAction") != null && Objects.requireNonNull(getIntent().getStringExtra("labelAction")).equals("edit")) {
labelName.setText(getIntent().getStringExtra("labelTitle")); labelName.setText(getIntent().getStringExtra("labelTitle"));
int labelColor_ = Color.parseColor("#" + getIntent().getStringExtra("labelColor")); int labelColor_ = Color.parseColor("#" + getIntent().getStringExtra("labelColor"));
@ -242,7 +253,7 @@ public class CreateLabelActivity extends AppCompatActivity {
Call<CreateLabel> call; Call<CreateLabel> call;
call = RetrofitClient call = RetrofitClient
.getInstance(instanceUrl) .getInstance(instanceUrl, getApplicationContext())
.getApiInterface() .getApiInterface()
.createLabel(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName, createLabelFunc); .createLabel(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName, createLabelFunc);
@ -296,7 +307,7 @@ public class CreateLabelActivity extends AppCompatActivity {
Call<CreateLabel> call; Call<CreateLabel> call;
call = RetrofitClient call = RetrofitClient
.getInstance(instanceUrl) .getInstance(instanceUrl, getApplicationContext())
.getApiInterface() .getApiInterface()
.patchLabel(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName, labelId, createLabelFunc); .patchLabel(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName, labelId, createLabelFunc);
@ -369,7 +380,7 @@ public class CreateLabelActivity extends AppCompatActivity {
Call<Labels> call; Call<Labels> call;
call = RetrofitClient call = RetrofitClient
.getInstance(instanceUrl) .getInstance(instanceUrl, getApplicationContext())
.getApiInterface() .getApiInterface()
.deleteLabel(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName, labelId); .deleteLabel(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName, labelId);
@ -382,7 +393,7 @@ public class CreateLabelActivity extends AppCompatActivity {
if(response.code() == 204) { if(response.code() == 204) {
Toasty.info(getApplicationContext(), getString(R.string.labelDeleteText)); Toasty.info(getApplicationContext(), getString(R.string.labelDeleteText));
LabelsViewModel.loadLabelsList(instanceUrl, instanceToken, repoOwner, repoName); LabelsViewModel.loadLabelsList(instanceUrl, instanceToken, repoOwner, repoName, getApplicationContext());
getIntent().removeExtra("labelAction"); getIntent().removeExtra("labelAction");
getIntent().removeExtra("labelId"); getIntent().removeExtra("labelId");

View File

@ -1,7 +1,6 @@
package org.mian.gitnex.activities; package org.mian.gitnex.activities;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import retrofit2.Call; import retrofit2.Call;
import retrofit2.Callback; import retrofit2.Callback;
import android.app.DatePickerDialog; import android.app.DatePickerDialog;
@ -10,6 +9,7 @@ import android.graphics.drawable.GradientDrawable;
import android.os.Bundle; import android.os.Bundle;
import android.util.Log; import android.util.Log;
import android.view.View; import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button; import android.widget.Button;
import android.widget.DatePicker; import android.widget.DatePicker;
import android.widget.EditText; import android.widget.EditText;
@ -18,6 +18,7 @@ import org.mian.gitnex.R;
import org.mian.gitnex.clients.RetrofitClient; import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.helpers.AlertDialogs; import org.mian.gitnex.helpers.AlertDialogs;
import org.mian.gitnex.helpers.Authorization; import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.helpers.VersionCheck;
import org.mian.gitnex.helpers.Toasty; import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.models.Milestones; import org.mian.gitnex.models.Milestones;
import org.mian.gitnex.util.AppUtil; import org.mian.gitnex.util.AppUtil;
@ -28,7 +29,7 @@ import java.util.Calendar;
* Author M M Arif * Author M M Arif
*/ */
public class NewMilestoneActivity extends AppCompatActivity implements View.OnClickListener { public class CreateMilestoneActivity extends BaseActivity implements View.OnClickListener {
private EditText milestoneDueDate; private EditText milestoneDueDate;
private View.OnClickListener onClickListener; private View.OnClickListener onClickListener;
@ -38,18 +39,28 @@ public class NewMilestoneActivity extends AppCompatActivity implements View.OnCl
final Context ctx = this; final Context ctx = this;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected int getLayoutResourceId(){
return R.layout.activity_new_milestone;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_new_milestone);
boolean connToInternet = AppUtil.haveNetworkConnection(getApplicationContext()); boolean connToInternet = AppUtil.haveNetworkConnection(getApplicationContext());
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
milestoneDueDate = findViewById(R.id.milestoneDueDate); milestoneDueDate = findViewById(R.id.milestoneDueDate);
ImageView closeActivity = findViewById(R.id.close); ImageView closeActivity = findViewById(R.id.close);
createNewMilestoneButton = findViewById(R.id.createNewMilestoneButton); createNewMilestoneButton = findViewById(R.id.createNewMilestoneButton);
milestoneTitle = findViewById(R.id.milestoneTitle); milestoneTitle = findViewById(R.id.milestoneTitle);
milestoneDescription = findViewById(R.id.milestoneDescription); milestoneDescription = findViewById(R.id.milestoneDescription);
milestoneTitle.requestFocus();
assert imm != null;
imm.showSoftInput(milestoneTitle, InputMethodManager.SHOW_IMPLICIT);
initCloseListener(); initCloseListener();
closeActivity.setOnClickListener(onClickListener); closeActivity.setOnClickListener(onClickListener);
milestoneDueDate.setOnClickListener(this); milestoneDueDate.setOnClickListener(this);
@ -117,15 +128,16 @@ public class NewMilestoneActivity extends AppCompatActivity implements View.OnCl
} }
} }
if(newMilestoneDueDate.equals("")) { String finalMilestoneDueDate = null;
if(!newMilestoneDueDate.isEmpty()) {
finalMilestoneDueDate = (AppUtil.customDateCombine(AppUtil.customDateFormat(newMilestoneDueDate)));
} else if (VersionCheck.compareVersion("1.10.0", tinyDb.getString("giteaVersion")) > 1) {
// if Gitea version is less than 1.10.0 DueDate is required
Toasty.info(getApplicationContext(), getString(R.string.milestoneDateEmpty)); Toasty.info(getApplicationContext(), getString(R.string.milestoneDateEmpty));
return; return;
} }
disableProcessButton(); disableProcessButton();
String finalMilestoneDueDate = (AppUtil.customDateCombine(AppUtil.customDateFormat(newMilestoneDueDate)));
createNewMilestone(instanceUrl, Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName, newMilestoneTitle, newMilestoneDescription, finalMilestoneDueDate); createNewMilestone(instanceUrl, Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName, newMilestoneTitle, newMilestoneDescription, finalMilestoneDueDate);
} }
@ -137,7 +149,7 @@ public class NewMilestoneActivity extends AppCompatActivity implements View.OnCl
Call<Milestones> call; Call<Milestones> call;
call = RetrofitClient call = RetrofitClient
.getInstance(instanceUrl) .getInstance(instanceUrl, getApplicationContext())
.getApiInterface() .getApiInterface()
.createMilestone(token, repoOwner, repoName, createMilestone); .createMilestone(token, repoOwner, repoName, createMilestone);

View File

@ -1,7 +1,6 @@
package org.mian.gitnex.activities; package org.mian.gitnex.activities;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import retrofit2.Call; import retrofit2.Call;
import retrofit2.Callback; import retrofit2.Callback;
import android.content.Context; import android.content.Context;
@ -10,6 +9,7 @@ import android.os.Bundle;
import android.util.Log; import android.util.Log;
import android.util.Patterns; import android.util.Patterns;
import android.view.View; import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button; import android.widget.Button;
import android.widget.EditText; import android.widget.EditText;
import android.widget.ImageView; import android.widget.ImageView;
@ -26,7 +26,7 @@ import org.mian.gitnex.util.TinyDB;
* Author M M Arif * Author M M Arif
*/ */
public class CreateNewUserActivity extends AppCompatActivity { public class CreateNewUserActivity extends BaseActivity {
private View.OnClickListener onClickListener; private View.OnClickListener onClickListener;
private EditText fullName; private EditText fullName;
@ -37,13 +37,19 @@ public class CreateNewUserActivity extends AppCompatActivity {
final Context ctx = this; final Context ctx = this;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected int getLayoutResourceId(){
return R.layout.activity_create_new_user;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_create_new_user);
boolean connToInternet = AppUtil.haveNetworkConnection(getApplicationContext()); boolean connToInternet = AppUtil.haveNetworkConnection(getApplicationContext());
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
ImageView closeActivity = findViewById(R.id.close); ImageView closeActivity = findViewById(R.id.close);
createUserButton = findViewById(R.id.createUserButton); createUserButton = findViewById(R.id.createUserButton);
fullName = findViewById(R.id.fullName); fullName = findViewById(R.id.fullName);
@ -51,6 +57,10 @@ public class CreateNewUserActivity extends AppCompatActivity {
userEmail = findViewById(R.id.userEmail); userEmail = findViewById(R.id.userEmail);
userPassword = findViewById(R.id.userPassword); userPassword = findViewById(R.id.userPassword);
fullName.requestFocus();
assert imm != null;
imm.showSoftInput(fullName, InputMethodManager.SHOW_IMPLICIT);
initCloseListener(); initCloseListener();
closeActivity.setOnClickListener(onClickListener); closeActivity.setOnClickListener(onClickListener);
@ -127,7 +137,7 @@ public class CreateNewUserActivity extends AppCompatActivity {
Call<UserInfo> call; Call<UserInfo> call;
call = RetrofitClient call = RetrofitClient
.getInstance(instanceUrl) .getInstance(instanceUrl, getApplicationContext())
.getApiInterface() .getApiInterface()
.createNewUser(instanceToken, createUser); .createNewUser(instanceToken, createUser);

View File

@ -4,9 +4,9 @@ import android.content.Context;
import android.graphics.drawable.GradientDrawable; import android.graphics.drawable.GradientDrawable;
import android.os.Bundle; import android.os.Bundle;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.util.Log; import android.util.Log;
import android.view.View; import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button; import android.widget.Button;
import android.widget.EditText; import android.widget.EditText;
import android.widget.ImageView; import android.widget.ImageView;
@ -25,7 +25,7 @@ import retrofit2.Callback;
* Author M M Arif * Author M M Arif
*/ */
public class NewOrganizationActivity extends AppCompatActivity { public class CreateOrganizationActivity extends BaseActivity {
public ImageView closeActivity; public ImageView closeActivity;
private View.OnClickListener onClickListener; private View.OnClickListener onClickListener;
@ -36,16 +36,26 @@ public class NewOrganizationActivity extends AppCompatActivity {
final Context ctx = this; final Context ctx = this;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected int getLayoutResourceId(){
return R.layout.activity_new_organization;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_new_organization);
boolean connToInternet = AppUtil.haveNetworkConnection(getApplicationContext()); boolean connToInternet = AppUtil.haveNetworkConnection(getApplicationContext());
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
closeActivity = findViewById(R.id.close); closeActivity = findViewById(R.id.close);
orgName = findViewById(R.id.newOrganizationName); orgName = findViewById(R.id.newOrganizationName);
orgDesc = findViewById(R.id.newOrganizationDescription); orgDesc = findViewById(R.id.newOrganizationDescription);
orgName.requestFocus();
assert imm != null;
imm.showSoftInput(orgName, InputMethodManager.SHOW_IMPLICIT);
initCloseListener(); initCloseListener();
closeActivity.setOnClickListener(onClickListener); closeActivity.setOnClickListener(onClickListener);
@ -134,7 +144,7 @@ public class NewOrganizationActivity extends AppCompatActivity {
UserOrganizations createOrganization = new UserOrganizations(orgName, null, orgDesc, null, null); UserOrganizations createOrganization = new UserOrganizations(orgName, null, orgDesc, null, null);
Call<UserOrganizations> call = RetrofitClient Call<UserOrganizations> call = RetrofitClient
.getInstance(instanceUrl) .getInstance(instanceUrl, getApplicationContext())
.getApiInterface() .getApiInterface()
.createNewOrganization(token, createOrganization); .createNewOrganization(token, createOrganization);

View File

@ -1,7 +1,6 @@
package org.mian.gitnex.activities; package org.mian.gitnex.activities;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import retrofit2.Call; import retrofit2.Call;
import retrofit2.Callback; import retrofit2.Callback;
import android.content.Context; import android.content.Context;
@ -10,6 +9,7 @@ import android.graphics.drawable.GradientDrawable;
import android.os.Bundle; import android.os.Bundle;
import android.util.Log; import android.util.Log;
import android.view.View; import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView; import android.widget.AdapterView;
import android.widget.ArrayAdapter; import android.widget.ArrayAdapter;
import android.widget.Button; import android.widget.Button;
@ -33,7 +33,7 @@ import java.util.List;
* Author M M Arif * Author M M Arif
*/ */
public class CreateReleaseActivity extends AppCompatActivity { public class CreateReleaseActivity extends BaseActivity {
private View.OnClickListener onClickListener; private View.OnClickListener onClickListener;
public ImageView closeActivity; public ImageView closeActivity;
@ -49,13 +49,19 @@ public class CreateReleaseActivity extends AppCompatActivity {
List<Branches> branchesList = new ArrayList<>(); List<Branches> branchesList = new ArrayList<>();
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected int getLayoutResourceId(){
return R.layout.activity_create_release;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_create_release);
boolean connToInternet = AppUtil.haveNetworkConnection(getApplicationContext()); boolean connToInternet = AppUtil.haveNetworkConnection(getApplicationContext());
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
TinyDB tinyDb = new TinyDB(getApplicationContext()); TinyDB tinyDb = new TinyDB(getApplicationContext());
final String instanceUrl = tinyDb.getString("instanceUrl"); final String instanceUrl = tinyDb.getString("instanceUrl");
final String loginUid = tinyDb.getString("loginUid"); final String loginUid = tinyDb.getString("loginUid");
@ -72,6 +78,10 @@ public class CreateReleaseActivity extends AppCompatActivity {
releaseType = findViewById(R.id.releaseType); releaseType = findViewById(R.id.releaseType);
releaseDraft = findViewById(R.id.releaseDraft); releaseDraft = findViewById(R.id.releaseDraft);
releaseTagName.requestFocus();
assert imm != null;
imm.showSoftInput(releaseTagName, InputMethodManager.SHOW_IMPLICIT);
initCloseListener(); initCloseListener();
closeActivity.setOnClickListener(onClickListener); closeActivity.setOnClickListener(onClickListener);
@ -164,7 +174,7 @@ public class CreateReleaseActivity extends AppCompatActivity {
Call<Releases> call; Call<Releases> call;
call = RetrofitClient call = RetrofitClient
.getInstance(instanceUrl) .getInstance(instanceUrl, getApplicationContext())
.getApiInterface() .getApiInterface()
.createNewRelease(token, repoOwner, repoName, createReleaseJson); .createNewRelease(token, repoOwner, repoName, createReleaseJson);
@ -224,7 +234,7 @@ public class CreateReleaseActivity extends AppCompatActivity {
private void getBranches(String instanceUrl, String instanceToken, final String repoOwner, final String repoName) { private void getBranches(String instanceUrl, String instanceToken, final String repoOwner, final String repoName) {
Call<List<Branches>> call = RetrofitClient Call<List<Branches>> call = RetrofitClient
.getInstance(instanceUrl) .getInstance(instanceUrl, getApplicationContext())
.getApiInterface() .getApiInterface()
.getBranches(instanceToken, repoOwner, repoName); .getBranches(instanceToken, repoOwner, repoName);

View File

@ -5,9 +5,9 @@ import android.graphics.PorterDuff;
import android.graphics.drawable.GradientDrawable; import android.graphics.drawable.GradientDrawable;
import android.os.Bundle; import android.os.Bundle;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.util.Log; import android.util.Log;
import android.view.View; import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView; import android.widget.AdapterView;
import android.widget.ArrayAdapter; import android.widget.ArrayAdapter;
import android.widget.Button; import android.widget.Button;
@ -25,7 +25,9 @@ import org.mian.gitnex.models.OrganizationRepository;
import org.mian.gitnex.util.AppUtil; import org.mian.gitnex.util.AppUtil;
import org.mian.gitnex.util.TinyDB; import org.mian.gitnex.util.TinyDB;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.regex.Pattern;
import retrofit2.Call; import retrofit2.Call;
import retrofit2.Callback; import retrofit2.Callback;
@ -33,7 +35,7 @@ import retrofit2.Callback;
* Author M M Arif * Author M M Arif
*/ */
public class NewRepoActivity extends AppCompatActivity { public class CreateRepoActivity extends BaseActivity {
public ImageView closeActivity; public ImageView closeActivity;
private View.OnClickListener onClickListener; private View.OnClickListener onClickListener;
@ -44,12 +46,20 @@ public class NewRepoActivity extends AppCompatActivity {
private CheckBox repoAccess; private CheckBox repoAccess;
final Context ctx = this; final Context ctx = this;
List<OrgOwner> orgsList = new ArrayList<>(); List<OrgOwner> organizationsList = new ArrayList<>();
//https://github.com/go-gitea/gitea/blob/52cfd2743c0e85b36081cf80a850e6a5901f1865/models/repo.go#L964-L967
final List<String> reservedRepoNames = Arrays.asList(".", "..");
final Pattern reservedRepoPatterns = Pattern.compile("\\.(git|wiki)$");
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected int getLayoutResourceId(){
return R.layout.activity_new_repo;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_new_repo);
boolean connToInternet = AppUtil.haveNetworkConnection(getApplicationContext()); boolean connToInternet = AppUtil.haveNetworkConnection(getApplicationContext());
@ -59,17 +69,23 @@ public class NewRepoActivity extends AppCompatActivity {
final String userLogin = tinyDb.getString("userLogin"); final String userLogin = tinyDb.getString("userLogin");
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token"); final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
closeActivity = findViewById(R.id.close); closeActivity = findViewById(R.id.close);
repoName = findViewById(R.id.newRepoName); repoName = findViewById(R.id.newRepoName);
repoDesc = findViewById(R.id.newRepoDescription); repoDesc = findViewById(R.id.newRepoDescription);
repoAccess = findViewById(R.id.newRepoPrivate); repoAccess = findViewById(R.id.newRepoPrivate);
repoName.requestFocus();
assert imm != null;
imm.showSoftInput(repoName, InputMethodManager.SHOW_IMPLICIT);
initCloseListener(); initCloseListener();
closeActivity.setOnClickListener(onClickListener); closeActivity.setOnClickListener(onClickListener);
spinner = findViewById(R.id.ownerSpinner); spinner = findViewById(R.id.ownerSpinner);
spinner.getBackground().setColorFilter(getResources().getColor(R.color.white), PorterDuff.Mode.SRC_ATOP); spinner.getBackground().setColorFilter(getResources().getColor(R.color.white), PorterDuff.Mode.SRC_ATOP);
getOrgs(instanceUrl, Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), userLogin); getOrganizations(instanceUrl, Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), userLogin);
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override @Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
@ -95,7 +111,6 @@ public class NewRepoActivity extends AppCompatActivity {
createRepo.setOnClickListener(createRepoListener); createRepo.setOnClickListener(createRepoListener);
} }
} }
private View.OnClickListener createRepoListener = new View.OnClickListener() { private View.OnClickListener createRepoListener = new View.OnClickListener() {
@ -143,15 +158,23 @@ public class NewRepoActivity extends AppCompatActivity {
Toasty.info(getApplicationContext(), getString(R.string.repoNameErrorInvalid)); Toasty.info(getApplicationContext(), getString(R.string.repoNameErrorInvalid));
}
else if (reservedRepoNames.contains(newRepoName)) {
Toasty.info(getApplicationContext(), getString(R.string.repoNameErrorReservedName));
}
else if (reservedRepoPatterns.matcher(newRepoName).find()) {
Toasty.info(getApplicationContext(), getString(R.string.repoNameErrorReservedPatterns));
} }
else { else {
//Log.i("repoOwner", String.valueOf(repoOwner));
disableProcessButton(); disableProcessButton();
createNewRepository(instanceUrl, Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), loginUid, newRepoName, newRepoDesc, repoOwner, newRepoAccess); createNewRepository(instanceUrl, Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), loginUid, newRepoName, newRepoDesc, repoOwner, newRepoAccess);
} }
} }
private void createNewRepository(final String instanceUrl, final String token, String loginUid, String repoName, String repoDesc, String repoOwner, boolean isPrivate) { private void createNewRepository(final String instanceUrl, final String token, String loginUid, String repoName, String repoDesc, String repoOwner, boolean isPrivate) {
@ -162,7 +185,7 @@ public class NewRepoActivity extends AppCompatActivity {
if(repoOwner.equals(loginUid)) { if(repoOwner.equals(loginUid)) {
call = RetrofitClient call = RetrofitClient
.getInstance(instanceUrl) .getInstance(instanceUrl, getApplicationContext())
.getApiInterface() .getApiInterface()
.createNewUserRepository(token, createRepository); .createNewUserRepository(token, createRepository);
@ -170,7 +193,7 @@ public class NewRepoActivity extends AppCompatActivity {
else { else {
call = RetrofitClient call = RetrofitClient
.getInstance(instanceUrl) .getInstance(instanceUrl, getApplicationContext())
.getApiInterface() .getApiInterface()
.createNewUserOrgRepository(token, repoOwner, createRepository); .createNewUserOrgRepository(token, repoOwner, createRepository);
@ -219,13 +242,14 @@ public class NewRepoActivity extends AppCompatActivity {
enableProcessButton(); enableProcessButton();
} }
}); });
} }
private void getOrgs(String instanceUrl, String instanceToken, final String userLogin) { private void getOrganizations(String instanceUrl, String instanceToken, final String userLogin) {
TinyDB tinyDb = new TinyDB(getApplicationContext());
Call<List<OrgOwner>> call = RetrofitClient Call<List<OrgOwner>> call = RetrofitClient
.getInstance(instanceUrl) .getInstance(instanceUrl, getApplicationContext())
.getApiInterface() .getApiInterface()
.getOrgOwners(instanceToken); .getOrgOwners(instanceToken);
@ -237,26 +261,39 @@ public class NewRepoActivity extends AppCompatActivity {
if(response.isSuccessful()) { if(response.isSuccessful()) {
if(response.code() == 200) { if(response.code() == 200) {
List<OrgOwner> orgsList_ = response.body(); int organizationId = 0;
orgsList.add(new OrgOwner(userLogin)); List<OrgOwner> organizationsList_ = response.body();
assert orgsList_ != null;
if(orgsList_.size() > 0) {
for (int i = 0; i < orgsList_.size(); i++) {
organizationsList.add(new OrgOwner(userLogin));
assert organizationsList_ != null;
if(organizationsList_.size() > 0) {
for (int i = 0; i < organizationsList_.size(); i++) {
if(!tinyDb.getString("organizationId").isEmpty()) {
if (Integer.parseInt(tinyDb.getString("organizationId")) == organizationsList_.get(i).getId()) {
organizationId = i + 1;
}
}
OrgOwner data = new OrgOwner( OrgOwner data = new OrgOwner(
orgsList_.get(i).getUsername() organizationsList_.get(i).getUsername()
); );
orgsList.add(data); organizationsList.add(data);
} }
} }
ArrayAdapter<OrgOwner> adapter = new ArrayAdapter<>(getApplicationContext(), ArrayAdapter<OrgOwner> adapter = new ArrayAdapter<>(getApplicationContext(),
R.layout.spinner_item, orgsList); R.layout.spinner_item, organizationsList);
adapter.setDropDownViewResource(R.layout.spinner_dropdown_item); adapter.setDropDownViewResource(R.layout.spinner_dropdown_item);
spinner.setAdapter(adapter); spinner.setAdapter(adapter);
if (tinyDb.getBoolean("organizationAction") & organizationId != 0) {
spinner.setSelection(organizationId);
tinyDb.putBoolean("organizationAction", false);
}
enableProcessButton(); enableProcessButton();
} }
@ -279,7 +316,6 @@ public class NewRepoActivity extends AppCompatActivity {
enableProcessButton(); enableProcessButton();
} }
}); });
} }
private void initCloseListener() { private void initCloseListener() {

View File

@ -2,7 +2,6 @@ package org.mian.gitnex.activities;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import retrofit2.Call; import retrofit2.Call;
import retrofit2.Callback; import retrofit2.Callback;
import android.content.Context; import android.content.Context;
@ -10,6 +9,7 @@ import android.content.DialogInterface;
import android.graphics.drawable.GradientDrawable; import android.graphics.drawable.GradientDrawable;
import android.os.Bundle; import android.os.Bundle;
import android.view.View; import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button; import android.widget.Button;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
@ -30,7 +30,7 @@ import android.util.Log;
* Author M M Arif * Author M M Arif
*/ */
public class CreateTeamByOrgActivity extends AppCompatActivity implements View.OnClickListener { public class CreateTeamByOrgActivity extends BaseActivity implements View.OnClickListener {
final Context ctx = CreateTeamByOrgActivity.this; final Context ctx = CreateTeamByOrgActivity.this;
private View.OnClickListener onClickListener; private View.OnClickListener onClickListener;
@ -44,6 +44,11 @@ public class CreateTeamByOrgActivity extends AppCompatActivity implements View.O
private String[] permissionList = {"Read", "Write", "Admin"}; private String[] permissionList = {"Read", "Write", "Admin"};
public int permissionSelectedChoice = -1; public int permissionSelectedChoice = -1;
@Override
protected int getLayoutResourceId(){
return R.layout.activity_create_team_by_org;
}
private String[] accessControlsList = new String[] { private String[] accessControlsList = new String[] {
"Code", "Code",
"Issues", "Issues",
@ -67,12 +72,13 @@ public class CreateTeamByOrgActivity extends AppCompatActivity implements View.O
}; };
@Override @Override
protected void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_create_team_by_org);
boolean connToInternet = AppUtil.haveNetworkConnection(getApplicationContext()); boolean connToInternet = AppUtil.haveNetworkConnection(getApplicationContext());
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
ImageView closeActivity = findViewById(R.id.close); ImageView closeActivity = findViewById(R.id.close);
teamName = findViewById(R.id.teamName); teamName = findViewById(R.id.teamName);
teamDesc = findViewById(R.id.teamDesc); teamDesc = findViewById(R.id.teamDesc);
@ -82,6 +88,10 @@ public class CreateTeamByOrgActivity extends AppCompatActivity implements View.O
teamAccessControlsArray = findViewById(R.id.teamAccessControlsArray); teamAccessControlsArray = findViewById(R.id.teamAccessControlsArray);
createTeamButton = findViewById(R.id.createTeamButton); createTeamButton = findViewById(R.id.createTeamButton);
teamName.requestFocus();
assert imm != null;
imm.showSoftInput(teamName, InputMethodManager.SHOW_IMPLICIT);
initCloseListener(); initCloseListener();
closeActivity.setOnClickListener(onClickListener); closeActivity.setOnClickListener(onClickListener);
@ -89,7 +99,7 @@ public class CreateTeamByOrgActivity extends AppCompatActivity implements View.O
@Override @Override
public void onClick(View view) { public void onClick(View view) {
AlertDialog.Builder pBuilder = new AlertDialog.Builder(ctx, R.style.confirmDialog); AlertDialog.Builder pBuilder = new AlertDialog.Builder(ctx);
pBuilder.setTitle(R.string.newTeamPermission); pBuilder.setTitle(R.string.newTeamPermission);
if(permissionSelectedChoice != -1) { if(permissionSelectedChoice != -1) {
@ -141,7 +151,7 @@ public class CreateTeamByOrgActivity extends AppCompatActivity implements View.O
teamAccessControlsArray.setText(""); teamAccessControlsArray.setText("");
pushAccessList = Arrays.asList(accessControlsList); pushAccessList = Arrays.asList(accessControlsList);
AlertDialog.Builder aDialogBuilder = new AlertDialog.Builder(ctx, R.style.confirmDialog); AlertDialog.Builder aDialogBuilder = new AlertDialog.Builder(ctx);
aDialogBuilder.setMultiChoiceItems(accessControlsList, selectedAccessControlsTrueFalse, new DialogInterface.OnMultiChoiceClickListener() { aDialogBuilder.setMultiChoiceItems(accessControlsList, selectedAccessControlsTrueFalse, new DialogInterface.OnMultiChoiceClickListener() {
@ -308,7 +318,7 @@ public class CreateTeamByOrgActivity extends AppCompatActivity implements View.O
Call<Teams> call3; Call<Teams> call3;
call3 = RetrofitClient call3 = RetrofitClient
.getInstance(instanceUrl) .getInstance(instanceUrl, getApplicationContext())
.getApiInterface() .getApiInterface()
.createTeamsByOrg(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), orgName, createNewTeamJson); .createTeamsByOrg(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), orgName, createNewTeamJson);

View File

@ -1,35 +1,58 @@
package org.mian.gitnex.activities; package org.mian.gitnex.activities;
import androidx.appcompat.app.AppCompatActivity; import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.content.res.Resources;
import android.os.Bundle; import android.os.Bundle;
import android.text.method.LinkMovementMethod;
import android.view.View; import android.view.View;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView;
import org.mian.gitnex.R; import org.mian.gitnex.R;
import org.mian.gitnex.adapters.CreditsAdapter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/** /**
* Author M M Arif * Author M M Arif
*/ */
public class CreditsActivity extends AppCompatActivity { public class CreditsActivity extends BaseActivity {
private View.OnClickListener onClickListener; private View.OnClickListener onClickListener;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected int getLayoutResourceId(){
return R.layout.activity_credits;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_credits);
TextView creditKasun = findViewById(R.id.creditKasun);
ImageView closeActivity = findViewById(R.id.close); ImageView closeActivity = findViewById(R.id.close);
creditKasun.setMovementMethod(LinkMovementMethod.getInstance());
initCloseListener(); initCloseListener();
closeActivity.setOnClickListener(onClickListener); closeActivity.setOnClickListener(onClickListener);
Resources res = getResources();
CharSequence[] creditsInfo = res.getTextArray(R.array.creditsInfo);
List<CharSequence> creditsList = new ArrayList<>(Arrays.asList(creditsInfo));
RecyclerView mRecyclerView = findViewById(R.id.recyclerView);
mRecyclerView.setHasFixedSize(true);
mRecyclerView.setLayoutManager(new LinearLayoutManager(getApplicationContext()));
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(mRecyclerView.getContext(),
DividerItemDecoration.VERTICAL);
mRecyclerView.addItemDecoration(dividerItemDecoration);
CreditsAdapter adapter = new CreditsAdapter(creditsList);
mRecyclerView.setAdapter(adapter);
} }
private void initCloseListener() { private void initCloseListener() {

View File

@ -1,7 +1,6 @@
package org.mian.gitnex.activities; package org.mian.gitnex.activities;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import retrofit2.Call; import retrofit2.Call;
import retrofit2.Callback; import retrofit2.Callback;
import retrofit2.Response; import retrofit2.Response;
@ -13,6 +12,7 @@ import android.graphics.drawable.GradientDrawable;
import android.os.Bundle; import android.os.Bundle;
import android.util.Log; import android.util.Log;
import android.view.View; import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.ArrayAdapter; import android.widget.ArrayAdapter;
import android.widget.Button; import android.widget.Button;
import android.widget.DatePicker; import android.widget.DatePicker;
@ -45,7 +45,7 @@ import java.util.List;
* Author M M Arif * Author M M Arif
*/ */
public class EditIssueActivity extends AppCompatActivity implements View.OnClickListener { public class EditIssueActivity extends BaseActivity implements View.OnClickListener {
final Context ctx = this; final Context ctx = this;
private View.OnClickListener onClickListener; private View.OnClickListener onClickListener;
@ -62,10 +62,16 @@ public class EditIssueActivity extends AppCompatActivity implements View.OnClick
private ArrayAdapter<Mention> defaultMentionAdapter; private ArrayAdapter<Mention> defaultMentionAdapter;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected int getLayoutResourceId(){
return R.layout.activity_edit_issue;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_edit_issue);
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
final TinyDB tinyDb = new TinyDB(getApplicationContext()); final TinyDB tinyDb = new TinyDB(getApplicationContext());
@ -85,6 +91,10 @@ public class EditIssueActivity extends AppCompatActivity implements View.OnClick
editIssueDescription = findViewById(R.id.editIssueDescription); editIssueDescription = findViewById(R.id.editIssueDescription);
editIssueDueDate = findViewById(R.id.editIssueDueDate); editIssueDueDate = findViewById(R.id.editIssueDueDate);
editIssueTitle.requestFocus();
assert imm != null;
imm.showSoftInput(editIssueTitle, InputMethodManager.SHOW_IMPLICIT);
defaultMentionAdapter = new MentionArrayAdapter<>(this); defaultMentionAdapter = new MentionArrayAdapter<>(this);
loadCollaboratorsList(); loadCollaboratorsList();
@ -100,8 +110,14 @@ public class EditIssueActivity extends AppCompatActivity implements View.OnClick
editIssueButton.setOnClickListener(this); editIssueButton.setOnClickListener(this);
if(!tinyDb.getString("issueNumber").isEmpty()) { if(!tinyDb.getString("issueNumber").isEmpty()) {
if(tinyDb.getString("issueType").equals("pr")) {
toolbar_title.setText(getString(R.string.editPrNavHeader, String.valueOf(issueIndex)));
}
else {
toolbar_title.setText(getString(R.string.editIssueNavHeader, String.valueOf(issueIndex))); toolbar_title.setText(getString(R.string.editIssueNavHeader, String.valueOf(issueIndex)));
} }
}
disableProcessButton(); disableProcessButton();
getIssue(instanceUrl, instanceToken, loginUid, repoOwner, repoName, issueIndex); getIssue(instanceUrl, instanceToken, loginUid, repoOwner, repoName, issueIndex);
@ -122,7 +138,7 @@ public class EditIssueActivity extends AppCompatActivity implements View.OnClick
final String repoName = parts[1]; final String repoName = parts[1];
Call<List<Collaborators>> call = RetrofitClient Call<List<Collaborators>> call = RetrofitClient
.getInstance(instanceUrl) .getInstance(instanceUrl, getApplicationContext())
.getApiInterface() .getApiInterface()
.getCollaborators(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName); .getCollaborators(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName);
@ -153,7 +169,7 @@ public class EditIssueActivity extends AppCompatActivity implements View.OnClick
@Override @Override
public void onFailure(@NonNull Call<List<Collaborators>> call, @NonNull Throwable t) { public void onFailure(@NonNull Call<List<Collaborators>> call, @NonNull Throwable t) {
Log.i("onFailure", t.getMessage()); Log.i("onFailure", t.toString());
} }
}); });
@ -229,7 +245,7 @@ public class EditIssueActivity extends AppCompatActivity implements View.OnClick
CreateIssue issueData = new CreateIssue(title, description, dueDate, editIssueMilestoneId); CreateIssue issueData = new CreateIssue(title, description, dueDate, editIssueMilestoneId);
Call<JsonElement> call = RetrofitClient Call<JsonElement> call = RetrofitClient
.getInstance(instanceUrl) .getInstance(instanceUrl, getApplicationContext())
.getApiInterface() .getApiInterface()
.patchIssue(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName, issueIndex, issueData); .patchIssue(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName, issueIndex, issueData);
@ -240,7 +256,13 @@ public class EditIssueActivity extends AppCompatActivity implements View.OnClick
if(response.code() == 201) { if(response.code() == 201) {
if(tinyDb.getString("issueType").equals("pr")) {
Toasty.info(getApplicationContext(), getString(R.string.editPrSuccessMessage));
}
else {
Toasty.info(getApplicationContext(), getString(R.string.editIssueSuccessMessage)); Toasty.info(getApplicationContext(), getString(R.string.editIssueSuccessMessage));
}
tinyDb.putBoolean("issueEdited", true); tinyDb.putBoolean("issueEdited", true);
tinyDb.putBoolean("resumeIssues", true); tinyDb.putBoolean("resumeIssues", true);
finish(); finish();
@ -307,7 +329,7 @@ public class EditIssueActivity extends AppCompatActivity implements View.OnClick
private void getIssue(final String instanceUrl, final String instanceToken, final String loginUid, final String repoOwner, final String repoName, int issueIndex) { private void getIssue(final String instanceUrl, final String instanceToken, final String loginUid, final String repoOwner, final String repoName, int issueIndex) {
Call<Issues> call = RetrofitClient Call<Issues> call = RetrofitClient
.getInstance(instanceUrl) .getInstance(instanceUrl, getApplicationContext())
.getApiInterface() .getApiInterface()
.getIssueByIndex(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName, issueIndex); .getIssueByIndex(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName, issueIndex);
@ -331,7 +353,7 @@ public class EditIssueActivity extends AppCompatActivity implements View.OnClick
if(response.body().getId() > 0) { if(response.body().getId() > 0) {
Call<List<Milestones>> call_ = RetrofitClient Call<List<Milestones>> call_ = RetrofitClient
.getInstance(instanceUrl) .getInstance(instanceUrl, getApplicationContext())
.getApiInterface() .getApiInterface()
.getMilestones(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName, msState); .getMilestones(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName, msState);

View File

@ -0,0 +1,219 @@
package org.mian.gitnex.activities;
import android.os.Bundle;
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.widget.Toolbar;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import org.apache.commons.io.FileUtils;
import org.mian.gitnex.R;
import org.mian.gitnex.adapters.FilesDiffAdapter;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.helpers.AlertDialogs;
import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.models.FileDiffView;
import org.mian.gitnex.util.AppUtil;
import org.mian.gitnex.util.TinyDB;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.Callback;
/**
* Author M M Arif
*/
public class FileDiffActivity extends BaseActivity {
private View.OnClickListener onClickListener;
private TextView toolbar_title;
private RecyclerView mRecyclerView;
private ProgressBar mProgressBar;
@Override
protected int getLayoutResourceId(){
return R.layout.activity_file_diff;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
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");
ImageView closeActivity = findViewById(R.id.close);
toolbar_title = findViewById(R.id.toolbar_title);
mRecyclerView = findViewById(R.id.recyclerView);
mProgressBar = findViewById(R.id.progress_bar);
mRecyclerView.setHasFixedSize(true);
mRecyclerView.setLayoutManager(new LinearLayoutManager(getApplicationContext()));
toolbar_title.setText(R.string.processingText);
initCloseListener();
closeActivity.setOnClickListener(onClickListener);
mProgressBar.setVisibility(View.VISIBLE);
String pullIndex = tinyDb.getString("issueNumber");
getPullDiffContent(tinyDb.getString("instanceUrlWithProtocol"), repoOwner, repoName, pullIndex);
}
private void getPullDiffContent(String instanceUrl, String owner, String repo, String filename) {
Call<ResponseBody> call = RetrofitClient
.getInstance(instanceUrl, getApplicationContext())
.getWebInterface()
.getPullDiffContent(owner, repo, filename);
call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(@NonNull Call<ResponseBody> call, @NonNull retrofit2.Response<ResponseBody> response) {
if (response.code() == 200) {
try {
assert response.body() != null;
AppUtil appUtil = new AppUtil();
List<FileDiffView> fileContentsArray = new ArrayList<>();
String[] lines = response.body().string().split("diff");
if(lines.length > 0) {
for (int i = 1; i < lines.length; i++) {
if(lines[i].contains("@@ -")) {
String[] level2nd = lines[i].split("@@ -"); // main content part of single diff view
String[] fileName_ = level2nd[0].split("\\+\\+\\+ b/"); // filename part
String fileNameFinal = fileName_[1];
String[] fileContents_ = level2nd[1].split("@@"); // file info / content part
String fileInfoFinal = fileContents_[0];
String fileContentsFinal = (fileContents_[1]);
if(level2nd.length > 2) {
for (int j = 2; j < level2nd.length; j++) {
fileContentsFinal += (level2nd[j]);
}
}
String fileExtension = FileUtils.getExtension(fileNameFinal);
String fileContentsFinalWithBlankLines = fileContentsFinal.replaceAll( ".*@@.*", "" );
String fileContentsFinalWithoutBlankLines = fileContentsFinal.replaceAll( ".*@@.*(\r?\n|\r)?", "" );
fileContentsFinalWithoutBlankLines = fileContentsFinalWithoutBlankLines.replaceAll( ".*\\ No newline at end of file.*(\r?\n|\r)?", "" );
fileContentsArray.add(new FileDiffView(fileNameFinal, appUtil.imageExtension(fileExtension), fileInfoFinal, fileContentsFinalWithoutBlankLines));
}
else {
String[] getFileName = lines[i].split("--git a/");
String[] getFileName_ = getFileName[1].split("b/");
String getFileNameFinal = getFileName_[0].trim();
String[] binaryFile = getFileName_[1].split("GIT binary patch");
String binaryFileRaw = binaryFile[1].substring(binaryFile[1].indexOf('\n')+1);
String binaryFileFinal = binaryFile[1].substring(binaryFileRaw.indexOf('\n')+1);
String fileExtension = FileUtils.getExtension(getFileNameFinal);
if(appUtil.imageExtension(FileUtils.getExtension(getFileNameFinal))) {
fileContentsArray.add(new FileDiffView(getFileNameFinal, appUtil.imageExtension(fileExtension), "", binaryFileFinal));
}
}
}
}
int filesCount = fileContentsArray.size();
if(filesCount > 1) {
toolbar_title.setText(getResources().getString(R.string.fileDiffViewHeader, Integer.toString(filesCount)));
}
else {
toolbar_title.setText(getResources().getString(R.string.fileDiffViewHeaderSingle, Integer.toString(filesCount)));
}
FilesDiffAdapter adapter = new FilesDiffAdapter(fileContentsArray, getApplicationContext());
mRecyclerView.setAdapter(adapter);
mProgressBar.setVisibility(View.GONE);
} catch (IOException e) {
e.printStackTrace();
}
}
else if(response.code() == 401) {
AlertDialogs.authorizationTokenRevokedDialog(getApplicationContext(), 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(getApplicationContext(), getApplicationContext().getString(R.string.authorizeError));
}
else if(response.code() == 404) {
Toasty.info(getApplicationContext(), getApplicationContext().getString(R.string.apiNotFound));
}
else {
Toasty.info(getApplicationContext(), getString(R.string.labelGeneralError));
}
}
@Override
public void onFailure(@NonNull Call<ResponseBody> 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

@ -1,23 +1,50 @@
package org.mian.gitnex.activities; package org.mian.gitnex.activities;
import android.content.Context; import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.BitmapFactory;
import android.graphics.Typeface;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.os.Environment;
import android.text.method.ScrollingMovementMethod; import android.text.method.ScrollingMovementMethod;
import android.util.Base64;
import android.util.Log; import android.util.Log;
import android.view.Gravity;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar; import android.widget.ProgressBar;
import android.widget.TextView; import android.widget.TextView;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar; import androidx.appcompat.widget.Toolbar;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import com.github.barteksc.pdfviewer.PDFView;
import com.github.barteksc.pdfviewer.util.FitPolicy;
import com.github.chrisbanes.photoview.PhotoView;
import com.pddstudio.highlightjs.HighlightJsView;
import com.pddstudio.highlightjs.models.Theme;
import org.apache.commons.io.FileUtils;
import org.mian.gitnex.R; import org.mian.gitnex.R;
import org.mian.gitnex.clients.RetrofitClient; import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.fragments.BottomSheetFileViewerFragment;
import org.mian.gitnex.helpers.AlertDialogs; import org.mian.gitnex.helpers.AlertDialogs;
import org.mian.gitnex.helpers.Toasty; import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.models.Files; import org.mian.gitnex.models.Files;
import org.mian.gitnex.util.AppUtil; import org.mian.gitnex.util.AppUtil;
import org.mian.gitnex.util.TinyDB; import org.mian.gitnex.util.TinyDB;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.Objects;
import retrofit2.Call; import retrofit2.Call;
import retrofit2.Callback; import retrofit2.Callback;
@ -25,18 +52,32 @@ import retrofit2.Callback;
* Author M M Arif * Author M M Arif
*/ */
public class FileViewActivity extends AppCompatActivity { public class FileViewActivity extends BaseActivity implements BottomSheetFileViewerFragment.BottomSheetListener {
private View.OnClickListener onClickListener; private View.OnClickListener onClickListener;
private TextView singleFileContents; private TextView singleFileContents;
private LinearLayout singleFileContentsFrame;
private HighlightJsView singleCodeContents;
private PhotoView imageView;
final Context ctx = this; final Context ctx = this;
private ProgressBar mProgressBar; private ProgressBar mProgressBar;
private byte[] imageData;
private PDFView pdfView;
private LinearLayout pdfViewFrame;
private byte[] decodedPdf;
private Boolean pdfNightMode;
private static final int PERMISSION_REQUEST_CODE = 1;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected int getLayoutResourceId() {
return R.layout.activity_file_view;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_file_view);
Toolbar toolbar = findViewById(R.id.toolbar); Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar); setSupportActionBar(toolbar);
@ -49,37 +90,50 @@ public class FileViewActivity extends AppCompatActivity {
final String loginUid = tinyDb.getString("loginUid"); final String loginUid = tinyDb.getString("loginUid");
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token"); final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
boolean connToInternet = AppUtil.haveNetworkConnection(getApplicationContext());
ImageView closeActivity = findViewById(R.id.close); ImageView closeActivity = findViewById(R.id.close);
singleFileContents = findViewById(R.id.singleFileContents); singleFileContents = findViewById(R.id.singleFileContents);
singleFileContents.setVisibility(View.GONE); singleCodeContents = findViewById(R.id.singleCodeContents);
imageView = findViewById(R.id.imageView);
mProgressBar = findViewById(R.id.progress_bar); mProgressBar = findViewById(R.id.progress_bar);
pdfView = findViewById(R.id.pdfView);
pdfViewFrame = findViewById(R.id.pdfViewFrame);
singleFileContentsFrame = findViewById(R.id.singleFileContentsFrame);
String singleFileName = getIntent().getStringExtra("singleFileName"); String singleFileName = getIntent().getStringExtra("singleFileName");
TextView toolbar_title = findViewById(R.id.toolbar_title); TextView toolbar_title = findViewById(R.id.toolbar_title);
toolbar_title.setMovementMethod(new ScrollingMovementMethod()); toolbar_title.setMovementMethod(new ScrollingMovementMethod());
toolbar_title.setText(singleFileName);
initCloseListener(); initCloseListener();
closeActivity.setOnClickListener(onClickListener); closeActivity.setOnClickListener(onClickListener);
if(connToInternet) { tinyDb.putString("downloadFileContents", "");
try {
singleFileName = URLDecoder.decode(singleFileName, "UTF-8");
singleFileName = singleFileName.replaceAll("//", "/");
singleFileName = singleFileName.startsWith("/") ? singleFileName.substring(1) : singleFileName;
}
catch(UnsupportedEncodingException e) {
assert singleFileName != null;
Log.i("singleFileName", singleFileName);
}
toolbar_title.setText(singleFileName);
getSingleFileContents(instanceUrl, instanceToken, repoOwner, repoName, singleFileName); 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) { private void getSingleFileContents(String instanceUrl, String token, final String owner, String repo, final String filename) {
Call<Files> call = RetrofitClient final TinyDB tinyDb = new TinyDB(getApplicationContext());
.getInstance(instanceUrl)
.getApiInterface() Call<Files> call = RetrofitClient.getInstance(instanceUrl, getApplicationContext()).getApiInterface().getSingleFileContents(token, owner, repo, filename);
.getSingleFileContents(token, owner, repo, filename);
call.enqueue(new Callback<Files>() { call.enqueue(new Callback<Files>() {
@ -92,9 +146,93 @@ public class FileViewActivity extends AppCompatActivity {
assert response.body() != null; assert response.body() != null;
if(!response.body().getContent().equals("")) { if(!response.body().getContent().equals("")) {
singleFileContents.setVisibility(View.VISIBLE);
String fileExtension = FileUtils.getExtension(filename);
mProgressBar.setVisibility(View.GONE); mProgressBar.setVisibility(View.GONE);
// download file meta
tinyDb.putString("downloadFileName", filename);
tinyDb.putString("downloadFileContents", response.body().getContent());
if(appUtil.imageExtension(fileExtension)) { // file is image
singleFileContentsFrame.setVisibility(View.GONE);
singleCodeContents.setVisibility(View.GONE);
pdfViewFrame.setVisibility(View.GONE);
imageView.setVisibility(View.VISIBLE);
imageData = Base64.decode(response.body().getContent(), Base64.DEFAULT);
Drawable imageDrawable = new BitmapDrawable(getResources(), BitmapFactory.decodeByteArray(imageData, 0, imageData.length));
imageView.setImageDrawable(imageDrawable);
}
else if(appUtil.sourceCodeExtension(fileExtension)) { // file is sourcecode
imageView.setVisibility(View.GONE);
singleFileContentsFrame.setVisibility(View.GONE);
pdfViewFrame.setVisibility(View.GONE);
singleCodeContents.setVisibility(View.VISIBLE);
switch(tinyDb.getInt("fileviewerSourceCodeThemeId")) {
case 1:
singleCodeContents.setTheme(Theme.ARDUINO_LIGHT);
break;
case 2:
singleCodeContents.setTheme(Theme.GITHUB);
break;
case 3:
singleCodeContents.setTheme(Theme.FAR);
break;
case 4:
singleCodeContents.setTheme(Theme.IR_BLACK);
break;
case 5:
singleCodeContents.setTheme(Theme.ANDROID_STUDIO);
break;
default:
singleCodeContents.setTheme(Theme.MONOKAI_SUBLIME);
}
singleCodeContents.setShowLineNumbers(true);
singleCodeContents.setSource(appUtil.decodeBase64(response.body().getContent()));
}
else if(appUtil.pdfExtension(fileExtension)) { // file is pdf
imageView.setVisibility(View.GONE);
singleFileContentsFrame.setVisibility(View.GONE);
singleCodeContents.setVisibility(View.GONE);
pdfViewFrame.setVisibility(View.VISIBLE);
pdfNightMode = tinyDb.getBoolean("enablePdfMode");
decodedPdf = Base64.decode(response.body().getContent(), Base64.DEFAULT);
pdfView.fromBytes(decodedPdf).enableSwipe(true).swipeHorizontal(false).enableDoubletap(true).defaultPage(0).enableAnnotationRendering(false).password(null).scrollHandle(null).enableAntialiasing(true).spacing(0).autoSpacing(true).pageFitPolicy(FitPolicy.WIDTH).fitEachPage(true).pageSnap(false).pageFling(true).nightMode(pdfNightMode).load();
}
else if(appUtil.excludeFilesInFileViewerExtension(fileExtension)) { // files need to be excluded
imageView.setVisibility(View.GONE);
singleCodeContents.setVisibility(View.GONE);
pdfViewFrame.setVisibility(View.GONE);
singleFileContentsFrame.setVisibility(View.VISIBLE);
singleFileContents.setText(getResources().getString(R.string.excludeFilesInFileviewer));
singleFileContents.setGravity(Gravity.CENTER);
singleFileContents.setTypeface(null, Typeface.BOLD);
}
else { // file type not known - plain text view
imageView.setVisibility(View.GONE);
singleCodeContents.setVisibility(View.GONE);
pdfViewFrame.setVisibility(View.GONE);
singleFileContentsFrame.setVisibility(View.VISIBLE);
singleFileContents.setText(appUtil.decodeBase64(response.body().getContent())); singleFileContents.setText(appUtil.decodeBase64(response.body().getContent()));
}
} }
else { else {
singleFileContents.setText(""); singleFileContents.setText("");
@ -104,10 +242,7 @@ public class FileViewActivity extends AppCompatActivity {
} }
else if(response.code() == 401) { else if(response.code() == 401) {
AlertDialogs.authorizationTokenRevokedDialog(ctx, getResources().getString(R.string.alertDialogTokenRevokedTitle), AlertDialogs.authorizationTokenRevokedDialog(ctx, getResources().getString(R.string.alertDialogTokenRevokedTitle), getResources().getString(R.string.alertDialogTokenRevokedMessage), getResources().getString(R.string.alertDialogTokenRevokedCopyNegativeButton), getResources().getString(R.string.alertDialogTokenRevokedCopyPositiveButton));
getResources().getString(R.string.alertDialogTokenRevokedMessage),
getResources().getString(R.string.alertDialogTokenRevokedCopyNegativeButton),
getResources().getString(R.string.alertDialogTokenRevokedCopyPositiveButton));
} }
else if(response.code() == 403) { else if(response.code() == 403) {
@ -130,16 +265,128 @@ public class FileViewActivity extends AppCompatActivity {
@Override @Override
public void onFailure(@NonNull Call<Files> call, @NonNull Throwable t) { public void onFailure(@NonNull Call<Files> call, @NonNull Throwable t) {
Log.e("onFailure", t.toString()); Log.e("onFailure", t.toString());
} }
}); });
} }
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.generic_nav_dotted_menu, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
switch(id) {
case android.R.id.home:
finish();
return true;
case R.id.genericMenu:
BottomSheetFileViewerFragment bottomSheet = new BottomSheetFileViewerFragment();
bottomSheet.show(getSupportFragmentManager(), "fileViewerBottomSheet");
return true;
default:
return super.onOptionsItemSelected(item);
}
}
@Override
public void onButtonClicked(String text) {
switch(text) {
case "downloadFile":
if(Build.VERSION.SDK_INT >= 23) {
if(checkPermission()) {
requestFileDownload();
}
else {
requestPermission();
}
}
else {
requestFileDownload();
}
break;
}
}
private void requestFileDownload() {
final TinyDB tinyDb = new TinyDB(getApplicationContext());
if(!tinyDb.getString("downloadFileContents").isEmpty()) {
File outputFileName = new File(tinyDb.getString("downloadFileName"));
final File downloadFilePath = new File(Environment.getExternalStorageDirectory().getPath() + "/Download/" + outputFileName.getName());
byte[] pdfAsBytes = Base64.decode(tinyDb.getString("downloadFileContents"), 0);
FileOutputStream fileOutputStream = null;
try {
fileOutputStream = new FileOutputStream(downloadFilePath, false);
Objects.requireNonNull(fileOutputStream).write(pdfAsBytes);
fileOutputStream.flush();
fileOutputStream.close();
Toasty.info(getApplicationContext(), getString(R.string.downloadFileSaved));
}
catch(IOException e) {
Log.e("errorFileDownloading", Objects.requireNonNull(e.getMessage()));
}
}
else {
Toasty.error(getApplicationContext(), getString(R.string.waitLoadingDownloadFile));
}
}
private boolean checkPermission() {
int result = ContextCompat.checkSelfPermission(this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE);
return result == PackageManager.PERMISSION_GRANTED;
}
private void requestPermission() {
ActivityCompat.requestPermissions(this, new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE}, PERMISSION_REQUEST_CODE);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
switch(requestCode) {
case PERMISSION_REQUEST_CODE:
if(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Log.i("PermissionsCheck", "Permission Granted");
}
else {
Log.e("PermissionsCheck", "Permission Denied");
}
break;
}
}
private void initCloseListener() { private void initCloseListener() {
onClickListener = new View.OnClickListener() { onClickListener = new View.OnClickListener() {
@Override @Override
public void onClick(View view) { public void onClick(View view) {
getIntent().removeExtra("singleFileName"); getIntent().removeExtra("singleFileName");
finish(); finish();
} }

View File

@ -2,10 +2,9 @@ package org.mian.gitnex.activities;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar; import androidx.appcompat.widget.Toolbar;
import androidx.lifecycle.Observer; import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProviders; import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.DividerItemDecoration; import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
@ -18,7 +17,6 @@ import io.noties.markwon.ext.strikethrough.StrikethroughPlugin;
import io.noties.markwon.ext.tables.TablePlugin; import io.noties.markwon.ext.tables.TablePlugin;
import io.noties.markwon.ext.tasklist.TaskListPlugin; import io.noties.markwon.ext.tasklist.TaskListPlugin;
import io.noties.markwon.html.HtmlPlugin; import io.noties.markwon.html.HtmlPlugin;
import io.noties.markwon.image.AsyncDrawable;
import io.noties.markwon.image.DefaultMediaDecoder; import io.noties.markwon.image.DefaultMediaDecoder;
import io.noties.markwon.image.ImageItem; import io.noties.markwon.image.ImageItem;
import io.noties.markwon.image.ImagesPlugin; import io.noties.markwon.image.ImagesPlugin;
@ -30,12 +28,15 @@ import retrofit2.Call;
import retrofit2.Callback; import retrofit2.Callback;
import retrofit2.Response; import retrofit2.Response;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.graphics.Color; import android.graphics.Color;
import android.graphics.Typeface; import android.graphics.Typeface;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.net.Uri; import android.net.Uri;
import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.text.Html;
import android.text.Spanned; import android.text.Spanned;
import android.util.Log; import android.util.Log;
import android.view.Gravity; import android.view.Gravity;
@ -50,14 +51,15 @@ import android.widget.RelativeLayout;
import android.widget.ScrollView; import android.widget.ScrollView;
import android.widget.TextView; import android.widget.TextView;
import com.amulyakhare.textdrawable.TextDrawable; import com.amulyakhare.textdrawable.TextDrawable;
import com.squareup.picasso.Picasso;
import com.vdurmont.emoji.EmojiParser; import com.vdurmont.emoji.EmojiParser;
import org.mian.gitnex.R; import org.mian.gitnex.R;
import org.mian.gitnex.adapters.IssueCommentsAdapter; import org.mian.gitnex.adapters.IssueCommentsAdapter;
import org.mian.gitnex.clients.PicassoService;
import org.mian.gitnex.clients.RetrofitClient; import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.fragments.SingleIssueBottomSheetFragment; import org.mian.gitnex.fragments.BottomSheetSingleIssueFragment;
import org.mian.gitnex.helpers.AlertDialogs; import org.mian.gitnex.helpers.AlertDialogs;
import org.mian.gitnex.helpers.Authorization; import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.helpers.LabelWidthCalculator;
import org.mian.gitnex.helpers.TimeHelper; import org.mian.gitnex.helpers.TimeHelper;
import org.mian.gitnex.helpers.UserMentions; import org.mian.gitnex.helpers.UserMentions;
import org.mian.gitnex.models.IssueComments; import org.mian.gitnex.models.IssueComments;
@ -67,7 +69,6 @@ import org.mian.gitnex.helpers.RoundedTransformation;
import org.mian.gitnex.util.TinyDB; import org.mian.gitnex.util.TinyDB;
import org.mian.gitnex.helpers.ClickListener; import org.mian.gitnex.helpers.ClickListener;
import org.mian.gitnex.viewmodels.IssueCommentsViewModel; import org.mian.gitnex.viewmodels.IssueCommentsViewModel;
import org.ocpsoft.prettytime.PrettyTime;
import java.text.DateFormat; import java.text.DateFormat;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Collection; import java.util.Collection;
@ -80,7 +81,7 @@ import java.util.Objects;
* Author M M Arif * Author M M Arif
*/ */
public class IssueDetailActivity extends AppCompatActivity { public class IssueDetailActivity extends BaseActivity {
public ImageView closeActivity; public ImageView closeActivity;
private IssueCommentsAdapter adapter; private IssueCommentsAdapter adapter;
@ -95,15 +96,20 @@ public class IssueDetailActivity extends AppCompatActivity {
private HorizontalScrollView assigneesScrollView; private HorizontalScrollView assigneesScrollView;
private ScrollView scrollViewComments; private ScrollView scrollViewComments;
private TextView issueModified; private TextView issueModified;
private ImageView createNewComment;
final Context ctx = this; final Context ctx = this;
private LinearLayout labelsLayout; private LinearLayout labelsLayout;
private LinearLayout assigneesLayout; private LinearLayout assigneesLayout;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected int getLayoutResourceId(){
return R.layout.activity_issue_detail;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_issue_detail);
final TinyDB tinyDb = new TinyDB(getApplicationContext()); final TinyDB tinyDb = new TinyDB(getApplicationContext());
@ -128,10 +134,13 @@ public class IssueDetailActivity extends AppCompatActivity {
assigneesScrollView = findViewById(R.id.assigneesScrollView); assigneesScrollView = findViewById(R.id.assigneesScrollView);
scrollViewComments = findViewById(R.id.scrollViewComments); scrollViewComments = findViewById(R.id.scrollViewComments);
issueModified = findViewById(R.id.issueModified); issueModified = findViewById(R.id.issueModified);
createNewComment = findViewById(R.id.addNewComment);
labelsLayout = findViewById(R.id.frameLabels); labelsLayout = findViewById(R.id.frameLabels);
assigneesLayout = findViewById(R.id.frameAssignees); assigneesLayout = findViewById(R.id.frameAssignees);
Toolbar toolbar = findViewById(R.id.toolbar); Toolbar toolbar = findViewById(R.id.toolbar);
TextView toolbarTitle = toolbar.findViewById(R.id.toolbar_title);
setSupportActionBar(toolbar); setSupportActionBar(toolbar);
Objects.requireNonNull(getSupportActionBar()).setTitle(repoName); Objects.requireNonNull(getSupportActionBar()).setTitle(repoName);
getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setDisplayHomeAsUpEnabled(true);
@ -141,23 +150,62 @@ public class IssueDetailActivity extends AppCompatActivity {
mRecyclerView.setNestedScrollingEnabled(false); mRecyclerView.setNestedScrollingEnabled(false);
mRecyclerView.setLayoutManager(new LinearLayoutManager(getApplicationContext())); mRecyclerView.setLayoutManager(new LinearLayoutManager(getApplicationContext()));
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(mRecyclerView.getContext(), DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(mRecyclerView.getContext(), DividerItemDecoration.VERTICAL);
DividerItemDecoration.VERTICAL);
mRecyclerView.addItemDecoration(dividerItemDecoration); mRecyclerView.addItemDecoration(dividerItemDecoration);
swipeRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { createNewComment.setOnClickListener(v -> startActivity(new Intent(ctx, ReplyToIssueActivity.class)));
@Override
public void onRefresh() { if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
new Handler().postDelayed(new Runnable() {
@Override scrollViewComments.setOnScrollChangeListener((v, scrollX, scrollY, oldScrollX, oldScrollY) -> {
public void run() {
swipeRefresh.setRefreshing(false); if ((scrollY - oldScrollY) > 0 && createNewComment.isShown()) {
IssueCommentsViewModel.loadIssueComments(instanceUrl, Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName, issueIndex); createNewComment.setVisibility(View.GONE);
} }
}, 500); else if ((scrollY - oldScrollY) < 0) {
createNewComment.setVisibility(View.VISIBLE);
} }
if (!scrollViewComments.canScrollVertically(1)) { // bottom
createNewComment.setVisibility(View.GONE);
}
if (!scrollViewComments.canScrollVertically(-1)) { // top
createNewComment.setVisibility(View.VISIBLE);
}
}); });
}
swipeRefresh.setOnRefreshListener(() -> new Handler().postDelayed(() -> {
swipeRefresh.setRefreshing(false);
IssueCommentsViewModel.loadIssueComments(instanceUrl, Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName, issueIndex, getApplicationContext());
}, 500));
Typeface myTypeface;
switch(tinyDb.getInt("customFontId", -1)) {
case 1:
myTypeface = Typeface.createFromAsset(Objects.requireNonNull(getApplicationContext()).getAssets(), "fonts/manroperegular.ttf");
break;
case 2:
myTypeface = Typeface.createFromAsset(Objects.requireNonNull(getApplicationContext()).getAssets(), "fonts/sourcecodeproregular.ttf");
break;
default:
myTypeface = Typeface.createFromAsset(Objects.requireNonNull(getApplicationContext()).getAssets(), "fonts/roboto.ttf");
break;
}
toolbarTitle.setTypeface(myTypeface);
toolbarTitle.setText(repoName);
getSingleIssue(instanceUrl, instanceToken, repoOwner, repoName, issueIndex, loginUid); getSingleIssue(instanceUrl, instanceToken, repoOwner, repoName, issueIndex, loginUid);
fetchDataAsync(instanceUrl, instanceToken, repoOwner, repoName, issueIndex, loginUid); fetchDataAsync(instanceUrl, instanceToken, repoOwner, repoName, issueIndex, loginUid);
@ -180,7 +228,7 @@ public class IssueDetailActivity extends AppCompatActivity {
finish(); finish();
return true; return true;
case R.id.genericMenu: case R.id.genericMenu:
SingleIssueBottomSheetFragment bottomSheet = new SingleIssueBottomSheetFragment(); BottomSheetSingleIssueFragment bottomSheet = new BottomSheetSingleIssueFragment();
bottomSheet.show(getSupportFragmentManager(), "singleIssueBottomSheet"); bottomSheet.show(getSupportFragmentManager(), "singleIssueBottomSheet");
return true; return true;
default: default:
@ -206,7 +254,7 @@ public class IssueDetailActivity extends AppCompatActivity {
scrollViewComments.post(new Runnable() { scrollViewComments.post(new Runnable() {
@Override @Override
public void run() { public void run() {
IssueCommentsViewModel.loadIssueComments(instanceUrl, Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName, issueIndex); IssueCommentsViewModel.loadIssueComments(instanceUrl, Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName, issueIndex, getApplicationContext());
new Handler().postDelayed(new Runnable() { new Handler().postDelayed(new Runnable() {
@Override @Override
@ -224,7 +272,7 @@ public class IssueDetailActivity extends AppCompatActivity {
scrollViewComments.post(new Runnable() { scrollViewComments.post(new Runnable() {
@Override @Override
public void run() { public void run() {
IssueCommentsViewModel.loadIssueComments(instanceUrl, Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName, issueIndex); IssueCommentsViewModel.loadIssueComments(instanceUrl, Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName, issueIndex, getApplicationContext());
tinyDb.putBoolean("commentEdited", false); tinyDb.putBoolean("commentEdited", false);
} }
}); });
@ -262,9 +310,9 @@ public class IssueDetailActivity extends AppCompatActivity {
private void fetchDataAsync(String instanceUrl, String instanceToken, String owner, String repo, int index, String loginUid) { private void fetchDataAsync(String instanceUrl, String instanceToken, String owner, String repo, int index, String loginUid) {
IssueCommentsViewModel issueCommentsModel = ViewModelProviders.of(this).get(IssueCommentsViewModel.class); IssueCommentsViewModel issueCommentsModel = new ViewModelProvider(this).get(IssueCommentsViewModel.class);
issueCommentsModel.getIssueCommentList(instanceUrl, Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), owner, repo, index).observe(this, new Observer<List<IssueComments>>() { issueCommentsModel.getIssueCommentList(instanceUrl, Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), owner, repo, index, getApplicationContext()).observe(this, new Observer<List<IssueComments>>() {
@Override @Override
public void onChanged(@Nullable List<IssueComments> issueCommentsMain) { public void onChanged(@Nullable List<IssueComments> issueCommentsMain) {
adapter = new IssueCommentsAdapter(getApplicationContext(), issueCommentsMain); adapter = new IssueCommentsAdapter(getApplicationContext(), issueCommentsMain);
@ -278,7 +326,7 @@ public class IssueDetailActivity extends AppCompatActivity {
final TinyDB tinyDb = new TinyDB(getApplicationContext()); final TinyDB tinyDb = new TinyDB(getApplicationContext());
Call<Issues> call = RetrofitClient Call<Issues> call = RetrofitClient
.getInstance(instanceUrl) .getInstance(instanceUrl, getApplicationContext())
.getApiInterface() .getApiInterface()
.getIssueByIndex(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName, issueIndex); .getIssueByIndex(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName, issueIndex);
@ -295,9 +343,7 @@ public class IssueDetailActivity extends AppCompatActivity {
final Markwon markwon = Markwon.builder(Objects.requireNonNull(getApplicationContext())) final Markwon markwon = Markwon.builder(Objects.requireNonNull(getApplicationContext()))
.usePlugin(CorePlugin.create()) .usePlugin(CorePlugin.create())
.usePlugin(ImagesPlugin.create(new ImagesPlugin.ImagesConfigure() { .usePlugin(ImagesPlugin.create(plugin -> {
@Override
public void configureImages(@NonNull ImagesPlugin plugin) {
plugin.addSchemeHandler(new SchemeHandler() { plugin.addSchemeHandler(new SchemeHandler() {
@NonNull @NonNull
@Override @Override
@ -320,19 +366,12 @@ public class IssueDetailActivity extends AppCompatActivity {
return Collections.singleton("drawable"); return Collections.singleton("drawable");
} }
}); });
plugin.placeholderProvider(new ImagesPlugin.PlaceholderProvider() { plugin.placeholderProvider(drawable -> null);
@Nullable
@Override
public Drawable providePlaceholder(@NonNull AsyncDrawable drawable) {
return null;
}
});
plugin.addMediaDecoder(GifMediaDecoder.create(false)); plugin.addMediaDecoder(GifMediaDecoder.create(false));
plugin.addMediaDecoder(SvgMediaDecoder.create(getApplicationContext().getResources())); plugin.addMediaDecoder(SvgMediaDecoder.create(getApplicationContext().getResources()));
plugin.addMediaDecoder(SvgMediaDecoder.create()); plugin.addMediaDecoder(SvgMediaDecoder.create());
plugin.defaultMediaDecoder(DefaultMediaDecoder.create(getApplicationContext().getResources())); plugin.defaultMediaDecoder(DefaultMediaDecoder.create(getApplicationContext().getResources()));
plugin.defaultMediaDecoder(DefaultMediaDecoder.create()); plugin.defaultMediaDecoder(DefaultMediaDecoder.create());
}
})) }))
.usePlugin(new AbstractMarkwonPlugin() { .usePlugin(new AbstractMarkwonPlugin() {
@ -357,8 +396,9 @@ public class IssueDetailActivity extends AppCompatActivity {
tinyDb.putString("issueState", singleIssue.getState()); tinyDb.putString("issueState", singleIssue.getState());
tinyDb.putString("issueTitle", singleIssue.getTitle()); tinyDb.putString("issueTitle", singleIssue.getTitle());
Picasso.get().load(singleIssue.getUser().getAvatar_url()).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(assigneeAvatar); PicassoService.getInstance(ctx).get().load(singleIssue.getUser().getAvatar_url()).placeholder(R.drawable.loader_animated).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(assigneeAvatar);
issueTitle.setText(getString(R.string.issueTitleWithId, singleIssue.getNumber(), singleIssue.getTitle())); String issueNumber_ = "<font color='" + getApplicationContext().getResources().getColor(R.color.lightGray) + "'>" + getApplicationContext().getResources().getString(R.string.hash) + singleIssue.getNumber() + "</font>";
issueTitle.setText(Html.fromHtml(issueNumber_ + " " + singleIssue.getTitle()));
String cleanIssueDescription = singleIssue.getBody().trim(); String cleanIssueDescription = singleIssue.getBody().trim();
Spanned bodyWithMD = markwon.toMarkdown(EmojiParser.parseToUnicode(cleanIssueDescription)); Spanned bodyWithMD = markwon.toMarkdown(EmojiParser.parseToUnicode(cleanIssueDescription));
markwon.setParsedMarkdown(issueDescription, UserMentions.UserMentionsFunc(getApplicationContext(), bodyWithMD, cleanIssueDescription)); markwon.setParsedMarkdown(issueDescription, UserMentions.UserMentionsFunc(getApplicationContext(), bodyWithMD, cleanIssueDescription));
@ -374,7 +414,7 @@ public class IssueDetailActivity extends AppCompatActivity {
ImageView assigneesView = new ImageView(getApplicationContext()); ImageView assigneesView = new ImageView(getApplicationContext());
Picasso.get().load(singleIssue.getAssignees().get(i).getAvatar_url()).transform(new RoundedTransformation(8, 0)).resize(100, 100).centerCrop().into(assigneesView); PicassoService.getInstance(ctx).get().load(singleIssue.getAssignees().get(i).getAvatar_url()).placeholder(R.drawable.loader_animated).transform(new RoundedTransformation(8, 0)).resize(100, 100).centerCrop().into(assigneesView);
assigneesLayout.addView(assigneesView); assigneesLayout.addView(assigneesView);
assigneesView.setLayoutParams(params1); assigneesView.setLayoutParams(params1);
@ -395,7 +435,7 @@ public class IssueDetailActivity extends AppCompatActivity {
if(singleIssue.getLabels() != null) { if(singleIssue.getLabels() != null) {
labelsScrollView.setVisibility(View.VISIBLE); labelsScrollView.setVisibility(View.VISIBLE);
int width = 33; int width = 25;
for (int i = 0; i < singleIssue.getLabels().size(); i++) { for (int i = 0; i < singleIssue.getLabels().size(); i++) {
String labelColor = singleIssue.getLabels().get(i).getColor(); String labelColor = singleIssue.getLabels().get(i).getColor();
@ -411,11 +451,11 @@ public class IssueDetailActivity extends AppCompatActivity {
.beginConfig() .beginConfig()
.useFont(Typeface.DEFAULT) .useFont(Typeface.DEFAULT)
.textColor(new ColorInverter().getContrastColor(color)) .textColor(new ColorInverter().getContrastColor(color))
.fontSize(36) .fontSize(30)
.width((width * labelName.length()) - ((width / 4) * labelName.length())) .width(LabelWidthCalculator.calculateLabelWidth(labelName, Typeface.DEFAULT, 30, 15))
.height(60) .height(50)
.endConfig() .endConfig()
.buildRoundRect(labelName, color, 8); .buildRoundRect(labelName, color, 10);
labelsView.setImageDrawable(drawable); labelsView.setImageDrawable(drawable);
labelsLayout.addView(labelsView); labelsLayout.addView(labelsView);
@ -474,29 +514,11 @@ public class IssueDetailActivity extends AppCompatActivity {
issueDescription.setLayoutParams(paramsDesc); issueDescription.setLayoutParams(paramsDesc);
} }
switch (timeFormat) { issueCreatedTime.setText(TimeHelper.formatTime(singleIssue.getCreated_at(), new Locale(locale), timeFormat, ctx));
case "pretty": {
PrettyTime prettyTime = new PrettyTime(new Locale(locale));
String createdTime = prettyTime.format(singleIssue.getCreated_at());
issueCreatedTime.setText(createdTime);
issueCreatedTime.setVisibility(View.VISIBLE); issueCreatedTime.setVisibility(View.VISIBLE);
issueCreatedTime.setOnClickListener(new ClickListener(TimeHelper.customDateFormatForToastDateFormat(singleIssue.getCreated_at()), getApplicationContext()));
break; if(timeFormat.equals("pretty")) {
} issueCreatedTime.setOnClickListener(new ClickListener(TimeHelper.customDateFormatForToastDateFormat(singleIssue.getCreated_at()), ctx));
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(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(createdTime);
issueCreatedTime.setVisibility(View.VISIBLE);
break;
}
} }
if(singleIssue.getMilestone() != null) { if(singleIssue.getMilestone() != null) {
@ -535,12 +557,7 @@ public class IssueDetailActivity extends AppCompatActivity {
} }
private void initCloseListener() { private void initCloseListener() {
View.OnClickListener onClickListener = new View.OnClickListener() { View.OnClickListener onClickListener = view -> finish();
@Override
public void onClick(View view) {
finish();
}
};
} }
} }

View File

@ -1,9 +1,8 @@
package org.mian.gitnex.activities; package org.mian.gitnex.activities;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent; import android.content.Intent;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.content.res.Resources; import android.content.res.Resources;
import android.graphics.drawable.GradientDrawable; import android.graphics.drawable.GradientDrawable;
import android.os.Bundle; import android.os.Bundle;
@ -15,21 +14,30 @@ import android.widget.ArrayAdapter;
import android.widget.Button; import android.widget.Button;
import android.widget.EditText; import android.widget.EditText;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.RadioGroup;
import android.widget.ScrollView;
import android.widget.Spinner; import android.widget.Spinner;
import android.widget.TextView; import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import com.tooltip.Tooltip; import com.tooltip.Tooltip;
import org.mian.gitnex.R;
import org.mian.gitnex.clients.RetrofitClient; import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.helpers.Toasty; import org.mian.gitnex.helpers.NetworkObserver;
import org.mian.gitnex.helpers.SnackBar;
import org.mian.gitnex.helpers.VersionCheck;
import org.mian.gitnex.models.GiteaVersion;
import org.mian.gitnex.models.UserInfo;
import org.mian.gitnex.models.UserTokens; import org.mian.gitnex.models.UserTokens;
import org.mian.gitnex.util.AppUtil; import org.mian.gitnex.util.AppUtil;
import org.mian.gitnex.R;
import org.mian.gitnex.util.TinyDB; import org.mian.gitnex.util.TinyDB;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.UUID;
import okhttp3.Credentials; import okhttp3.Credentials;
import okhttp3.Headers;
import retrofit2.Call; import retrofit2.Call;
import retrofit2.Callback; import retrofit2.Callback;
@ -37,31 +45,44 @@ import retrofit2.Callback;
* Author M M Arif * Author M M Arif
*/ */
public class LoginActivity extends AppCompatActivity implements View.OnClickListener { public class LoginActivity extends BaseActivity implements View.OnClickListener {
private Button login_button; private Button loginButton;
private EditText instance_url, login_uid, login_passwd, otpCode; private EditText instanceUrlET, loginUidET, loginPassword, otpCode, loginTokenCode;
private Spinner protocolSpinner; private Spinner protocolSpinner;
private TextView otpInfo;
private RadioGroup loginMethod;
final Context ctx = this;
private String device_id = "token";
private ScrollView layoutView;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected int getLayoutResourceId(){
return R.layout.activity_login;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
TinyDB tinyDb = new TinyDB(getApplicationContext()); TinyDB tinyDb = new TinyDB(getApplicationContext());
boolean connToInternet = AppUtil.haveNetworkConnection(getApplicationContext()); NetworkObserver networkMonitor = new NetworkObserver(this);
login_button = findViewById(R.id.login_button); loginButton = findViewById(R.id.login_button);
instance_url = findViewById(R.id.instance_url); instanceUrlET = findViewById(R.id.instance_url);
login_uid = findViewById(R.id.login_uid); loginUidET = findViewById(R.id.login_uid);
login_passwd = findViewById(R.id.login_passwd); loginPassword = findViewById(R.id.login_passwd);
otpCode = findViewById(R.id.otpCode); otpCode = findViewById(R.id.otpCode);
otpInfo = findViewById(R.id.otpInfo);
ImageView info_button = findViewById(R.id.info); ImageView info_button = findViewById(R.id.info);
final TextView viewTextGiteaVersion = findViewById(R.id.appVersion); final TextView viewTextAppVersion = findViewById(R.id.appVersion);
protocolSpinner = findViewById(R.id.httpsSpinner); protocolSpinner = findViewById(R.id.httpsSpinner);
loginMethod = findViewById(R.id.loginMethod);
loginTokenCode = findViewById(R.id.loginTokenCode);
layoutView = findViewById(R.id.loginForm);
viewTextGiteaVersion.setText(AppUtil.getAppVersion(getApplicationContext())); viewTextAppVersion.setText(AppUtil.getAppVersion(getApplicationContext()));
Resources res = getResources(); Resources res = getResources();
String[] allProtocols = res.getStringArray(R.array.protocolValues); String[] allProtocols = res.getStringArray(R.array.protocolValues);
@ -73,33 +94,88 @@ public class LoginActivity extends AppCompatActivity implements View.OnClickList
protocolSpinner.setAdapter(adapterProtocols); protocolSpinner.setAdapter(adapterProtocols);
protocolSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { protocolSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) { public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
String value = getResources().getStringArray(R.array.protocolValues)[pos]; String value = getResources().getStringArray(R.array.protocolValues)[pos];
if(value.toLowerCase().equals("http")) { if(value.toLowerCase().equals("http")) {
Toasty.info(getApplicationContext(), getResources().getString(R.string.protocolError)); SnackBar.warning(getApplicationContext(), layoutView,getResources().getString(R.string.protocolError));
} }
} }
public void onNothingSelected(AdapterView<?> parent) { public void onNothingSelected(AdapterView<?> parent) {
} }
}); });
info_button.setOnClickListener(infoListener); info_button.setOnClickListener(infoListener);
if(!connToInternet) { if(tinyDb.getString("loginType").equals("basic")) { // username/password
Toasty.info(getApplicationContext(), getResources().getString(R.string.checkNetConnection)); loginMethod.check(R.id.loginUsernamePassword);
return;
loginUidET.setVisibility(View.VISIBLE);
loginPassword.setVisibility(View.VISIBLE);
otpCode.setVisibility(View.VISIBLE);
otpInfo.setVisibility(View.VISIBLE);
loginTokenCode.setVisibility(View.GONE);
} }
else {
loginMethod.check(R.id.loginToken);
loginUidET.setVisibility(View.GONE);
loginPassword.setVisibility(View.GONE);
otpCode.setVisibility(View.GONE);
otpInfo.setVisibility(View.GONE);
loginTokenCode.setVisibility(View.VISIBLE);
}
loginMethod.setOnCheckedChangeListener((group, checkedId) -> {
if(checkedId == R.id.loginToken) {
loginUidET.setVisibility(View.GONE);
loginPassword.setVisibility(View.GONE);
otpCode.setVisibility(View.GONE);
otpInfo.setVisibility(View.GONE);
loginTokenCode.setVisibility(View.VISIBLE);
}
else {
loginUidET.setVisibility(View.VISIBLE);
loginPassword.setVisibility(View.VISIBLE);
otpCode.setVisibility(View.VISIBLE);
otpInfo.setVisibility(View.VISIBLE);
loginTokenCode.setVisibility(View.GONE);
}
});
networkMonitor.onInternetStateListener(isAvailable -> {
if(isAvailable) {
enableProcessButton();
SnackBar.success(getApplicationContext(), layoutView, getResources().getString(R.string.netConnectionIsBack));
}
else {
disableProcessButton();
SnackBar.error(getApplicationContext(), layoutView, getResources().getString(R.string.checkNetConnection));
}
});
//login_button.setOnClickListener(this); //login_button.setOnClickListener(this);
if(!tinyDb.getString("instanceUrlRaw").isEmpty()) { if(!tinyDb.getString("instanceUrlRaw").isEmpty()) {
instance_url.setText(tinyDb.getString("instanceUrlRaw")); instanceUrlET.setText(tinyDb.getString("instanceUrlRaw"));
} }
if(!tinyDb.getString("loginUid").isEmpty()) { if(!tinyDb.getString("loginUid").isEmpty()) {
login_uid.setText(tinyDb.getString("loginUid")); loginUidET.setText(tinyDb.getString("loginUid"));
} }
if(tinyDb.getBoolean("loggedInMode")) { if(tinyDb.getBoolean("loggedInMode")) {
@ -109,20 +185,23 @@ public class LoginActivity extends AppCompatActivity implements View.OnClickList
} }
login_button.setOnClickListener(loginListener); loginButton.setOnClickListener(loginListener);
if(!tinyDb.getString("uniqueAppId").isEmpty()) {
device_id = tinyDb.getString("uniqueAppId");
}
else {
device_id = UUID.randomUUID().toString();
tinyDb.putString("uniqueAppId", device_id);
}
} }
@Override @Override
public void onClick(View v) { public void onClick(View v) {
switch(v.getId()) { if (v.getId() == R.id.login_button) {
case R.id.login_button:
login(); login();
break;
default:
} }
} }
@ -131,15 +210,13 @@ public class LoginActivity extends AppCompatActivity implements View.OnClickList
public void onClick(View v) { public void onClick(View v) {
disableProcessButton(); disableProcessButton();
login_button.setText(R.string.processingText); loginButton.setText(R.string.processingText);
login(); login();
} }
}; };
private View.OnClickListener infoListener = new View.OnClickListener() { private View.OnClickListener infoListener = v -> new Tooltip.Builder(v)
public void onClick(View v) {
new Tooltip.Builder(v)
.setText(R.string.urlInfoTooltip) .setText(R.string.urlInfoTooltip)
.setTextColor(getResources().getColor(R.color.white)) .setTextColor(getResources().getColor(R.color.white))
.setBackgroundColor(getResources().getColor(R.color.tooltipBackground)) .setBackgroundColor(getResources().getColor(R.color.tooltipBackground))
@ -149,8 +226,6 @@ public class LoginActivity extends AppCompatActivity implements View.OnClickList
.setCornerRadius(R.dimen.tooltipCornor) .setCornerRadius(R.dimen.tooltipCornor)
.setGravity(Gravity.BOTTOM) .setGravity(Gravity.BOTTOM)
.show(); .show();
}
};
@SuppressLint("ResourceAsColor") @SuppressLint("ResourceAsColor")
private void login() { private void login() {
@ -159,11 +234,17 @@ public class LoginActivity extends AppCompatActivity implements View.OnClickList
AppUtil appUtil = new AppUtil(); AppUtil appUtil = new AppUtil();
boolean connToInternet = AppUtil.haveNetworkConnection(LoginActivity.this); boolean connToInternet = AppUtil.haveNetworkConnection(LoginActivity.this);
String instanceUrl = instance_url.getText().toString().trim(); String instanceUrl = instanceUrlET.getText().toString().trim();
String loginUid = login_uid.getText().toString(); String loginUid = loginUidET.getText().toString();
String loginPass = login_passwd.getText().toString(); String loginPass = loginPassword.getText().toString();
String protocol = protocolSpinner.getSelectedItem().toString(); String protocol = protocolSpinner.getSelectedItem().toString();
String loginOTP_ = otpCode.getText().toString().trim(); String loginOTP_ = otpCode.getText().toString().trim();
int loginMethodType = loginMethod.getCheckedRadioButtonId();
String loginToken_ = loginTokenCode.getText().toString().trim();
if(loginMethodType == R.id.loginUsernamePassword) {
tinyDb.putString("loginType", "basic");
if(instanceUrl.contains("@")) { if(instanceUrl.contains("@")) {
@ -201,7 +282,7 @@ public class LoginActivity extends AppCompatActivity implements View.OnClickList
} }
else { else {
instanceUrl = "http://" + instanceHost + "/api/v1/"; instanceUrl = "http://" + instanceHost + "/api/v1/";
instanceUrlWithProtocol = "https://" + instanceHost; instanceUrlWithProtocol = "http://" + instanceHost;
} }
tinyDb.putString("instanceUrlRaw", instanceHost); tinyDb.putString("instanceUrlRaw", instanceHost);
@ -211,27 +292,27 @@ public class LoginActivity extends AppCompatActivity implements View.OnClickList
if(connToInternet) { if(connToInternet) {
if(instance_url.getText().toString().equals("")) { if(instanceUrlET.getText().toString().equals("")) {
Toasty.info(getApplicationContext(), getString(R.string.emptyFieldURL)); SnackBar.warning(getApplicationContext(), layoutView, getResources().getString(R.string.emptyFieldURL));
enableProcessButton(); enableProcessButton();
login_button.setText(R.string.btnLogin); loginButton.setText(R.string.btnLogin);
return; return;
} }
if(loginUid.equals("")) { if(loginUid.equals("")) {
Toasty.info(getApplicationContext(), getString(R.string.emptyFieldUsername)); SnackBar.warning(getApplicationContext(), layoutView, getResources().getString(R.string.emptyFieldUsername));
enableProcessButton(); enableProcessButton();
login_button.setText(R.string.btnLogin); loginButton.setText(R.string.btnLogin);
return; return;
} }
if(login_passwd.getText().toString().equals("")) { if(loginPassword.getText().toString().equals("")) {
Toasty.info(getApplicationContext(), getString(R.string.emptyFieldPassword)); SnackBar.warning(getApplicationContext(), layoutView, getResources().getString(R.string.emptyFieldPassword));
enableProcessButton(); enableProcessButton();
login_button.setText(R.string.btnLogin); loginButton.setText(R.string.btnLogin);
return; return;
} }
@ -241,46 +322,289 @@ public class LoginActivity extends AppCompatActivity implements View.OnClickList
if(appUtil.checkIntegers(loginOTP_)) { if(appUtil.checkIntegers(loginOTP_)) {
loginOTP = Integer.valueOf(loginOTP_); loginOTP = Integer.parseInt(loginOTP_);
} }
else { else {
Toasty.info(getApplicationContext(), getString(R.string.loginOTPTypeError)); SnackBar.warning(getApplicationContext(), layoutView, getResources().getString(R.string.loginOTPTypeError));
enableProcessButton(); enableProcessButton();
login_button.setText(R.string.btnLogin); loginButton.setText(R.string.btnLogin);
return; return;
} }
} }
letTheUserIn(instanceUrl, loginUid, loginPass, loginOTP); versionCheck(instanceUrl, loginUid, loginPass, loginOTP, loginToken_, 1);
} }
else { else {
Toasty.info(getApplicationContext(), getString(R.string.checkNetConnection)); SnackBar.error(getApplicationContext(), layoutView, getResources().getString(R.string.checkNetConnection));
} }
}
else {
tinyDb.putString("loginType", "token");
String instanceHost;
if(AppUtil.httpCheck(instanceUrl)) {
URI uri = null;
try {
uri = new URI(instanceUrl);
} catch (URISyntaxException e) {
e.printStackTrace();
}
assert uri != null;
instanceHost = uri.getHost();
}
else {
instanceHost = instanceUrl;
}
String instanceUrlWithProtocol;
if(protocol.toLowerCase().equals("https")) {
instanceUrl = "https://" + instanceHost + "/api/v1/";
instanceUrlWithProtocol = "https://" + instanceHost;
}
else {
instanceUrl = "http://" + instanceHost + "/api/v1/";
instanceUrlWithProtocol = "http://" + instanceHost;
}
tinyDb.putString("instanceUrlRaw", instanceHost);
tinyDb.putString("instanceUrl", instanceUrl);
tinyDb.putString("instanceUrlWithProtocol", instanceUrlWithProtocol);
if(connToInternet) {
if (instanceUrlET.getText().toString().equals("")) {
SnackBar.warning(getApplicationContext(), layoutView, getResources().getString(R.string.emptyFieldURL));
enableProcessButton();
loginButton.setText(R.string.btnLogin);
return;
}
if (loginToken_.equals("")) {
SnackBar.warning(getApplicationContext(), layoutView, getResources().getString(R.string.loginTokenError));
enableProcessButton();
loginButton.setText(R.string.btnLogin);
return;
}
versionCheck(instanceUrl, loginUid, loginPass, 123, loginToken_, 2);
}
else {
SnackBar.error(getApplicationContext(), layoutView, getResources().getString(R.string.checkNetConnection));
}
}
}
private void versionCheck(final String instanceUrl, final String loginUid, final String loginPass, final int loginOTP, final String loginToken_, final int loginType) {
Call<GiteaVersion> callVersion;
if (!loginToken_.isEmpty()) {
callVersion = RetrofitClient
.getInstance(instanceUrl, getApplicationContext())
.getApiInterface()
.getGiteaVersionWithToken(loginToken_);
}
else {
final String credential = Credentials.basic(loginUid, loginPass, StandardCharsets.UTF_8);
if (loginOTP != 0) {
callVersion = RetrofitClient
.getInstance(instanceUrl, getApplicationContext())
.getApiInterface()
.getGiteaVersionWithOTP(credential,loginOTP);
}
else {
callVersion = RetrofitClient
.getInstance(instanceUrl, getApplicationContext())
.getApiInterface()
.getGiteaVersionWithBasic(credential);
}
}
callVersion.enqueue(new Callback<GiteaVersion>() {
@Override
public void onResponse(@NonNull final Call<GiteaVersion> callVersion, @NonNull retrofit2.Response<GiteaVersion> responseVersion) {
if (responseVersion.code() == 200) {
GiteaVersion version = responseVersion.body();
assert version != null;
VersionCheck vt = VersionCheck.check(getString(R.string.versionLow), getString(R.string.versionHigh), version.getVersion());
switch (vt) {
case UNSUPPORTED_NEW:
//SnackBar.warning(getApplicationContext(), layoutView, getResources().getString(R.string.versionUnsupportedNew));
case SUPPORTED_LATEST:
case SUPPORTED_OLD:
case DEVELOPMENT:
login(loginType, instanceUrl, loginUid, loginPass, loginOTP, loginToken_);
return;
case UNSUPPORTED_OLD:
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(ctx);
alertDialogBuilder
.setTitle(getString(R.string.versionAlertDialogHeader))
.setMessage(getResources().getString(R.string.versionUnsupportedOld, version.getVersion()))
.setCancelable(true)
.setIcon(R.drawable.ic_warning)
.setNegativeButton(getString(R.string.cancelButton), (dialog, which) -> {
dialog.dismiss();
enableProcessButton();
})
.setPositiveButton(getString(R.string.textContinue), (dialog, which) -> {
dialog.dismiss();
login(loginType, instanceUrl, loginUid, loginPass, loginOTP, loginToken_);
});
AlertDialog alertDialog = alertDialogBuilder.create();
alertDialog.show();
return;
default: // UNKNOWN
SnackBar.error(getApplicationContext(), layoutView, getResources().getString(R.string.versionUnknow));
enableProcessButton();
}
}
else if (responseVersion.code() == 403) {
login(loginType, instanceUrl, loginUid, loginPass, loginOTP, loginToken_);
}
}
private void login(int loginType, String instanceUrl, String loginUid, String loginPass, int loginOTP, String loginToken_) {
if (loginType == 1) {
letTheUserIn(instanceUrl, loginUid, loginPass, loginOTP);
}
else if (loginType == 2) { // token
letTheUserInViaToken(instanceUrl, loginToken_);
}
}
@Override
public void onFailure(@NonNull Call<GiteaVersion> callVersion, Throwable t) {
Log.e("onFailure-version", t.toString());
SnackBar.error(getApplicationContext(), layoutView, getResources().getString(R.string.errorOnLogin));
enableProcessButton();
loginButton.setText(R.string.btnLogin);
}
});
}
private void letTheUserInViaToken(String instanceUrl, final String loginToken_) {
final TinyDB tinyDb = new TinyDB(getApplicationContext());
Call<UserInfo> call = RetrofitClient
.getInstance(instanceUrl, getApplicationContext())
.getApiInterface()
.getUserInfo("token " + loginToken_);
call.enqueue(new Callback<UserInfo>() {
@Override
public void onResponse(@NonNull Call<UserInfo> call, @NonNull retrofit2.Response<UserInfo> response) {
UserInfo userDetails = response.body();
if (response.isSuccessful()) {
if (response.code() == 200) {
tinyDb.putBoolean("loggedInMode", true);
assert userDetails != null;
tinyDb.putString(userDetails.getLogin() + "-token", loginToken_);
tinyDb.putString("loginUid", userDetails.getLogin());
tinyDb.putString("userLogin", userDetails.getUsername());
enableProcessButton();
loginButton.setText(R.string.btnLogin);
startActivity(new Intent(LoginActivity.this, MainActivity.class));
finish();
}
}
else if(response.code() == 401) {
SnackBar.error(getApplicationContext(), layoutView, getResources().getString(R.string.unauthorizedApiError));
enableProcessButton();
loginButton.setText(R.string.btnLogin);
}
else {
SnackBar.error(getApplicationContext(), layoutView, getResources().getString(R.string.genericApiStatusError) + response.code());
enableProcessButton();
loginButton.setText(R.string.btnLogin);
}
}
@Override
public void onFailure(@NonNull Call<UserInfo> call, @NonNull Throwable t) {
Log.e("onFailure", t.toString());
SnackBar.error(getApplicationContext(), layoutView, getResources().getString(R.string.genericError));
enableProcessButton();
loginButton.setText(R.string.btnLogin);
}
});
} }
private void letTheUserIn(final String instanceUrl, final String loginUid, final String loginPass, final int loginOTP) { private void letTheUserIn(final String instanceUrl, final String loginUid, final String loginPass, final int loginOTP) {
final String credential = Credentials.basic(loginUid, loginPass); final String credential = Credentials.basic(loginUid, loginPass, StandardCharsets.UTF_8);
Call<List<UserTokens>> call; Call<List<UserTokens>> call;
if(loginOTP != 0) { if(loginOTP != 0) {
call = RetrofitClient call = RetrofitClient
.getInstance(instanceUrl) .getInstance(instanceUrl, getApplicationContext())
.getApiInterface() .getApiInterface()
.getUserTokensWithOTP(credential, loginOTP, loginUid); .getUserTokensWithOTP(credential, loginOTP, loginUid);
} }
else { else {
call = RetrofitClient call = RetrofitClient
.getInstance(instanceUrl) .getInstance(instanceUrl, getApplicationContext())
.getApiInterface() .getApiInterface()
.getUserTokens(credential, loginUid); .getUserTokens(credential, loginUid);
} }
call.enqueue(new Callback<List<UserTokens>>() { call.enqueue(new Callback<List<UserTokens>>() {
@ -290,7 +614,8 @@ public class LoginActivity extends AppCompatActivity implements View.OnClickList
List<UserTokens> userTokens = response.body(); List<UserTokens> userTokens = response.body();
final TinyDB tinyDb = new TinyDB(getApplicationContext()); final TinyDB tinyDb = new TinyDB(getApplicationContext());
Headers responseHeaders = response.headers(); final AppUtil appUtil = new AppUtil();
//Headers responseHeaders = response.headers();
if (response.isSuccessful()) { if (response.isSuccessful()) {
@ -300,6 +625,20 @@ public class LoginActivity extends AppCompatActivity implements View.OnClickList
assert userTokens != null; assert userTokens != null;
if (userTokens.size() > 0) { if (userTokens.size() > 0) {
if(userTokens.get(0).getToken_last_eight() != null) {
for (int i = 0; i < userTokens.size(); i++) {
if (userTokens.get(i).getToken_last_eight().equals(tinyDb.getString(loginUid + "-token-last-eight"))) {
setTokenFlag = true;
break;
}
//Log.i("Tokens: ", userTokens.get(i).getToken_last_eight());
}
}
else {
for (int i = 0; i < userTokens.size(); i++) { for (int i = 0; i < userTokens.size(); i++) {
if (userTokens.get(i).getSha1().equals(tinyDb.getString(loginUid + "-token"))) { if (userTokens.get(i).getSha1().equals(tinyDb.getString(loginUid + "-token"))) {
setTokenFlag = true; setTokenFlag = true;
@ -307,24 +646,31 @@ public class LoginActivity extends AppCompatActivity implements View.OnClickList
} }
//Log.i("Tokens: ", userTokens.get(i).getSha1()); //Log.i("Tokens: ", userTokens.get(i).getSha1());
} }
}
} }
if(tinyDb.getString(loginUid + "-token").isEmpty() || !setTokenFlag) { if(tinyDb.getString(loginUid + "-token").isEmpty() || !setTokenFlag) {
UserTokens createUserToken = new UserTokens("gitnex-app-token"); UserTokens createUserToken = new UserTokens("gitnex-app-" + device_id);
Call<UserTokens> callCreateToken; Call<UserTokens> callCreateToken;
if(loginOTP != 0) { if(loginOTP != 0) {
callCreateToken = RetrofitClient callCreateToken = RetrofitClient
.getInstance(instanceUrl) .getInstance(instanceUrl, getApplicationContext())
.getApiInterface() .getApiInterface()
.createNewTokenWithOTP(credential, loginOTP, loginUid, createUserToken); .createNewTokenWithOTP(credential, loginOTP, loginUid, createUserToken);
} }
else { else {
callCreateToken = RetrofitClient callCreateToken = RetrofitClient
.getInstance(instanceUrl) .getInstance(instanceUrl, getApplicationContext())
.getApiInterface() .getApiInterface()
.createNewToken(credential, loginUid, createUserToken); .createNewToken(credential, loginUid, createUserToken);
} }
callCreateToken.enqueue(new Callback<UserTokens>() { callCreateToken.enqueue(new Callback<UserTokens>() {
@ -342,10 +688,28 @@ public class LoginActivity extends AppCompatActivity implements View.OnClickList
if (!newToken.getSha1().equals("")) { if (!newToken.getSha1().equals("")) {
Call<UserInfo> call = RetrofitClient
.getInstance(instanceUrl, getApplicationContext())
.getApiInterface()
.getUserInfo("token " + newToken.getSha1());
call.enqueue(new Callback<UserInfo>() {
@Override
public void onResponse(@NonNull Call<UserInfo> call, @NonNull retrofit2.Response<UserInfo> response) {
UserInfo userDetails = response.body();
if (response.isSuccessful()) {
if (response.code() == 200) {
tinyDb.remove("loginPass"); tinyDb.remove("loginPass");
tinyDb.putBoolean("loggedInMode", true); tinyDb.putBoolean("loggedInMode", true);
assert userDetails != null;
tinyDb.putString("userLogin", userDetails.getUsername());
tinyDb.putString(loginUid + "-token", newToken.getSha1()); tinyDb.putString(loginUid + "-token", newToken.getSha1());
//Log.i("Tokens", "new:" + newToken.getSha1() + " old:" + tinyDb.getString(loginUid + "-token")); tinyDb.putString(loginUid + "-token-last-eight", appUtil.getLastCharactersOfWord(newToken.getSha1(), 8));
startActivity(new Intent(LoginActivity.this, MainActivity.class)); startActivity(new Intent(LoginActivity.this, MainActivity.class));
finish(); finish();
@ -353,21 +717,53 @@ public class LoginActivity extends AppCompatActivity implements View.OnClickList
} }
} }
else if(response.code() == 401) {
SnackBar.error(getApplicationContext(), layoutView, getResources().getString(R.string.unauthorizedApiError));
enableProcessButton();
loginButton.setText(R.string.btnLogin);
}
else {
SnackBar.error(getApplicationContext(), layoutView, getResources().getString(R.string.genericApiStatusError) + response.code());
enableProcessButton();
loginButton.setText(R.string.btnLogin);
}
}
@Override
public void onFailure(@NonNull Call<UserInfo> call, @NonNull Throwable t) {
Log.e("onFailure", t.toString());
SnackBar.error(getApplicationContext(), layoutView, getResources().getString(R.string.genericError));
enableProcessButton();
loginButton.setText(R.string.btnLogin);
}
});
}
}
} }
else if(responseCreate.code() == 500) { else if(responseCreate.code() == 500) {
String toastError = getResources().getString(R.string.genericApiStatusError) + String.valueOf(responseCreate.code()); SnackBar.error(getApplicationContext(), layoutView,getResources().getString(R.string.genericApiStatusError) + responseCreate.code());
Toasty.info(getApplicationContext(), toastError);
enableProcessButton(); enableProcessButton();
login_button.setText(R.string.btnLogin); loginButton.setText(R.string.btnLogin);
} }
} }
@Override @Override
public void onFailure(@NonNull Call<UserTokens> createUserToken, Throwable t) { public void onFailure(@NonNull Call<UserTokens> createUserToken, @NonNull Throwable t) {
Log.e("onFailure-token", t.toString());
} }
@ -375,7 +771,27 @@ public class LoginActivity extends AppCompatActivity implements View.OnClickList
} }
else { else {
//Log.i("Current Token", tinyDb.getString(loginUid + "-token")); String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
Call<UserInfo> callGetUsername = RetrofitClient
.getInstance(instanceUrl, getApplicationContext())
.getApiInterface()
.getUserInfo(instanceToken);
callGetUsername.enqueue(new Callback<UserInfo>() {
@Override
public void onResponse(@NonNull Call<UserInfo> call, @NonNull retrofit2.Response<UserInfo> response) {
UserInfo userDetails = response.body();
if (response.isSuccessful()) {
if (response.code() == 200) {
assert userDetails != null;
tinyDb.putString("userLogin", userDetails.getUsername());
tinyDb.putBoolean("loggedInMode", true); tinyDb.putBoolean("loggedInMode", true);
startActivity(new Intent(LoginActivity.this, MainActivity.class)); startActivity(new Intent(LoginActivity.this, MainActivity.class));
finish(); finish();
@ -383,24 +799,51 @@ public class LoginActivity extends AppCompatActivity implements View.OnClickList
} }
} }
else if(response.code() == 401) {
SnackBar.error(getApplicationContext(), layoutView, getResources().getString(R.string.unauthorizedApiError));
enableProcessButton();
loginButton.setText(R.string.btnLogin);
}
else {
SnackBar.error(getApplicationContext(), layoutView, getResources().getString(R.string.genericApiStatusError) + response.code());
enableProcessButton();
loginButton.setText(R.string.btnLogin);
}
}
@Override
public void onFailure(@NonNull Call<UserInfo> call, @NonNull Throwable t) {
Log.e("onFailure", t.toString());
SnackBar.error(getApplicationContext(), layoutView, getResources().getString(R.string.genericError));
enableProcessButton();
loginButton.setText(R.string.btnLogin);
}
});
}
}
} }
else if(response.code() == 500) { else if(response.code() == 500) {
String toastError = getResources().getString(R.string.genericApiStatusError) + String.valueOf(response.code()); SnackBar.error(getApplicationContext(), layoutView,getResources().getString(R.string.genericApiStatusError) + response.code());
Toasty.info(getApplicationContext(), toastError);
enableProcessButton(); enableProcessButton();
login_button.setText(R.string.btnLogin); loginButton.setText(R.string.btnLogin);
} }
else { else {
String toastError = getResources().getString(R.string.genericApiStatusError) + String.valueOf(response.code()); SnackBar.error(getApplicationContext(), layoutView,getResources().getString(R.string.genericApiStatusError) + response.code());
//Log.i("error message else4", String.valueOf(response.code()));
Toasty.info(getApplicationContext(), toastError);
enableProcessButton(); enableProcessButton();
login_button.setText(R.string.btnLogin); loginButton.setText(R.string.btnLogin);
} }
@ -408,10 +851,12 @@ public class LoginActivity extends AppCompatActivity implements View.OnClickList
@Override @Override
public void onFailure(@NonNull Call<List<UserTokens>> call, @NonNull Throwable t) { public void onFailure(@NonNull Call<List<UserTokens>> call, @NonNull Throwable t) {
Log.e("onFailure-login", t.toString()); Log.e("onFailure-login", t.toString());
Toasty.info(getApplicationContext(), getResources().getString(R.string.malformedJson)); SnackBar.error(getApplicationContext(), layoutView,getResources().getString(R.string.malformedJson));
enableProcessButton(); enableProcessButton();
login_button.setText(R.string.btnLogin); loginButton.setText(R.string.btnLogin);
} }
}); });
@ -419,21 +864,21 @@ public class LoginActivity extends AppCompatActivity implements View.OnClickList
private void disableProcessButton() { private void disableProcessButton() {
login_button.setEnabled(false); loginButton.setEnabled(false);
GradientDrawable shape = new GradientDrawable(); GradientDrawable shape = new GradientDrawable();
shape.setCornerRadius( 8 ); shape.setCornerRadius( 8 );
shape.setColor(getResources().getColor(R.color.hintColor)); shape.setColor(getResources().getColor(R.color.hintColor));
login_button.setBackground(shape); loginButton.setBackground(shape);
} }
private void enableProcessButton() { private void enableProcessButton() {
login_button.setEnabled(true); loginButton.setEnabled(true);
GradientDrawable shape = new GradientDrawable(); GradientDrawable shape = new GradientDrawable();
shape.setCornerRadius( 8 ); shape.setCornerRadius( 8 );
shape.setColor(getResources().getColor(R.color.btnBackground)); shape.setColor(getResources().getColor(R.color.btnBackground));
login_button.setBackground(shape); loginButton.setBackground(shape);
} }

View File

@ -1,14 +1,20 @@
package org.mian.gitnex.activities; package org.mian.gitnex.activities;
import android.app.Activity;
import android.content.ActivityNotFoundException; import android.content.ActivityNotFoundException;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import com.google.android.material.navigation.NavigationView; import com.google.android.material.navigation.NavigationView;
import androidx.appcompat.widget.Toolbar;
import androidx.core.view.GravityCompat; import androidx.core.view.GravityCompat;
import androidx.drawerlayout.widget.DrawerLayout; import androidx.drawerlayout.widget.DrawerLayout;
import androidx.appcompat.app.ActionBarDrawerToggle; import androidx.appcompat.app.ActionBarDrawerToggle;
import androidx.appcompat.app.AppCompatActivity; import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.Typeface;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.util.Log; import android.util.Log;
@ -17,19 +23,21 @@ import android.view.View;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import com.squareup.picasso.NetworkPolicy; import com.squareup.picasso.NetworkPolicy;
import com.squareup.picasso.Picasso;
import org.mian.gitnex.R; import org.mian.gitnex.R;
import org.mian.gitnex.clients.PicassoService;
import org.mian.gitnex.clients.RetrofitClient; import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.fragments.AboutFragment; import org.mian.gitnex.fragments.AboutFragment;
import org.mian.gitnex.fragments.ExploreRepositoriesFragment; import org.mian.gitnex.fragments.ExploreRepositoriesFragment;
import org.mian.gitnex.fragments.MyRepositoriesFragment; import org.mian.gitnex.fragments.MyRepositoriesFragment;
import org.mian.gitnex.fragments.NavSubMenuBottomSheetFragment; import org.mian.gitnex.fragments.BottomSheetNavSubMenuFragment;
import org.mian.gitnex.fragments.OrganizationsFragment; import org.mian.gitnex.fragments.OrganizationsFragment;
import org.mian.gitnex.fragments.SettingsFragment; import org.mian.gitnex.fragments.SettingsFragment;
import org.mian.gitnex.fragments.StarredRepositoriesFragment; import org.mian.gitnex.fragments.StarredRepositoriesFragment;
import org.mian.gitnex.helpers.AlertDialogs; import org.mian.gitnex.helpers.AlertDialogs;
import org.mian.gitnex.helpers.Authorization; import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.helpers.ChangeLog;
import org.mian.gitnex.helpers.Toasty; import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.models.GiteaVersion;
import org.mian.gitnex.models.UserInfo; import org.mian.gitnex.models.UserInfo;
import org.mian.gitnex.util.AppUtil; import org.mian.gitnex.util.AppUtil;
import org.mian.gitnex.helpers.RoundedTransformation; import org.mian.gitnex.helpers.RoundedTransformation;
@ -44,17 +52,25 @@ import retrofit2.Callback;
* Author M M Arif * Author M M Arif
*/ */
public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener { public class MainActivity extends BaseActivity implements NavigationView.OnNavigationItemSelectedListener {
private DrawerLayout drawer; private DrawerLayout drawer;
private TextView userFullName; private TextView userFullName;
private TextView userEmail; private TextView userEmail;
private ImageView userAvatar; private ImageView userAvatar;
private TextView toolbarTitle;
final Context ctx = this; final Context ctx = this;
private Typeface myTypeface;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected int getLayoutResourceId(){
return R.layout.activity_main;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final TinyDB tinyDb = new TinyDB(getApplicationContext()); final TinyDB tinyDb = new TinyDB(getApplicationContext());
tinyDb.putBoolean("noConnection", false); tinyDb.putBoolean("noConnection", false);
//userAvatar = findViewById(R.id.userAvatar); //userAvatar = findViewById(R.id.userAvatar);
@ -85,17 +101,57 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
boolean connToInternet = AppUtil.haveNetworkConnection(getApplicationContext()); boolean connToInternet = AppUtil.haveNetworkConnection(getApplicationContext());
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(!tinyDb.getBoolean("loggedInMode")) { if(!tinyDb.getBoolean("loggedInMode")) {
logout(); logout(this, ctx);
return; return;
} }
androidx.appcompat.widget.Toolbar toolbar = findViewById(R.id.toolbar); Toolbar toolbar = findViewById(R.id.toolbar);
toolbarTitle = toolbar.findViewById(R.id.toolbar_title);
switch(tinyDb.getInt("customFontId", -1)) {
case 0:
myTypeface = Typeface.createFromAsset(getAssets(), "fonts/roboto.ttf");
break;
case 2:
myTypeface = Typeface.createFromAsset(getAssets(), "fonts/sourcecodeproregular.ttf");
break;
default:
myTypeface = Typeface.createFromAsset(getAssets(), "fonts/manroperegular.ttf");
break;
}
toolbarTitle.setTypeface(myTypeface);
setSupportActionBar(toolbar); setSupportActionBar(toolbar);
FragmentManager fm = getSupportFragmentManager();
Fragment fragmentById = fm.findFragmentById(R.id.fragment_container);
if (fragmentById instanceof SettingsFragment) {
toolbarTitle.setText(getResources().getString(R.string.pageTitleSettings));
}
else if (fragmentById instanceof MyRepositoriesFragment) {
toolbarTitle.setText(getResources().getString(R.string.pageTitleMyRepos));
}
else if (fragmentById instanceof StarredRepositoriesFragment) {
toolbarTitle.setText(getResources().getString(R.string.pageTitleStarredRepos));
}
else if (fragmentById instanceof OrganizationsFragment) {
toolbarTitle.setText(getResources().getString(R.string.pageTitleOrganizations));
}
else if (fragmentById instanceof ExploreRepositoriesFragment) {
toolbarTitle.setText(getResources().getString(R.string.pageTitleExplore));
}
else if (fragmentById instanceof ProfileFragment) {
toolbarTitle.setText(getResources().getString(R.string.pageTitleProfile));
}
else if (fragmentById instanceof AboutFragment) {
toolbarTitle.setText(getResources().getString(R.string.pageTitleAbout));
}
drawer = findViewById(R.id.drawer_layout); drawer = findViewById(R.id.drawer_layout);
NavigationView navigationView = findViewById(R.id.nav_view); NavigationView navigationView = findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this); navigationView.setNavigationItemSelectedListener(this);
@ -104,14 +160,14 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
ImageView navSubMenu = hView.findViewById(R.id.navSubMenu); ImageView navSubMenu = hView.findViewById(R.id.navSubMenu);
navSubMenu.setOnClickListener(new View.OnClickListener() { navSubMenu.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) { public void onClick(View v) {
NavSubMenuBottomSheetFragment bottomSheet = new NavSubMenuBottomSheetFragment(); BottomSheetNavSubMenuFragment bottomSheet = new BottomSheetNavSubMenuFragment();
bottomSheet.show(getSupportFragmentManager(), "adminMenuBottomSheet"); bottomSheet.show(getSupportFragmentManager(), "adminMenuBottomSheet");
} }
}); });
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawer, toolbar, ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawer, toolbar,
R.string.navigation_drawer_open, R.string.navigation_drawer_close); R.string.navigation_drawer_open, R.string.navigation_drawer_close);
toggle.getDrawerArrowDrawable().setColor(getResources().getColor(R.color.white)); toggle.getDrawerArrowDrawable().setColor(getResources().getColor(R.color.darkGreen));
drawer.addDrawerListener(toggle); drawer.addDrawerListener(toggle);
drawer.addDrawerListener(new DrawerLayout.DrawerListener() { drawer.addDrawerListener(new DrawerLayout.DrawerListener() {
@ -124,15 +180,11 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
@Override @Override
public void onDrawerOpened(@NonNull View drawerView) { public void onDrawerOpened(@NonNull View drawerView) {
boolean connToInternet = AppUtil.haveNetworkConnection(getApplicationContext()); if(tinyDb.getBoolean("noConnection")) {
if(!connToInternet) {
if(!tinyDb.getBoolean("noConnection")) {
Toasty.info(getApplicationContext(), getResources().getString(R.string.checkNetConnection)); Toasty.info(getApplicationContext(), getResources().getString(R.string.checkNetConnection));
tinyDb.putBoolean("noConnection", false);
} }
tinyDb.putBoolean("noConnection", true);
String userEmailNav = tinyDb.getString("userEmail"); String userEmailNav = tinyDb.getString("userEmail");
String userFullNameNav = tinyDb.getString("userFullname"); String userFullNameNav = tinyDb.getString("userFullname");
String userAvatarNav = tinyDb.getString("userAvatar"); String userAvatarNav = tinyDb.getString("userAvatar");
@ -140,24 +192,27 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
userEmail = hView.findViewById(R.id.userEmail); userEmail = hView.findViewById(R.id.userEmail);
if (!userEmailNav.equals("")) { if (!userEmailNav.equals("")) {
userEmail.setText(userEmailNav); userEmail.setText(userEmailNav);
userEmail.setTypeface(myTypeface);
} }
userFullName = hView.findViewById(R.id.userFullname); userFullName = hView.findViewById(R.id.userFullname);
if (!userFullNameNav.equals("")) { if (!userFullNameNav.equals("")) {
userFullName.setText(userFullNameNav); userFullName.setText(userFullNameNav);
userFullName.setTypeface(myTypeface);
} }
userAvatar = hView.findViewById(R.id.userAvatar); userAvatar = hView.findViewById(R.id.userAvatar);
if (!userAvatarNav.equals("")) { if (!userAvatarNav.equals("")) {
Picasso.get().load(userAvatarNav).networkPolicy(NetworkPolicy.OFFLINE).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(userAvatar); PicassoService.getInstance(ctx).get().load(userAvatarNav).networkPolicy(NetworkPolicy.OFFLINE).placeholder(R.drawable.loader_animated).transform(new RoundedTransformation(8, 0)).resize(160, 160).centerCrop().into(userAvatar);
} }
} else { userAvatar.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
displayUserInfo(instanceUrl, instanceToken, loginUid); getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
tinyDb.putBoolean("noConnection", false); new ProfileFragment()).commit();
drawer.closeDrawers();
} }
});
} }
@ -176,31 +231,37 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
if(savedInstanceState == null) { if(savedInstanceState == null) {
if(tinyDb.getInt("homeScreenId") == 0) { if(tinyDb.getInt("homeScreenId") == 0) {
toolbarTitle.setText(getResources().getString(R.string.pageTitleMyRepos));
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
new MyRepositoriesFragment()).commit(); new MyRepositoriesFragment()).commit();
navigationView.setCheckedItem(R.id.nav_home); navigationView.setCheckedItem(R.id.nav_home);
} }
else if(tinyDb.getInt("homeScreenId") == 1) { else if(tinyDb.getInt("homeScreenId") == 1) {
toolbarTitle.setText(getResources().getString(R.string.pageTitleStarredRepos));
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
new StarredRepositoriesFragment()).commit(); new StarredRepositoriesFragment()).commit();
navigationView.setCheckedItem(R.id.nav_starred_repos); navigationView.setCheckedItem(R.id.nav_starred_repos);
} }
else if(tinyDb.getInt("homeScreenId") == 2) { else if(tinyDb.getInt("homeScreenId") == 2) {
toolbarTitle.setText(getResources().getString(R.string.pageTitleOrganizations));
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
new OrganizationsFragment()).commit(); new OrganizationsFragment()).commit();
navigationView.setCheckedItem(R.id.nav_organizations); navigationView.setCheckedItem(R.id.nav_organizations);
} }
else if(tinyDb.getInt("homeScreenId") == 3) { else if(tinyDb.getInt("homeScreenId") == 3) {
toolbarTitle.setText(getResources().getString(R.string.pageTitleRepositories));
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
new RepositoriesFragment()).commit(); new RepositoriesFragment()).commit();
navigationView.setCheckedItem(R.id.nav_repositories); navigationView.setCheckedItem(R.id.nav_repositories);
} }
else if(tinyDb.getInt("homeScreenId") == 4) { else if(tinyDb.getInt("homeScreenId") == 4) {
toolbarTitle.setText(getResources().getString(R.string.pageTitleProfile));
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
new ProfileFragment()).commit(); new ProfileFragment()).commit();
navigationView.setCheckedItem(R.id.nav_profile); navigationView.setCheckedItem(R.id.nav_profile);
} }
else { else {
toolbarTitle.setText(getResources().getString(R.string.pageTitleMyRepos));
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
new MyRepositoriesFragment()).commit(); new MyRepositoriesFragment()).commit();
navigationView.setCheckedItem(R.id.nav_home); navigationView.setCheckedItem(R.id.nav_home);
@ -218,10 +279,28 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
} else { } else {
displayUserInfo(instanceUrl, instanceToken, loginUid); displayUserInfo(instanceUrl, instanceToken, loginUid);
giteaVersion(instanceUrl);
tinyDb.putBoolean("noConnection", false); tinyDb.putBoolean("noConnection", false);
} }
// Changelog popup
int versionCode = 0;
try {
PackageInfo packageInfo = getApplicationContext().getPackageManager()
.getPackageInfo(getApplicationContext().getPackageName(), 0);
versionCode = packageInfo.versionCode;
}
catch (PackageManager.NameNotFoundException e) {
Log.e("changelogDialog", Objects.requireNonNull(e.getMessage()));
}
if (versionCode > tinyDb.getInt("versionCode")) {
tinyDb.putInt("versionCode", versionCode);
tinyDb.putBoolean("versionFlag", true);
ChangeLog changelogDialog = new ChangeLog(this);
changelogDialog.showDialog();
}
} }
public void setActionBarTitle (@NonNull String title) { public void setActionBarTitle (@NonNull String title) {
@ -245,30 +324,37 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
switch (menuItem.getItemId()) { switch (menuItem.getItemId()) {
case R.id.nav_home: case R.id.nav_home:
toolbarTitle.setText(getResources().getString(R.string.pageTitleMyRepos));
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
new MyRepositoriesFragment()).commit(); new MyRepositoriesFragment()).commit();
break; break;
case R.id.nav_organizations: case R.id.nav_organizations:
toolbarTitle.setText(getResources().getString(R.string.pageTitleOrganizations));
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
new OrganizationsFragment()).commit(); new OrganizationsFragment()).commit();
break; break;
case R.id.nav_profile: case R.id.nav_profile:
toolbarTitle.setText(getResources().getString(R.string.pageTitleProfile));
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
new ProfileFragment()).commit(); new ProfileFragment()).commit();
break; break;
case R.id.nav_repositories: case R.id.nav_repositories:
toolbarTitle.setText(getResources().getString(R.string.pageTitleRepositories));
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
new RepositoriesFragment()).commit(); new RepositoriesFragment()).commit();
break; break;
case R.id.nav_settings: case R.id.nav_settings:
toolbarTitle.setText(getResources().getString(R.string.pageTitleSettings));
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
new SettingsFragment()).commit(); new SettingsFragment()).commit();
break; break;
case R.id.nav_logout: case R.id.nav_logout:
logout(); logout(this, ctx);
overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out); overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
break; break;
case R.id.nav_about: case R.id.nav_about:
toolbarTitle.setText(getResources().getString(R.string.pageTitleAbout));
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
new AboutFragment()).commit(); new AboutFragment()).commit();
break; break;
@ -276,10 +362,12 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
rateThisApp(); rateThisApp();
break; break;
case R.id.nav_starred_repos: case R.id.nav_starred_repos:
toolbarTitle.setText(getResources().getString(R.string.pageTitleStarredRepos));
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
new StarredRepositoriesFragment()).commit(); new StarredRepositoriesFragment()).commit();
break; break;
case R.id.nav_explore: case R.id.nav_explore:
toolbarTitle.setText(getResources().getString(R.string.pageTitleExplore));
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
new ExploreRepositoriesFragment()).commit(); new ExploreRepositoriesFragment()).commit();
break; break;
@ -300,15 +388,53 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
} }
} }
public void logout() { public static void logout(Activity activity, Context ctx) {
TinyDB tinyDb = new TinyDB(getApplicationContext()); TinyDB tinyDb = new TinyDB(ctx.getApplicationContext());
tinyDb.putBoolean("loggedInMode", false); tinyDb.putBoolean("loggedInMode", false);
tinyDb.remove("basicAuthPassword"); tinyDb.remove("basicAuthPassword");
tinyDb.putBoolean("basicAuthFlag", false); tinyDb.putBoolean("basicAuthFlag", false);
//tinyDb.clear(); //tinyDb.clear();
finish(); activity.finish();
startActivity(new Intent(MainActivity.this, LoginActivity.class)); ctx.startActivity(new Intent(ctx, LoginActivity.class));
}
private void giteaVersion(final String instanceUrl) {
final TinyDB tinyDb = new TinyDB(getApplicationContext());
final String token = "token " + tinyDb.getString(tinyDb.getString("loginUid") + "-token");
Call<GiteaVersion> callVersion = RetrofitClient
.getInstance(instanceUrl, getApplicationContext())
.getApiInterface()
.getGiteaVersionWithToken(token);
callVersion.enqueue(new Callback<GiteaVersion>() {
@Override
public void onResponse(@NonNull final Call<GiteaVersion> callVersion, @NonNull retrofit2.Response<GiteaVersion> responseVersion) {
if (responseVersion.code() == 200) {
GiteaVersion version = responseVersion.body();
assert version != null;
tinyDb.putString("giteaVersion", version.getVersion());
}
}
@Override
public void onFailure(@NonNull Call<GiteaVersion> callVersion, @NonNull Throwable t) {
Log.e("onFailure-version", t.toString());
}
});
} }
@ -317,7 +443,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
final TinyDB tinyDb = new TinyDB(getApplicationContext()); final TinyDB tinyDb = new TinyDB(getApplicationContext());
Call<UserInfo> call = RetrofitClient Call<UserInfo> call = RetrofitClient
.getInstance(instanceUrl) .getInstance(instanceUrl, getApplicationContext())
.getApiInterface() .getApiInterface()
.getUserInfo(Authorization.returnAuthentication(getApplicationContext(), loginUid, token)); .getUserInfo(Authorization.returnAuthentication(getApplicationContext(), loginUid, token));
@ -345,7 +471,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
tinyDb.putString("userFullname", userDetails.getFullname()); tinyDb.putString("userFullname", userDetails.getFullname());
} }
else { else {
tinyDb.putString("userFullname", "..."); tinyDb.putString("userFullname", userDetails.getLogin());
} }
tinyDb.putString("userEmail", userDetails.getEmail()); tinyDb.putString("userEmail", userDetails.getEmail());
@ -360,7 +486,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
userAvatar = hView.findViewById(R.id.userAvatar); userAvatar = hView.findViewById(R.id.userAvatar);
if (!Objects.requireNonNull(userDetails).getAvatar().equals("")) { if (!Objects.requireNonNull(userDetails).getAvatar().equals("")) {
Picasso.get().load(userDetails.getAvatar()).transform(new RoundedTransformation(8, 0)).resize(160, 160).centerCrop().into(userAvatar); PicassoService.getInstance(ctx).get().load(userDetails.getAvatar()).placeholder(R.drawable.loader_animated).transform(new RoundedTransformation(8, 0)).resize(160, 160).centerCrop().into(userAvatar);
} else { } else {
userAvatar.setImageResource(R.mipmap.app_logo_round); userAvatar.setImageResource(R.mipmap.app_logo_round);
} }

View File

@ -0,0 +1,308 @@
package org.mian.gitnex.activities;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.drawable.GradientDrawable;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
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 android.widget.TextView;
import androidx.annotation.NonNull;
import com.hendraanggrian.appcompat.socialview.Mention;
import com.hendraanggrian.appcompat.widget.MentionArrayAdapter;
import com.hendraanggrian.appcompat.widget.SocialAutoCompleteTextView;
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.helpers.VersionCheck;
import org.mian.gitnex.models.Collaborators;
import org.mian.gitnex.models.MergePullRequest;
import org.mian.gitnex.models.MergePullRequestSpinner;
import org.mian.gitnex.util.AppUtil;
import org.mian.gitnex.util.TinyDB;
import java.util.ArrayList;
import java.util.List;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
/**
* Author M M Arif
*/
public class MergePullRequestActivity extends BaseActivity {
public ImageView closeActivity;
private View.OnClickListener onClickListener;
final Context ctx = this;
private SocialAutoCompleteTextView mergeDescription;
private EditText mergeTitle;
private Spinner mergeModeSpinner;
private ArrayAdapter<Mention> defaultMentionAdapter;
private Button mergeButton;
private String Do;
@Override
protected int getLayoutResourceId() {
return R.layout.activity_merge_pull_request;
}
@SuppressLint("SetTextI18n")
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
boolean connToInternet = AppUtil.haveNetworkConnection(getApplicationContext());
TinyDB tinyDb = new TinyDB(getApplicationContext());
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
mergeModeSpinner = findViewById(R.id.mergeSpinner);
mergeDescription = findViewById(R.id.mergeDescription);
mergeTitle = findViewById(R.id.mergeTitle);
mergeTitle.requestFocus();
assert imm != null;
imm.showSoftInput(mergeTitle, InputMethodManager.SHOW_IMPLICIT);
setMergeAdapter();
mergeModeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
MergePullRequestSpinner mergeId = (MergePullRequestSpinner) parent.getSelectedItem();
Do = mergeId.getId();
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
defaultMentionAdapter = new MentionArrayAdapter<>(this);
loadCollaboratorsList();
mergeDescription.setMentionAdapter(defaultMentionAdapter);
closeActivity = findViewById(R.id.close);
TextView toolbar_title = findViewById(R.id.toolbar_title);
if(!tinyDb.getString("issueTitle").isEmpty()) {
toolbar_title.setText(tinyDb.getString("issueTitle"));
mergeTitle.setText(tinyDb.getString("issueTitle") + " (#" + tinyDb.getString("issueNumber")+ ")");
}
initCloseListener();
closeActivity.setOnClickListener(onClickListener);
mergeButton = findViewById(R.id.mergeButton);
if(!connToInternet) {
disableProcessButton();
}
else {
mergeButton.setOnClickListener(mergePullRequest);
}
}
private void setMergeAdapter() {
TinyDB tinyDb = new TinyDB(getApplicationContext());
ArrayList<MergePullRequestSpinner> mergeList = new ArrayList<>();
mergeList.add(new MergePullRequestSpinner("merge", getResources().getString(R.string.mergeOptionMerge)));
mergeList.add(new MergePullRequestSpinner("rebase", getResources().getString(R.string.mergeOptionRebase)));
mergeList.add(new MergePullRequestSpinner("rebase-merge", getResources().getString(R.string.mergeOptionRebaseCommit)));
//squash merge works only on gitea v1.11.5 and higher due to a bug
if(VersionCheck.compareVersion("1.11.5", tinyDb.getString("giteaVersion")) < 1) {
mergeList.add(new MergePullRequestSpinner("squash", getResources().getString(R.string.mergeOptionSquash)));
}
ArrayAdapter<MergePullRequestSpinner> adapter = new ArrayAdapter<>(ctx, R.layout.spinner_item, mergeList);
adapter.setDropDownViewResource(R.layout.spinner_dropdown_item);
mergeModeSpinner.setAdapter(adapter);
}
public void loadCollaboratorsList() {
final 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];
Call<List<Collaborators>> call = RetrofitClient.getInstance(instanceUrl, getApplicationContext()).getApiInterface().getCollaborators(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName);
call.enqueue(new Callback<List<Collaborators>>() {
@Override
public void onResponse(@NonNull Call<List<Collaborators>> call, @NonNull Response<List<Collaborators>> response) {
if(response.isSuccessful()) {
assert response.body() != null;
String fullName = "";
for(int i = 0; i < response.body().size(); i++) {
if(!response.body().get(i).getFull_name().equals("")) {
fullName = response.body().get(i).getFull_name();
}
defaultMentionAdapter.add(new Mention(response.body().get(i).getUsername(), fullName, response.body().get(i).getAvatar_url()));
}
}
else {
Log.i("onResponse", String.valueOf(response.code()));
}
}
@Override
public void onFailure(@NonNull Call<List<Collaborators>> call, @NonNull Throwable t) {
Log.i("onFailure", t.toString());
}
});
}
private void initCloseListener() {
onClickListener = view -> finish();
}
private View.OnClickListener mergePullRequest = v -> processMergePullRequest();
private void processMergePullRequest() {
String mergePRDesc = mergeDescription.getText().toString();
String mergePRTitle = mergeTitle.getText().toString();
boolean connToInternet = AppUtil.haveNetworkConnection(getApplicationContext());
if(!connToInternet) {
Toasty.info(getApplicationContext(), getResources().getString(R.string.checkNetConnection));
return;
}
disableProcessButton();
mergeFunction(Do, mergePRDesc, mergePRTitle);
}
private void mergeFunction(String Do, String mergePRDT, String mergeTitle) {
final 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];
final int prIndex = Integer.parseInt(tinyDb.getString("issueNumber"));
MergePullRequest mergePR = new MergePullRequest(Do, mergePRDT, mergeTitle);
Call<ResponseBody> call = RetrofitClient.getInstance(instanceUrl, getApplicationContext()).getApiInterface().mergePullRequest(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName, prIndex, mergePR);
call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(@NonNull Call<ResponseBody> call, @NonNull retrofit2.Response<ResponseBody> response) {
if(response.code() == 200) {
Toasty.info(getApplicationContext(), getString(R.string.mergePRSuccessMsg));
tinyDb.putBoolean("prMerged", true);
tinyDb.putBoolean("resumePullRequests", true);
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.mergePR404ErrorMsg));
}
else {
enableProcessButton();
Toasty.info(getApplicationContext(), getString(R.string.genericError));
}
}
@Override
public void onFailure(@NonNull Call<ResponseBody> call, @NonNull Throwable t) {
Log.e("onFailure", t.toString());
enableProcessButton();
}
});
}
private void disableProcessButton() {
mergeButton.setEnabled(false);
GradientDrawable shape = new GradientDrawable();
shape.setCornerRadius(8);
shape.setColor(getResources().getColor(R.color.hintColor));
mergeButton.setBackground(shape);
}
private void enableProcessButton() {
mergeButton.setEnabled(true);
GradientDrawable shape = new GradientDrawable();
shape.setCornerRadius(8);
shape.setColor(getResources().getColor(R.color.btnBackground));
mergeButton.setBackground(shape);
}
}

View File

@ -2,20 +2,23 @@ package org.mian.gitnex.activities;
import com.google.android.material.tabs.TabLayout; import com.google.android.material.tabs.TabLayout;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar; import androidx.appcompat.widget.Toolbar;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter; import androidx.fragment.app.FragmentPagerAdapter;
import androidx.viewpager.widget.ViewPager; import androidx.viewpager.widget.ViewPager;
import android.content.Intent; import android.content.Intent;
import android.graphics.Typeface;
import android.os.Bundle; import android.os.Bundle;
import android.view.Menu; import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import org.mian.gitnex.R; import org.mian.gitnex.R;
import org.mian.gitnex.fragments.MembersByOrgFragment; import org.mian.gitnex.fragments.MembersByOrgFragment;
import org.mian.gitnex.fragments.OrgBottomSheetFragment; import org.mian.gitnex.fragments.BottomSheetOrganizationFragment;
import org.mian.gitnex.fragments.OrganizationInfoFragment; import org.mian.gitnex.fragments.OrganizationInfoFragment;
import org.mian.gitnex.fragments.RepositoriesByOrgFragment; import org.mian.gitnex.fragments.RepositoriesByOrgFragment;
import org.mian.gitnex.fragments.TeamsByOrgFragment; import org.mian.gitnex.fragments.TeamsByOrgFragment;
@ -26,28 +29,68 @@ import java.util.Objects;
* Author M M Arif * Author M M Arif
*/ */
public class OrgDetailActivity extends AppCompatActivity implements OrgBottomSheetFragment.BottomSheetListener { public class OrganizationDetailActivity extends BaseActivity implements BottomSheetOrganizationFragment.BottomSheetListener {
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected int getLayoutResourceId(){
return R.layout.activity_org_detail;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_org_detail);
TinyDB tinyDb = new TinyDB(getApplicationContext()); TinyDB tinyDb = new TinyDB(getApplicationContext());
String orgName = tinyDb.getString("orgName"); String orgName = tinyDb.getString("orgName");
Toolbar toolbar = findViewById(R.id.toolbar); Toolbar toolbar = findViewById(R.id.toolbar);
TextView toolbarTitle = toolbar.findViewById(R.id.toolbar_title);
setSupportActionBar(toolbar); setSupportActionBar(toolbar);
Objects.requireNonNull(getSupportActionBar()).setTitle(orgName); Objects.requireNonNull(getSupportActionBar()).setTitle(orgName);
getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setDisplayHomeAsUpEnabled(true);
OrgDetailActivity.SectionsPagerAdapter mSectionsPagerAdapter = new OrgDetailActivity.SectionsPagerAdapter(getSupportFragmentManager()); OrganizationDetailActivity.SectionsPagerAdapter mSectionsPagerAdapter = new OrganizationDetailActivity.SectionsPagerAdapter(getSupportFragmentManager());
ViewPager mViewPager = findViewById(R.id.container); ViewPager mViewPager = findViewById(R.id.container);
mViewPager.setAdapter(mSectionsPagerAdapter); mViewPager.setAdapter(mSectionsPagerAdapter);
TabLayout tabLayout = findViewById(R.id.tabs); TabLayout tabLayout = findViewById(R.id.tabs);
Typeface myTypeface;
switch(tinyDb.getInt("customFontId", -1)) {
case 0:
myTypeface = Typeface.createFromAsset(getApplicationContext().getAssets(), "fonts/roboto.ttf");
break;
case 2:
myTypeface = Typeface.createFromAsset(getApplicationContext().getAssets(), "fonts/sourcecodeproregular.ttf");
break;
default:
myTypeface = Typeface.createFromAsset(getApplicationContext().getAssets(), "fonts/manroperegular.ttf");
break;
}
toolbarTitle.setTypeface(myTypeface);
toolbarTitle.setText(orgName);
ViewGroup vg = (ViewGroup) tabLayout.getChildAt(0);
int tabsCount = vg.getChildCount();
for (int j = 0; j < tabsCount; j++) {
ViewGroup vgTab = (ViewGroup) vg.getChildAt(j);
int tabChildCount = vgTab.getChildCount();
for (int i = 0; i < tabChildCount; i++) {
View tabViewChild = vgTab.getChildAt(i);
if (tabViewChild instanceof TextView) {
((TextView) tabViewChild).setTypeface(myTypeface);
}
}
}
mViewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout)); mViewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
tabLayout.addOnTabSelectedListener(new TabLayout.ViewPagerOnTabSelectedListener(mViewPager)); tabLayout.addOnTabSelectedListener(new TabLayout.ViewPagerOnTabSelectedListener(mViewPager));
@ -71,7 +114,7 @@ public class OrgDetailActivity extends AppCompatActivity implements OrgBottomShe
finish(); finish();
return true; return true;
case R.id.repoMenu: case R.id.repoMenu:
OrgBottomSheetFragment bottomSheet = new OrgBottomSheetFragment(); BottomSheetOrganizationFragment bottomSheet = new BottomSheetOrganizationFragment();
bottomSheet.show(getSupportFragmentManager(), "orgBottomSheet"); bottomSheet.show(getSupportFragmentManager(), "orgBottomSheet");
return true; return true;
default: default:
@ -83,9 +126,15 @@ public class OrgDetailActivity extends AppCompatActivity implements OrgBottomShe
@Override @Override
public void onButtonClicked(String text) { public void onButtonClicked(String text) {
TinyDB tinyDb = new TinyDB(getApplicationContext());
switch (text) { switch (text) {
case "repository":
tinyDb.putBoolean("organizationAction", true);
startActivity(new Intent(OrganizationDetailActivity.this, CreateRepoActivity.class));
break;
case "team": case "team":
startActivity(new Intent(OrgDetailActivity.this, CreateTeamByOrgActivity.class)); startActivity(new Intent(OrganizationDetailActivity.this, CreateTeamByOrgActivity.class));
break; break;
} }
//Log.i("clicked", text); //Log.i("clicked", text);
@ -95,7 +144,7 @@ public class OrgDetailActivity extends AppCompatActivity implements OrgBottomShe
public class SectionsPagerAdapter extends FragmentPagerAdapter { public class SectionsPagerAdapter extends FragmentPagerAdapter {
SectionsPagerAdapter(FragmentManager fm) { SectionsPagerAdapter(FragmentManager fm) {
super(fm); super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
} }
@NonNull @NonNull
@ -104,7 +153,7 @@ public class OrgDetailActivity extends AppCompatActivity implements OrgBottomShe
TinyDB tinyDb = new TinyDB(getApplicationContext()); TinyDB tinyDb = new TinyDB(getApplicationContext());
String orgName; String orgName;
if(getIntent().getStringExtra("orgName") != null || !getIntent().getStringExtra("orgName").equals("")) { if(getIntent().getStringExtra("orgName") != null || !Objects.equals(getIntent().getStringExtra("orgName"), "")) {
orgName = getIntent().getStringExtra("orgName"); orgName = getIntent().getStringExtra("orgName");
} }
else { else {

View File

@ -1,7 +1,6 @@
package org.mian.gitnex.activities; package org.mian.gitnex.activities;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.Observer; import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider; import androidx.lifecycle.ViewModelProvider;
import android.os.Bundle; import android.os.Bundle;
@ -16,12 +15,13 @@ import org.mian.gitnex.models.UserInfo;
import org.mian.gitnex.util.TinyDB; import org.mian.gitnex.util.TinyDB;
import org.mian.gitnex.viewmodels.TeamMembersByOrgViewModel; import org.mian.gitnex.viewmodels.TeamMembersByOrgViewModel;
import java.util.List; import java.util.List;
import java.util.Objects;
/** /**
* Author M M Arif * Author M M Arif
*/ */
public class OrgTeamMembersActivity extends AppCompatActivity { public class OrganizationTeamMembersActivity extends BaseActivity {
private TextView noDataMembers; private TextView noDataMembers;
private View.OnClickListener onClickListener; private View.OnClickListener onClickListener;
@ -29,9 +29,13 @@ public class OrgTeamMembersActivity extends AppCompatActivity {
private GridView mGridView; private GridView mGridView;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected int getLayoutResourceId(){
return R.layout.activity_org_team_members;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_org_team_members);
TinyDB tinyDb = new TinyDB(getApplicationContext()); TinyDB tinyDb = new TinyDB(getApplicationContext());
final String instanceUrl = tinyDb.getString("instanceUrl"); final String instanceUrl = tinyDb.getString("instanceUrl");
@ -46,7 +50,7 @@ public class OrgTeamMembersActivity extends AppCompatActivity {
initCloseListener(); initCloseListener();
closeActivity.setOnClickListener(onClickListener); closeActivity.setOnClickListener(onClickListener);
if(getIntent().getStringExtra("teamTitle") != null && !getIntent().getStringExtra("teamTitle").equals("")) { if(getIntent().getStringExtra("teamTitle") != null && !Objects.requireNonNull(getIntent().getStringExtra("teamTitle")).equals("")) {
toolbarTitle.setText(getIntent().getStringExtra("teamTitle")); toolbarTitle.setText(getIntent().getStringExtra("teamTitle"));
} }
else { else {
@ -54,7 +58,7 @@ public class OrgTeamMembersActivity extends AppCompatActivity {
} }
String teamId; String teamId;
if(getIntent().getStringExtra("teamId") != null && !getIntent().getStringExtra("teamId").equals("")){ if(getIntent().getStringExtra("teamId") != null && !Objects.requireNonNull(getIntent().getStringExtra("teamId")).equals("")){
teamId = getIntent().getStringExtra("teamId"); teamId = getIntent().getStringExtra("teamId");
} }
else { else {
@ -64,6 +68,7 @@ public class OrgTeamMembersActivity extends AppCompatActivity {
getIntent().getStringExtra("teamId"); getIntent().getStringExtra("teamId");
//Log.i("teamId", getIntent().getStringExtra("teamId")); //Log.i("teamId", getIntent().getStringExtra("teamId"));
assert teamId != null;
fetchDataAsync(instanceUrl, Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), Integer.valueOf(teamId)); fetchDataAsync(instanceUrl, Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), Integer.valueOf(teamId));
} }
@ -72,7 +77,7 @@ public class OrgTeamMembersActivity extends AppCompatActivity {
TeamMembersByOrgViewModel teamMembersModel = new ViewModelProvider(this).get(TeamMembersByOrgViewModel.class); TeamMembersByOrgViewModel teamMembersModel = new ViewModelProvider(this).get(TeamMembersByOrgViewModel.class);
teamMembersModel.getMembersByOrgList(instanceUrl, instanceToken, teamId).observe(this, new Observer<List<UserInfo>>() { teamMembersModel.getMembersByOrgList(instanceUrl, instanceToken, teamId, getApplicationContext()).observe(this, new Observer<List<UserInfo>>() {
@Override @Override
public void onChanged(@Nullable List<UserInfo> teamMembersListMain) { public void onChanged(@Nullable List<UserInfo> teamMembersListMain) {
adapter = new TeamMembersByOrgAdapter(getApplicationContext(), teamMembersListMain); adapter = new TeamMembersByOrgAdapter(getApplicationContext(), teamMembersListMain);

View File

@ -1,7 +1,6 @@
package org.mian.gitnex.activities; package org.mian.gitnex.activities;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import retrofit2.Call; import retrofit2.Call;
import retrofit2.Callback; import retrofit2.Callback;
import android.content.Context; import android.content.Context;
@ -10,6 +9,7 @@ import android.os.Bundle;
import android.util.Log; import android.util.Log;
import android.util.Patterns; import android.util.Patterns;
import android.view.View; import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button; import android.widget.Button;
import android.widget.EditText; import android.widget.EditText;
import android.widget.ImageView; import android.widget.ImageView;
@ -30,7 +30,7 @@ import java.util.List;
* Author M M Arif * Author M M Arif
*/ */
public class ProfileEmailActivity extends AppCompatActivity { public class ProfileEmailActivity extends BaseActivity {
private View.OnClickListener onClickListener; private View.OnClickListener onClickListener;
private EditText userEmail; private EditText userEmail;
@ -38,16 +38,26 @@ public class ProfileEmailActivity extends AppCompatActivity {
private Button addEmailButton; private Button addEmailButton;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected int getLayoutResourceId(){
return R.layout.activity_profile_email;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_profile_email);
boolean connToInternet = AppUtil.haveNetworkConnection(getApplicationContext()); boolean connToInternet = AppUtil.haveNetworkConnection(getApplicationContext());
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
ImageView closeActivity = findViewById(R.id.close); ImageView closeActivity = findViewById(R.id.close);
userEmail = findViewById(R.id.userEmail); userEmail = findViewById(R.id.userEmail);
addEmailButton = findViewById(R.id.addEmailButton); addEmailButton = findViewById(R.id.addEmailButton);
userEmail.requestFocus();
assert imm != null;
imm.showSoftInput(userEmail, InputMethodManager.SHOW_IMPLICIT);
initCloseListener(); initCloseListener();
closeActivity.setOnClickListener(onClickListener); closeActivity.setOnClickListener(onClickListener);
@ -114,7 +124,7 @@ public class ProfileEmailActivity extends AppCompatActivity {
Call<JsonElement> call; Call<JsonElement> call;
call = RetrofitClient call = RetrofitClient
.getInstance(instanceUrl) .getInstance(instanceUrl, getApplicationContext())
.getApiInterface() .getApiInterface()
.addNewEmail(token, addEmailFunc); .addNewEmail(token, addEmailFunc);

View File

@ -1,7 +1,6 @@
package org.mian.gitnex.activities; package org.mian.gitnex.activities;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import retrofit2.Call; import retrofit2.Call;
import retrofit2.Callback; import retrofit2.Callback;
import retrofit2.Response; import retrofit2.Response;
@ -10,6 +9,7 @@ import android.graphics.drawable.GradientDrawable;
import android.os.Bundle; import android.os.Bundle;
import android.util.Log; import android.util.Log;
import android.view.View; import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.ArrayAdapter; import android.widget.ArrayAdapter;
import android.widget.Button; import android.widget.Button;
import android.widget.ImageView; import android.widget.ImageView;
@ -33,7 +33,7 @@ import java.util.List;
* Author M M Arif * Author M M Arif
*/ */
public class ReplyToIssueActivity extends AppCompatActivity { public class ReplyToIssueActivity extends BaseActivity {
public ImageView closeActivity; public ImageView closeActivity;
private View.OnClickListener onClickListener; private View.OnClickListener onClickListener;
@ -45,10 +45,16 @@ public class ReplyToIssueActivity extends AppCompatActivity {
private Button replyButton; private Button replyButton;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected int getLayoutResourceId(){
return R.layout.activity_reply_to_issue;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_reply_to_issue);
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
boolean connToInternet = AppUtil.haveNetworkConnection(getApplicationContext()); boolean connToInternet = AppUtil.haveNetworkConnection(getApplicationContext());
TinyDB tinyDb = new TinyDB(getApplicationContext()); TinyDB tinyDb = new TinyDB(getApplicationContext());
@ -64,6 +70,10 @@ public class ReplyToIssueActivity extends AppCompatActivity {
closeActivity = findViewById(R.id.close); closeActivity = findViewById(R.id.close);
TextView toolbar_title = findViewById(R.id.toolbar_title); TextView toolbar_title = findViewById(R.id.toolbar_title);
addComment.requestFocus();
assert imm != null;
imm.showSoftInput(addComment, InputMethodManager.SHOW_IMPLICIT);
if(!tinyDb.getString("issueTitle").isEmpty()) { if(!tinyDb.getString("issueTitle").isEmpty()) {
toolbar_title.setText(tinyDb.getString("issueTitle")); toolbar_title.setText(tinyDb.getString("issueTitle"));
} }
@ -83,6 +93,7 @@ public class ReplyToIssueActivity extends AppCompatActivity {
replyButton.setOnClickListener(new View.OnClickListener() { replyButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) { public void onClick(View v) {
disableProcessButton();
IssueActions.editIssueComment(ctx, Integer.valueOf(commentId), addComment.getText().toString()); IssueActions.editIssueComment(ctx, Integer.valueOf(commentId), addComment.getText().toString());
} }
@ -117,7 +128,7 @@ public class ReplyToIssueActivity extends AppCompatActivity {
final String repoName = parts[1]; final String repoName = parts[1];
Call<List<Collaborators>> call = RetrofitClient Call<List<Collaborators>> call = RetrofitClient
.getInstance(instanceUrl) .getInstance(instanceUrl, getApplicationContext())
.getApiInterface() .getApiInterface()
.getCollaborators(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName); .getCollaborators(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName);
@ -211,7 +222,7 @@ public class ReplyToIssueActivity extends AppCompatActivity {
Issues issueComment = new Issues(newReplyDT); Issues issueComment = new Issues(newReplyDT);
Call<Issues> call = RetrofitClient Call<Issues> call = RetrofitClient
.getInstance(instanceUrl) .getInstance(instanceUrl, getApplicationContext())
.getApiInterface() .getApiInterface()
.replyCommentToIssue(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName, issueIndex, issueComment); .replyCommentToIssue(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName, issueIndex, issueComment);
@ -225,6 +236,7 @@ public class ReplyToIssueActivity extends AppCompatActivity {
Toasty.info(getApplicationContext(), getString(R.string.commentSuccess)); Toasty.info(getApplicationContext(), getString(R.string.commentSuccess));
tinyDb.putBoolean("commentPosted", true); tinyDb.putBoolean("commentPosted", true);
tinyDb.putBoolean("resumeIssues", true); tinyDb.putBoolean("resumeIssues", true);
tinyDb.putBoolean("resumePullRequests", true);
finish(); finish();
} }

View File

@ -3,7 +3,6 @@ package org.mian.gitnex.activities;
import com.google.android.material.tabs.TabLayout; import com.google.android.material.tabs.TabLayout;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar; import androidx.appcompat.widget.Toolbar;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentManager;
@ -14,6 +13,7 @@ import retrofit2.Callback;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.content.Intent; import android.content.Intent;
import android.content.res.ColorStateList; import android.content.res.ColorStateList;
import android.graphics.Typeface;
import android.os.Bundle; import android.os.Bundle;
import android.util.Log; import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
@ -21,20 +21,22 @@ import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView; import android.widget.TextView;
import org.mian.gitnex.R; import org.mian.gitnex.R;
import org.mian.gitnex.clients.RetrofitClient; import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.fragments.BottomSheetRepoFragment;
import org.mian.gitnex.fragments.BranchesFragment; import org.mian.gitnex.fragments.BranchesFragment;
import org.mian.gitnex.fragments.ClosedIssuesFragment;
import org.mian.gitnex.fragments.CollaboratorsFragment; import org.mian.gitnex.fragments.CollaboratorsFragment;
import org.mian.gitnex.fragments.FilesFragment; import org.mian.gitnex.fragments.FilesFragment;
import org.mian.gitnex.fragments.IssuesFragment; import org.mian.gitnex.fragments.IssuesMainFragment;
import org.mian.gitnex.fragments.LabelsFragment; import org.mian.gitnex.fragments.LabelsFragment;
import org.mian.gitnex.fragments.MilestonesFragment; import org.mian.gitnex.fragments.MilestonesFragment;
import org.mian.gitnex.fragments.PullRequestsFragment;
import org.mian.gitnex.fragments.ReleasesFragment; import org.mian.gitnex.fragments.ReleasesFragment;
import org.mian.gitnex.fragments.RepoBottomSheetFragment;
import org.mian.gitnex.fragments.RepoInfoFragment; import org.mian.gitnex.fragments.RepoInfoFragment;
import org.mian.gitnex.helpers.Authorization; import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.helpers.VersionCheck;
import org.mian.gitnex.models.UserRepositories; import org.mian.gitnex.models.UserRepositories;
import org.mian.gitnex.models.WatchRepository; import org.mian.gitnex.models.WatchRepository;
import org.mian.gitnex.util.AppUtil; import org.mian.gitnex.util.AppUtil;
@ -46,14 +48,20 @@ import android.net.Uri;
* Author M M Arif * Author M M Arif
*/ */
public class RepoDetailActivity extends AppCompatActivity implements RepoBottomSheetFragment.BottomSheetListener { public class RepoDetailActivity extends BaseActivity implements BottomSheetRepoFragment.BottomSheetListener {
private TextView textViewBadge; private TextView textViewBadgeIssue;
private TextView textViewBadgePull;
private TextView textViewBadgeRelease;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected int getLayoutResourceId(){
return R.layout.activity_repo_detail;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_repo_detail);
TinyDB tinyDb = new TinyDB(getApplicationContext()); TinyDB tinyDb = new TinyDB(getApplicationContext());
String repoFullName = tinyDb.getString("repoFullName"); String repoFullName = tinyDb.getString("repoFullName");
@ -69,6 +77,8 @@ public class RepoDetailActivity extends AppCompatActivity implements RepoBottomS
AppUtil.setAppLocale(getResources(), appLocale); AppUtil.setAppLocale(getResources(), appLocale);
Toolbar toolbar = findViewById(R.id.toolbar); Toolbar toolbar = findViewById(R.id.toolbar);
TextView toolbarTitle = toolbar.findViewById(R.id.toolbar_title);
setSupportActionBar(toolbar); setSupportActionBar(toolbar);
Objects.requireNonNull(getSupportActionBar()).setTitle(repoName1); Objects.requireNonNull(getSupportActionBar()).setTitle(repoName1);
getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setDisplayHomeAsUpEnabled(true);
@ -80,28 +90,103 @@ public class RepoDetailActivity extends AppCompatActivity implements RepoBottomS
TabLayout tabLayout = findViewById(R.id.tabs); TabLayout tabLayout = findViewById(R.id.tabs);
Typeface myTypeface;
switch(tinyDb.getInt("customFontId", -1)) {
case 0:
myTypeface = Typeface.createFromAsset(getApplicationContext().getAssets(), "fonts/roboto.ttf");
break;
case 2:
myTypeface = Typeface.createFromAsset(getApplicationContext().getAssets(), "fonts/sourcecodeproregular.ttf");
break;
default:
myTypeface = Typeface.createFromAsset(getApplicationContext().getAssets(), "fonts/manroperegular.ttf");
break;
}
toolbarTitle.setTypeface(myTypeface);
toolbarTitle.setText(repoName1);
ViewGroup vg = (ViewGroup) tabLayout.getChildAt(0);
int tabsCount = vg.getChildCount();
for (int j = 0; j < tabsCount; j++) {
ViewGroup vgTab = (ViewGroup) vg.getChildAt(j);
int tabChildCount = vgTab.getChildCount();
for (int i = 0; i < tabChildCount; i++) {
View tabViewChild = vgTab.getChildAt(i);
if (tabViewChild instanceof TextView) {
((TextView) tabViewChild).setTypeface(myTypeface);
}
}
}
// only show Collaborators if you have permission to
final View collaboratorTab = vg.getChildAt(8);
if (tinyDb.getBoolean("isRepoAdmin")) {
collaboratorTab.setVisibility(View.VISIBLE);
}
else {
collaboratorTab.setVisibility(View.GONE);
}
mViewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout)); mViewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
tabLayout.addOnTabSelectedListener(new TabLayout.ViewPagerOnTabSelectedListener(mViewPager)); tabLayout.addOnTabSelectedListener(new TabLayout.ViewPagerOnTabSelectedListener(mViewPager));
if(tinyDb.getBoolean("enableCounterIssueBadge")) { if(tinyDb.getBoolean("enableCounterBadges")) {
@SuppressLint("InflateParams") View tabHeader2 = LayoutInflater.from(this).inflate(R.layout.badge_issue, null);
textViewBadgeIssue = tabHeader2.findViewById(R.id.counterBadgeIssue);
@SuppressLint("InflateParams") View tabHeader4 = LayoutInflater.from(this).inflate(R.layout.badge_pull, null);
textViewBadgePull = tabHeader4.findViewById(R.id.counterBadgePull);
@SuppressLint("InflateParams") View tabHeader6 = LayoutInflater.from(this).inflate(R.layout.badge_release, null);
textViewBadgeRelease = tabHeader6.findViewById(R.id.counterBadgeRelease);
textViewBadgeIssue.setVisibility(View.GONE);
textViewBadgePull.setVisibility(View.GONE);
textViewBadgeRelease.setVisibility(View.GONE);
@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); getRepoInfo(instanceUrl, Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName1);
}
Objects.requireNonNull(tabLayout.getTabAt(2)).setCustomView(tabHeader);
TabLayout.Tab tabOpenIssues = tabLayout.getTabAt(2);
ColorStateList textColor = tabLayout.getTabTextColors(); ColorStateList textColor = tabLayout.getTabTextColors();
assert tabOpenIssues != null;
TextView openIssueTabView = Objects.requireNonNull(tabOpenIssues.getCustomView()).findViewById(R.id.counterBadgeText);
openIssueTabView.setTextColor(textColor);
// issue count
if (textViewBadgeIssue.getText() != "") {
TabLayout.Tab tabOpenIssues = tabLayout.getTabAt(2);
Objects.requireNonNull(tabLayout.getTabAt(2)).setCustomView(tabHeader2);
assert tabOpenIssues != null;
TextView openIssueTabView = Objects.requireNonNull(tabOpenIssues.getCustomView()).findViewById(R.id.counterBadgeIssueText);
openIssueTabView.setTextColor(textColor);
}
// pull count
if (textViewBadgePull.getText() != "") { // only show if API returned a number
Objects.requireNonNull(tabLayout.getTabAt(4)).setCustomView(tabHeader4);
TabLayout.Tab tabOpenPulls = tabLayout.getTabAt(4);
assert tabOpenPulls != null;
TextView openPullTabView = Objects.requireNonNull(tabOpenPulls.getCustomView()).findViewById(R.id.counterBadgePullText);
openPullTabView.setTextColor(textColor);
}
// release count
if (VersionCheck.compareVersion("1.11.5", tinyDb.getString("giteaVersion")) < 1) {
if(textViewBadgeRelease.getText() != "") { // only show if API returned a number
Objects.requireNonNull(tabLayout.getTabAt(5)).setCustomView(tabHeader6);
TabLayout.Tab tabOpenRelease = tabLayout.getTabAt(5);
assert tabOpenRelease != null;
TextView openReleaseTabView = Objects.requireNonNull(tabOpenRelease.getCustomView()).findViewById(R.id.counterBadgeReleaseText);
openReleaseTabView.setTextColor(textColor);
}
}
} }
checkRepositoryStarStatus(instanceUrl, Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName1); checkRepositoryStarStatus(instanceUrl, Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName1);
checkRepositoryWatchStatus(instanceUrl, Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName1); checkRepositoryWatchStatus(instanceUrl, Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName1);
} }
@Override @Override
@ -120,13 +205,16 @@ public class RepoDetailActivity extends AppCompatActivity implements RepoBottomS
if(tinyDb.getBoolean("enableCounterIssueBadge")) { if(tinyDb.getBoolean("enableCounterIssueBadge")) {
getRepoInfo(instanceUrl, Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName); getRepoInfo(instanceUrl, Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName);
} }
} }
@Override @Override
public boolean onCreateOptionsMenu(Menu menu) { public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater(); MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.repo_dotted_menu, menu); inflater.inflate(R.menu.repo_dotted_menu, menu);
return true; return true;
} }
@Override @Override
@ -139,7 +227,7 @@ public class RepoDetailActivity extends AppCompatActivity implements RepoBottomS
finish(); finish();
return true; return true;
case R.id.repoMenu: case R.id.repoMenu:
RepoBottomSheetFragment bottomSheet = new RepoBottomSheetFragment(); BottomSheetRepoFragment bottomSheet = new BottomSheetRepoFragment();
bottomSheet.show(getSupportFragmentManager(), "repoBottomSheet"); bottomSheet.show(getSupportFragmentManager(), "repoBottomSheet");
return true; return true;
default: default:
@ -151,6 +239,14 @@ public class RepoDetailActivity extends AppCompatActivity implements RepoBottomS
@Override @Override
public void onButtonClicked(String text) { public void onButtonClicked(String text) {
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);
switch (text) { switch (text) {
case "label": case "label":
startActivity(new Intent(RepoDetailActivity.this, CreateLabelActivity.class)); startActivity(new Intent(RepoDetailActivity.this, CreateLabelActivity.class));
@ -159,7 +255,7 @@ public class RepoDetailActivity extends AppCompatActivity implements RepoBottomS
startActivity(new Intent(RepoDetailActivity.this, CreateIssueActivity.class)); startActivity(new Intent(RepoDetailActivity.this, CreateIssueActivity.class));
break; break;
case "newMilestone": case "newMilestone":
startActivity(new Intent(RepoDetailActivity.this, NewMilestoneActivity.class)); startActivity(new Intent(RepoDetailActivity.this, CreateMilestoneActivity.class));
break; break;
case "addCollaborator": case "addCollaborator":
startActivity(new Intent(RepoDetailActivity.this, AddCollaboratorToRepositoryActivity.class)); startActivity(new Intent(RepoDetailActivity.this, AddCollaboratorToRepositoryActivity.class));
@ -168,18 +264,18 @@ public class RepoDetailActivity extends AppCompatActivity implements RepoBottomS
startActivity(new Intent(RepoDetailActivity.this, CreateReleaseActivity.class)); startActivity(new Intent(RepoDetailActivity.this, CreateReleaseActivity.class));
break; break;
case "openWebRepo": 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); Intent i = new Intent(Intent.ACTION_VIEW, url);
startActivity(i); startActivity(i);
break; break;
case "shareRepo":
Intent sharingIntent = new Intent(android.content.Intent.ACTION_SEND);
sharingIntent.setType("text/plain");
sharingIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, url);
sharingIntent.putExtra(android.content.Intent.EXTRA_TEXT, url);
startActivity(Intent.createChooser(sharingIntent, url.toString()));
break;
case "newFile": case "newFile":
startActivity(new Intent(RepoDetailActivity.this, NewFileActivity.class)); startActivity(new Intent(RepoDetailActivity.this, CreateFileActivity.class));
break; break;
} }
@ -203,27 +299,28 @@ public class RepoDetailActivity extends AppCompatActivity implements RepoBottomS
Fragment fragment = null; Fragment fragment = null;
switch (position) { switch (position) {
case 0: // information case 0: // files
return RepoInfoFragment.newInstance(repoOwner, repoName);
case 1: // files
return FilesFragment.newInstance(repoOwner, repoName); return FilesFragment.newInstance(repoOwner, repoName);
case 1: // information
return RepoInfoFragment.newInstance(repoOwner, repoName);
case 2: // issues case 2: // issues
fragment = new IssuesFragment(); fragment = new IssuesMainFragment();
break; break;
case 3: // closed issues case 3: // branches
fragment = new ClosedIssuesFragment();
break;
case 4: // milestones
return MilestonesFragment.newInstance(repoOwner, repoName);
case 5: // labels
return LabelsFragment.newInstance(repoOwner, repoName);
case 6: // branches
return BranchesFragment.newInstance(repoOwner, repoName); return BranchesFragment.newInstance(repoOwner, repoName);
case 7: // releases case 4: // pull requests
fragment = new PullRequestsFragment();
break;
case 5: // releases
return ReleasesFragment.newInstance(repoOwner, repoName); return ReleasesFragment.newInstance(repoOwner, repoName);
case 6: // milestones
return MilestonesFragment.newInstance(repoOwner, repoName);
case 7: // labels
return LabelsFragment.newInstance(repoOwner, repoName);
case 8: // collaborators case 8: // collaborators
return CollaboratorsFragment.newInstance(repoOwner, repoName); return CollaboratorsFragment.newInstance(repoOwner, repoName);
} }
assert fragment != null;
return fragment; return fragment;
} }
@ -236,8 +333,10 @@ public class RepoDetailActivity extends AppCompatActivity implements RepoBottomS
private void getRepoInfo(String instanceUrl, String token, final String owner, String repo) { private void getRepoInfo(String instanceUrl, String token, final String owner, String repo) {
TinyDB tinyDb = new TinyDB(getApplicationContext());
Call<UserRepositories> call = RetrofitClient Call<UserRepositories> call = RetrofitClient
.getInstance(instanceUrl) .getInstance(instanceUrl, getApplicationContext())
.getApiInterface() .getApiInterface()
.getUserRepository(token, owner, repo); .getUserRepository(token, owner, repo);
@ -252,8 +351,24 @@ public class RepoDetailActivity extends AppCompatActivity implements RepoBottomS
if (response.code() == 200) { if (response.code() == 200) {
if(tinyDb.getBoolean("enableCounterBadges")) {
assert repoInfo != null; assert repoInfo != null;
textViewBadge.setText(repoInfo.getOpen_issues_count());
if(repoInfo.getOpen_issues_count() != null) {
textViewBadgeIssue.setVisibility(View.VISIBLE);
textViewBadgeIssue.setText(repoInfo.getOpen_issues_count());
}
if(repoInfo.getOpen_pull_count() != null) {
textViewBadgePull.setVisibility(View.VISIBLE);
textViewBadgePull.setText(repoInfo.getOpen_pull_count());
}
if(repoInfo.getRelease_count() != null) {
textViewBadgeRelease.setVisibility(View.VISIBLE);
textViewBadgeRelease.setText(repoInfo.getRelease_count());
}
}
} }
@ -268,6 +383,7 @@ public class RepoDetailActivity extends AppCompatActivity implements RepoBottomS
public void onFailure(@NonNull Call<UserRepositories> call, @NonNull Throwable t) { public void onFailure(@NonNull Call<UserRepositories> call, @NonNull Throwable t) {
Log.e("onFailure", t.toString()); Log.e("onFailure", t.toString());
} }
}); });
} }
@ -277,7 +393,7 @@ public class RepoDetailActivity extends AppCompatActivity implements RepoBottomS
Call<JsonElement> call; Call<JsonElement> call;
call = RetrofitClient call = RetrofitClient
.getInstance(instanceUrl) .getInstance(instanceUrl, getApplicationContext())
.getApiInterface() .getApiInterface()
.checkRepoStarStatus(instanceToken, owner, repo); .checkRepoStarStatus(instanceToken, owner, repo);
@ -304,7 +420,7 @@ public class RepoDetailActivity extends AppCompatActivity implements RepoBottomS
Call<WatchRepository> call; Call<WatchRepository> call;
call = RetrofitClient call = RetrofitClient
.getInstance(instanceUrl) .getInstance(instanceUrl, getApplicationContext())
.getApiInterface() .getApiInterface()
.checkRepoWatchStatus(instanceToken, owner, repo); .checkRepoWatchStatus(instanceToken, owner, repo);

View File

@ -2,7 +2,6 @@ package org.mian.gitnex.activities;
import android.os.Bundle; import android.os.Bundle;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.Observer; import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider; import androidx.lifecycle.ViewModelProvider;
import android.view.View; import android.view.View;
@ -22,7 +21,7 @@ import java.util.List;
* Author M M Arif * Author M M Arif
*/ */
public class RepoStargazersActivity extends AppCompatActivity { public class RepoStargazersActivity extends BaseActivity {
private TextView noDataStargazers; private TextView noDataStargazers;
private View.OnClickListener onClickListener; private View.OnClickListener onClickListener;
@ -31,9 +30,13 @@ public class RepoStargazersActivity extends AppCompatActivity {
private ProgressBar mProgressBar; private ProgressBar mProgressBar;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected int getLayoutResourceId(){
return R.layout.activity_repo_stargazers;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_repo_stargazers);
TinyDB tinyDb = new TinyDB(getApplicationContext()); TinyDB tinyDb = new TinyDB(getApplicationContext());
final String instanceUrl = tinyDb.getString("instanceUrl"); final String instanceUrl = tinyDb.getString("instanceUrl");
@ -64,7 +67,7 @@ public class RepoStargazersActivity extends AppCompatActivity {
RepoStargazersViewModel repoStargazersModel = new ViewModelProvider(this).get(RepoStargazersViewModel.class); RepoStargazersViewModel repoStargazersModel = new ViewModelProvider(this).get(RepoStargazersViewModel.class);
repoStargazersModel.getRepoStargazers(instanceUrl, instanceToken, repoOwner, repoName).observe(this, new Observer<List<UserInfo>>() { repoStargazersModel.getRepoStargazers(instanceUrl, instanceToken, repoOwner, repoName, getApplicationContext()).observe(this, new Observer<List<UserInfo>>() {
@Override @Override
public void onChanged(@Nullable List<UserInfo> stargazersListMain) { public void onChanged(@Nullable List<UserInfo> stargazersListMain) {
adapter = new RepoStargazersAdapter(getApplicationContext(), stargazersListMain); adapter = new RepoStargazersAdapter(getApplicationContext(), stargazersListMain);

View File

@ -2,7 +2,6 @@ package org.mian.gitnex.activities;
import android.os.Bundle; import android.os.Bundle;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.Observer; import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider; import androidx.lifecycle.ViewModelProvider;
import android.view.View; import android.view.View;
@ -22,7 +21,7 @@ import java.util.List;
* Author M M Arif * Author M M Arif
*/ */
public class RepoWatchersActivity extends AppCompatActivity { public class RepoWatchersActivity extends BaseActivity {
private TextView noDataWatchers; private TextView noDataWatchers;
private View.OnClickListener onClickListener; private View.OnClickListener onClickListener;
@ -31,9 +30,13 @@ public class RepoWatchersActivity extends AppCompatActivity {
private ProgressBar mProgressBar; private ProgressBar mProgressBar;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected int getLayoutResourceId(){
return R.layout.activity_repo_watchers;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_repo_watchers);
TinyDB tinyDb = new TinyDB(getApplicationContext()); TinyDB tinyDb = new TinyDB(getApplicationContext());
final String instanceUrl = tinyDb.getString("instanceUrl"); final String instanceUrl = tinyDb.getString("instanceUrl");
@ -64,7 +67,7 @@ public class RepoWatchersActivity extends AppCompatActivity {
RepoWatchersViewModel repoWatchersModel = new ViewModelProvider(this).get(RepoWatchersViewModel.class); RepoWatchersViewModel repoWatchersModel = new ViewModelProvider(this).get(RepoWatchersViewModel.class);
repoWatchersModel.getRepoWatchers(instanceUrl, instanceToken, repoOwner, repoName).observe(this, new Observer<List<UserInfo>>() { repoWatchersModel.getRepoWatchers(instanceUrl, instanceToken, repoOwner, repoName, getApplicationContext()).observe(this, new Observer<List<UserInfo>>() {
@Override @Override
public void onChanged(@Nullable List<UserInfo> watchersListMain) { public void onChanged(@Nullable List<UserInfo> watchersListMain) {
adapter = new RepoWatchersAdapter(getApplicationContext(), watchersListMain); adapter = new RepoWatchersAdapter(getApplicationContext(), watchersListMain);

View File

@ -1,33 +1,57 @@
package org.mian.gitnex.activities; package org.mian.gitnex.activities;
import androidx.appcompat.app.AppCompatActivity; import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.content.res.Resources;
import android.os.Bundle; import android.os.Bundle;
import android.text.method.LinkMovementMethod;
import android.view.View; import android.view.View;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView;
import org.mian.gitnex.R; import org.mian.gitnex.R;
import org.mian.gitnex.adapters.SponsorsAdapter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/** /**
* Author M M Arif * Author M M Arif
*/ */
public class SponsorsActivity extends AppCompatActivity { public class SponsorsActivity extends BaseActivity {
private View.OnClickListener onClickListener; private View.OnClickListener onClickListener;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected int getLayoutResourceId(){
return R.layout.activity_sponsors;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sponsors);
ImageView closeActivity = findViewById(R.id.close); ImageView closeActivity = findViewById(R.id.close);
TextView liberaPaySponsorsThomas = findViewById(R.id.liberaPaySponsorsThomas);
liberaPaySponsorsThomas.setMovementMethod(LinkMovementMethod.getInstance());
initCloseListener(); initCloseListener();
closeActivity.setOnClickListener(onClickListener); closeActivity.setOnClickListener(onClickListener);
Resources res = getResources();
CharSequence[] sponsorsInfo = res.getTextArray(R.array.sponsorsInfo);
List<CharSequence> sponsorsList = new ArrayList<>(Arrays.asList(sponsorsInfo));
RecyclerView mRecyclerView = findViewById(R.id.recyclerView);
mRecyclerView.setHasFixedSize(true);
mRecyclerView.setLayoutManager(new LinearLayoutManager(getApplicationContext()));
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(mRecyclerView.getContext(),
DividerItemDecoration.VERTICAL);
mRecyclerView.addItemDecoration(dividerItemDecoration);
SponsorsAdapter adapter = new SponsorsAdapter(sponsorsList);
mRecyclerView.setAdapter(adapter);
} }
private void initCloseListener() { private void initCloseListener() {

View File

@ -11,8 +11,8 @@ import android.widget.TextView;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import com.amulyakhare.textdrawable.TextDrawable; import com.amulyakhare.textdrawable.TextDrawable;
import com.squareup.picasso.Picasso;
import org.mian.gitnex.R; import org.mian.gitnex.R;
import org.mian.gitnex.clients.PicassoService;
import org.mian.gitnex.helpers.RoundedTransformation; import org.mian.gitnex.helpers.RoundedTransformation;
import org.mian.gitnex.models.UserInfo; import org.mian.gitnex.models.UserInfo;
import java.util.ArrayList; import java.util.ArrayList;
@ -57,7 +57,7 @@ public class AdminGetUsersAdapter extends RecyclerView.Adapter<AdminGetUsersAdap
@NonNull @NonNull
@Override @Override
public AdminGetUsersAdapter.UsersViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { public AdminGetUsersAdapter.UsersViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.admin_users_list, parent, false); View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_admin_users, parent, false);
return new AdminGetUsersAdapter.UsersViewHolder(v); return new AdminGetUsersAdapter.UsersViewHolder(v);
} }
@ -98,7 +98,7 @@ public class AdminGetUsersAdapter extends RecyclerView.Adapter<AdminGetUsersAdap
holder.userRole.setVisibility(View.GONE); holder.userRole.setVisibility(View.GONE);
} }
Picasso.get().load(currentItem.getAvatar()).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(holder.userAvatar); PicassoService.getInstance(mCtx).get().load(currentItem.getAvatar()).placeholder(R.drawable.loader_animated).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(holder.userAvatar);
} }
@Override @Override

View File

@ -1,16 +1,17 @@
package org.mian.gitnex.adapters; package org.mian.gitnex.adapters;
import android.content.Context; import android.content.Context;
import android.text.Html; import android.content.Intent;
import android.text.method.LinkMovementMethod;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.TextView; import android.widget.TextView;
import org.mian.gitnex.R; import org.mian.gitnex.R;
import org.mian.gitnex.activities.CommitsActivity;
import org.mian.gitnex.models.Branches; import org.mian.gitnex.models.Branches;
import org.mian.gitnex.util.TinyDB; import org.mian.gitnex.util.TinyDB;
import java.util.List; import java.util.List;
import java.util.Objects;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
@ -27,14 +28,23 @@ public class BranchesAdapter extends RecyclerView.Adapter<BranchesAdapter.Branch
private TextView branchNameTv; private TextView branchNameTv;
private TextView branchCommitAuthor; private TextView branchCommitAuthor;
private TextView branchCommitHash;
private BranchesViewHolder(View itemView) { private BranchesViewHolder(View itemView) {
super(itemView); super(itemView);
branchNameTv = itemView.findViewById(R.id.branchName); branchNameTv = itemView.findViewById(R.id.branchName);
branchCommitAuthor = itemView.findViewById(R.id.branchCommitAuthor); branchCommitAuthor = itemView.findViewById(R.id.branchCommitAuthor);
branchCommitHash = itemView.findViewById(R.id.branchCommitHash); TextView branchCommitHash = itemView.findViewById(R.id.branchCommitHash);
branchCommitHash.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Intent intent = new Intent(v.getContext(), CommitsActivity.class);
intent.putExtra("branchName", String.valueOf(branchNameTv.getText()));
Objects.requireNonNull(v.getContext()).startActivity(intent);
}
});
} }
} }
@ -47,7 +57,7 @@ public class BranchesAdapter extends RecyclerView.Adapter<BranchesAdapter.Branch
@NonNull @NonNull
@Override @Override
public BranchesAdapter.BranchesViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { public BranchesAdapter.BranchesViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.branches_list, parent, false); View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_branches, parent, false);
return new BranchesAdapter.BranchesViewHolder(v); return new BranchesAdapter.BranchesViewHolder(v);
} }
@ -67,10 +77,6 @@ public class BranchesAdapter extends RecyclerView.Adapter<BranchesAdapter.Branch
holder.branchCommitAuthor.setText(mCtx.getResources().getString(R.string.commitAuthor, currentItem.getCommit().getAuthor().getUsername())); holder.branchCommitAuthor.setText(mCtx.getResources().getString(R.string.commitAuthor, currentItem.getCommit().getAuthor().getUsername()));
} }
holder.branchCommitHash.setText(
Html.fromHtml("<a href='" + currentItem.getCommit().getUrl() + "'>" + mCtx.getResources().getString(R.string.commitLinkBranchesTab) + "</a> "));
holder.branchCommitHash.setMovementMethod(LinkMovementMethod.getInstance());
} }
@Override @Override

View File

@ -1,289 +0,0 @@
package org.mian.gitnex.adapters;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
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 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.models.Issues;
import org.mian.gitnex.util.TinyDB;
import org.ocpsoft.prettytime.PrettyTime;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
/**
* Author M M Arif
*/
public class ClosedIssuesAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> implements Filterable {
private Context context;
private final int TYPE_LOAD = 0;
private List<Issues> issuesList;
private List<Issues> issuesListFull;
private ClosedIssuesAdapter.OnLoadMoreListener loadMoreListener;
private boolean isLoading = false, isMoreDataAvailable = true;
public ClosedIssuesAdapter(Context context, List<Issues> issuesListMain) {
this.context = context;
this.issuesList = issuesListMain;
issuesListFull = new ArrayList<>(issuesList);
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(context);
if(viewType == TYPE_LOAD){
return new ClosedIssuesAdapter.IssuesHolder(inflater.inflate(R.layout.repo_detail_issues_list, parent,false));
}
else {
return new ClosedIssuesAdapter.LoadHolder(inflater.inflate(R.layout.row_load,parent,false));
}
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
if(position >= getItemCount()-1 && isMoreDataAvailable && !isLoading && loadMoreListener!=null) {
isLoading = true;
loadMoreListener.onLoadMore();
}
if(getItemViewType(position) == TYPE_LOAD) {
((ClosedIssuesAdapter.IssuesHolder)holder).bindData(issuesList.get(position));
}
}
@Override
public int getItemViewType(int position) {
if(issuesList.get(position).getTitle() != null) {
return TYPE_LOAD;
}
else {
return 1;
}
}
@Override
public int getItemCount() {
return issuesList.size();
}
class IssuesHolder extends RecyclerView.ViewHolder {
private TextView issueNumber;
private ImageView issueAssigneeAvatar;
private TextView issueTitle;
private TextView issueCreatedTime;
private TextView issueCommentsCount;
private ImageView issueType;
IssuesHolder(View itemView) {
super(itemView);
issueNumber = itemView.findViewById(R.id.issueNumber);
issueAssigneeAvatar = itemView.findViewById(R.id.assigneeAvatar);
issueTitle = itemView.findViewById(R.id.issueTitle);
issueCommentsCount = itemView.findViewById(R.id.issueCommentsCount);
LinearLayout frameCommentsCount = itemView.findViewById(R.id.frameCommentsCount);
issueCreatedTime = itemView.findViewById(R.id.issueCreatedTime);
issueType = itemView.findViewById(R.id.issueType);
issueTitle.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Context context = v.getContext();
//Log.i("issueNumber", issueNumber.getText().toString());
Intent intent = new Intent(context, IssueDetailActivity.class);
intent.putExtra("issueNumber", issueNumber.getText());
TinyDB tinyDb = new TinyDB(context);
tinyDb.putString("issueNumber", issueNumber.getText().toString());
context.startActivity(intent);
}
});
frameCommentsCount.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Context context = v.getContext();
//Log.i("issueNumber", issueNumber.getText().toString());
Intent intent = new Intent(context, IssueDetailActivity.class);
intent.putExtra("issueNumber", issueNumber.getText());
TinyDB tinyDb = new TinyDB(context);
tinyDb.putString("issueNumber", issueNumber.getText().toString());
context.startActivity(intent);
}
});
}
@SuppressLint("SetTextI18n")
void bindData(Issues issuesModel){
final TinyDB tinyDb = new TinyDB(context);
final String locale = tinyDb.getString("locale");
final String timeFormat = tinyDb.getString("dateFormat");
if (!issuesModel.getUser().getFull_name().equals("")) {
issueAssigneeAvatar.setOnClickListener(new ClickListener(context.getResources().getString(R.string.issueCreator) + issuesModel.getUser().getFull_name(), context));
} else {
issueAssigneeAvatar.setOnClickListener(new ClickListener(context.getResources().getString(R.string.issueCreator) + issuesModel.getUser().getLogin(), context));
}
if (issuesModel.getUser().getAvatar_url() != null) {
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(8, 0)).resize(120, 120).centerCrop().into(issueAssigneeAvatar);
}
if (issuesModel.getPull_request() == null) {
issueType.setImageResource(R.drawable.ic_issues);
issueType.setOnClickListener(new ClickListener(context.getResources().getString(R.string.issueTypeIssue), context));
} else {
issueType.setImageResource(R.drawable.ic_merge);
issueType.setOnClickListener(new ClickListener(context.getResources().getString(R.string.issueTypePullRequest), context));
}
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()));
switch (timeFormat) {
case "pretty": {
PrettyTime prettyTime = new PrettyTime(new Locale(locale));
String createdTime = prettyTime.format(issuesModel.getCreated_at());
issueCreatedTime.setText(createdTime);
issueCreatedTime.setOnClickListener(new ClickListener(TimeHelper.customDateFormatForToastDateFormat(issuesModel.getCreated_at()), context));
break;
}
case "normal": {
DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd '" + context.getResources().getString(R.string.timeAtText) + "' HH:mm", new Locale(locale));
String createdTime = formatter.format(issuesModel.getCreated_at());
issueCreatedTime.setText(createdTime);
break;
}
case "normal1": {
DateFormat formatter = new SimpleDateFormat("dd-MM-yyyy '" + context.getResources().getString(R.string.timeAtText) + "' HH:mm", new Locale(locale));
String createdTime = formatter.format(issuesModel.getCreated_at());
issueCreatedTime.setText(createdTime);
break;
}
}
}
}
static class LoadHolder extends RecyclerView.ViewHolder {
LoadHolder(View itemView) {
super(itemView);
}
}
public void setMoreDataAvailable(boolean moreDataAvailable) {
isMoreDataAvailable = moreDataAvailable;
}
public void notifyDataChanged() {
notifyDataSetChanged();
isLoading = false;
}
public interface OnLoadMoreListener {
void onLoadMore();
}
public void setLoadMoreListener(ClosedIssuesAdapter.OnLoadMoreListener loadMoreListener) {
this.loadMoreListener = loadMoreListener;
}
@Override
public Filter getFilter() {
return issuesFilter;
}
private Filter issuesFilter = new Filter() {
@Override
protected FilterResults performFiltering(CharSequence constraint) {
List<Issues> filteredList = new ArrayList<>();
if (constraint == null || constraint.length() == 0) {
filteredList.addAll(issuesList);
} else {
String filterPattern = constraint.toString().toLowerCase().trim();
for (Issues item : issuesList) {
if (item.getTitle().toLowerCase().contains(filterPattern) || item.getBody().toLowerCase().contains(filterPattern)) {
filteredList.add(item);
}
}
}
FilterResults results = new FilterResults();
results.values = filteredList;
return results;
}
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
issuesList.clear();
issuesList.addAll((List) results.values);
notifyDataSetChanged();
}
};
}

View File

@ -8,8 +8,8 @@ import android.view.ViewGroup;
import android.widget.BaseAdapter; import android.widget.BaseAdapter;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import com.squareup.picasso.Picasso;
import org.mian.gitnex.R; import org.mian.gitnex.R;
import org.mian.gitnex.clients.PicassoService;
import org.mian.gitnex.models.Collaborators; import org.mian.gitnex.models.Collaborators;
import org.mian.gitnex.helpers.RoundedTransformation; import org.mian.gitnex.helpers.RoundedTransformation;
import java.util.List; import java.util.List;
@ -61,7 +61,7 @@ public class CollaboratorsAdapter extends BaseAdapter {
ViewHolder viewHolder = null; ViewHolder viewHolder = null;
if (finalView == null) { if (finalView == null) {
finalView = LayoutInflater.from(mCtx).inflate(R.layout.collaborators_list, null); finalView = LayoutInflater.from(mCtx).inflate(R.layout.list_collaborators, null);
viewHolder = new ViewHolder(finalView); viewHolder = new ViewHolder(finalView);
finalView.setTag(viewHolder); finalView.setTag(viewHolder);
} }
@ -77,7 +77,7 @@ public class CollaboratorsAdapter extends BaseAdapter {
private void initData(ViewHolder viewHolder, int position) { private void initData(ViewHolder viewHolder, int position) {
Collaborators currentItem = collaboratorsList.get(position); Collaborators currentItem = collaboratorsList.get(position);
Picasso.get().load(currentItem.getAvatar_url()).transform(new RoundedTransformation(8, 0)).resize(180, 180).centerCrop().into(viewHolder.collaboratorAvatar); PicassoService.getInstance(mCtx).get().load(currentItem.getAvatar_url()).placeholder(R.drawable.loader_animated).transform(new RoundedTransformation(8, 0)).resize(180, 180).centerCrop().into(viewHolder.collaboratorAvatar);
if(!currentItem.getFull_name().equals("")) { if(!currentItem.getFull_name().equals("")) {
viewHolder.collaboratorName.setText(currentItem.getFull_name()); viewHolder.collaboratorName.setText(currentItem.getFull_name());

View File

@ -0,0 +1,161 @@
package org.mian.gitnex.adapters;
import android.content.Context;
import android.text.Html;
import android.text.method.LinkMovementMethod;
import android.view.View;
import android.widget.TextView;
import androidx.annotation.NonNull;
import com.mikepenz.fastadapter.FastAdapter;
import com.mikepenz.fastadapter.items.AbstractItem;
import org.mian.gitnex.R;
import org.mian.gitnex.helpers.ClickListener;
import org.mian.gitnex.helpers.TimeHelper;
import org.mian.gitnex.util.TinyDB;
import java.util.Date;
import java.util.List;
import java.util.Locale;
/**
* Author M M Arif
*/
public class CommitsAdapter extends AbstractItem<CommitsAdapter, CommitsAdapter.ViewHolder> {
final private Context ctx;
private String commitTitle;
private String commitHtmlUrl;
private String commitCommitter;
private Date commitDate;
private boolean isSelectable = true;
public CommitsAdapter(Context ctx) {
this.ctx = ctx;
}
public CommitsAdapter withNewItems(String commitTitle, String commitHtmlUrl, String commitCommitter, Date commitDate) {
this.setNewItems(commitTitle, commitHtmlUrl, commitCommitter, commitDate);
return this;
}
private void setNewItems(String commitTitle, String commitHtmlUrl, String commitCommitter, Date commitDate) {
this.commitTitle = commitTitle;
this.commitHtmlUrl = commitHtmlUrl;
this.commitCommitter = commitCommitter;
this.commitDate = commitDate;
}
public String getCommitTitle() {
return commitTitle;
}
private String getCommitHtmlUrl() {
return commitHtmlUrl;
}
private String getcommitCommitter() {
return commitCommitter;
}
private Date getcommitDate() {
return commitDate;
}
@Override
public boolean isEnabled() {
return true;
}
@Override
public CommitsAdapter withEnabled(boolean enabled) {
return null;
}
@Override
public boolean isSelectable() {
return isSelectable;
}
@Override
public CommitsAdapter withSelectable(boolean selectable) {
this.isSelectable = selectable;
return this;
}
@Override
public int getType() {
return R.id.commitList;
}
@Override
public int getLayoutRes() {
return R.layout.list_commits;
}
@NonNull
@Override
public CommitsAdapter.ViewHolder getViewHolder(@NonNull View v) {
return new CommitsAdapter.ViewHolder(v);
}
public class ViewHolder extends FastAdapter.ViewHolder<CommitsAdapter> {
final TinyDB tinyDb = new TinyDB(ctx);
final String locale = tinyDb.getString("locale");
final String timeFormat = tinyDb.getString("dateFormat");
TextView commitTitleVw;
TextView commitCommitterVw;
TextView commitDateVw;
TextView commitHtmlUrlVw;
public ViewHolder(View itemView) {
super(itemView);
commitTitleVw = itemView.findViewById(R.id.commitTitleVw);
commitCommitterVw = itemView.findViewById(R.id.commitCommitterVw);
commitDateVw = itemView.findViewById(R.id.commitDateVw);
commitHtmlUrlVw = itemView.findViewById(R.id.commitHtmlUrlVw);
}
@Override
public void bindView(CommitsAdapter item, @NonNull List<Object> payloads) {
commitTitleVw.setText(item.getCommitTitle());
commitCommitterVw.setText(ctx.getString(R.string.commitCommittedBy, item.getcommitCommitter()));
commitDateVw.setText(TimeHelper.formatTime(item.getcommitDate(), new Locale(locale), timeFormat, ctx));
if(timeFormat.equals("pretty")) {
commitDateVw.setOnClickListener(new ClickListener(TimeHelper.customDateFormatForToastDateFormat(item.getcommitDate()), ctx));
}
commitHtmlUrlVw.setText(Html.fromHtml("<a href='" + item.getCommitHtmlUrl() + "'>" + ctx.getResources().getString(R.string.viewInBrowser) + "</a> "));
commitHtmlUrlVw.setMovementMethod(LinkMovementMethod.getInstance());
}
@Override
public void unbindView(@NonNull CommitsAdapter item) {
commitTitleVw.setText(null);
commitCommitterVw.setText(null);
commitDateVw.setText(null);
commitHtmlUrlVw.setText(null);
}
}
}

View File

@ -0,0 +1,59 @@
package org.mian.gitnex.adapters;
import android.text.SpannableStringBuilder;
import android.text.method.LinkMovementMethod;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import org.mian.gitnex.R;
import java.util.List;
/**
* Author M M Arif
*/
public class CreditsAdapter extends RecyclerView.Adapter<CreditsAdapter.CreditsViewHolder> {
private List<CharSequence> creditsList;
static class CreditsViewHolder extends RecyclerView.ViewHolder {
private TextView creditText;
private CreditsViewHolder(View itemView) {
super(itemView);
creditText = itemView.findViewById(R.id.creditText);
}
}
public CreditsAdapter(List<CharSequence> creditsListMain) {
this.creditsList = creditsListMain;
}
@NonNull
@Override
public CreditsAdapter.CreditsViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.credits, parent, false);
return new CreditsAdapter.CreditsViewHolder(v);
}
@Override
public void onBindViewHolder(@NonNull CreditsAdapter.CreditsViewHolder holder, int position) {
SpannableStringBuilder strBuilder = new SpannableStringBuilder(creditsList.get(position));
holder.creditText.setText((strBuilder));
holder.creditText.setMovementMethod(LinkMovementMethod.getInstance());
}
@Override
public int getItemCount() {
return creditsList.size();
}
}

View File

@ -1,31 +1,35 @@
package org.mian.gitnex.adapters; package org.mian.gitnex.adapters;
import android.annotation.SuppressLint;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.graphics.Typeface; import android.graphics.Typeface;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.appcompat.view.ContextThemeWrapper;
import androidx.appcompat.widget.PopupMenu;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import com.amulyakhare.textdrawable.TextDrawable; import com.amulyakhare.textdrawable.TextDrawable;
import com.amulyakhare.textdrawable.util.ColorGenerator; import com.amulyakhare.textdrawable.util.ColorGenerator;
import com.squareup.picasso.Picasso; import com.google.android.material.bottomsheet.BottomSheetDialog;
import org.mian.gitnex.R; import org.mian.gitnex.R;
import org.mian.gitnex.activities.OpenRepoInBrowserActivity; import org.mian.gitnex.activities.OpenRepoInBrowserActivity;
import org.mian.gitnex.activities.RepoDetailActivity; import org.mian.gitnex.activities.RepoDetailActivity;
import org.mian.gitnex.activities.RepoStargazersActivity; import org.mian.gitnex.activities.RepoStargazersActivity;
import org.mian.gitnex.activities.RepoWatchersActivity; import org.mian.gitnex.activities.RepoWatchersActivity;
import org.mian.gitnex.clients.PicassoService;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.helpers.RoundedTransformation; import org.mian.gitnex.helpers.RoundedTransformation;
import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.models.UserRepositories; import org.mian.gitnex.models.UserRepositories;
import org.mian.gitnex.models.WatchRepository;
import org.mian.gitnex.util.TinyDB; import org.mian.gitnex.util.TinyDB;
import java.lang.reflect.Field;
import java.util.List; import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
/** /**
* Author M M Arif * Author M M Arif
@ -38,6 +42,7 @@ public class ExploreRepositoriesAdapter extends RecyclerView.Adapter<ExploreRepo
private Context mCtx; private Context mCtx;
public ExploreRepositoriesAdapter(List<UserRepositories> dataList, Context mCtx) { public ExploreRepositoriesAdapter(List<UserRepositories> dataList, Context mCtx) {
this.mCtx = mCtx; this.mCtx = mCtx;
this.searchedReposList = dataList; this.searchedReposList = dataList;
} }
@ -45,30 +50,31 @@ public class ExploreRepositoriesAdapter extends RecyclerView.Adapter<ExploreRepo
static class ReposSearchViewHolder extends RecyclerView.ViewHolder { static class ReposSearchViewHolder extends RecyclerView.ViewHolder {
private ImageView image; private ImageView image;
private TextView mTextView1; private TextView repoName;
private TextView mTextView2; private TextView repoDescription;
private TextView fullName; private TextView fullName;
private CheckBox isRepoAdmin;
private ImageView repoPrivatePublic; private ImageView repoPrivatePublic;
private TextView repoStars; private TextView repoStars;
private TextView repoForks; private TextView repoForks;
private TextView repoOpenIssuesCount; private TextView repoOpenIssuesCount;
private ReposSearchViewHolder(View itemView) { private ReposSearchViewHolder(View itemView) {
super(itemView); super(itemView);
mTextView1 = itemView.findViewById(R.id.repoName); repoName = itemView.findViewById(R.id.repoName);
mTextView2 = itemView.findViewById(R.id.repoDescription); repoDescription = itemView.findViewById(R.id.repoDescription);
image = itemView.findViewById(R.id.imageAvatar); image = itemView.findViewById(R.id.imageAvatar);
fullName = itemView.findViewById(R.id.repoFullName); fullName = itemView.findViewById(R.id.repoFullName);
isRepoAdmin = itemView.findViewById(R.id.repoIsAdmin);
repoPrivatePublic = itemView.findViewById(R.id.imageRepoType); repoPrivatePublic = itemView.findViewById(R.id.imageRepoType);
repoStars = itemView.findViewById(R.id.repoStars); repoStars = itemView.findViewById(R.id.repoStars);
repoForks = itemView.findViewById(R.id.repoForks); repoForks = itemView.findViewById(R.id.repoForks);
repoOpenIssuesCount = itemView.findViewById(R.id.repoOpenIssuesCount); repoOpenIssuesCount = itemView.findViewById(R.id.repoOpenIssuesCount);
ImageView reposDropdownMenu = itemView.findViewById(R.id.reposDropdownMenu); ImageView reposDropdownMenu = itemView.findViewById(R.id.reposDropdownMenu);
itemView.setOnClickListener(new View.OnClickListener() { itemView.setOnClickListener(v -> {
@Override
public void onClick(View v) {
Context context = v.getContext(); Context context = v.getContext();
TextView repoFullName = v.findViewById(R.id.repoFullName); TextView repoFullName = v.findViewById(R.id.repoFullName);
@ -79,72 +85,103 @@ public class ExploreRepositoriesAdapter extends RecyclerView.Adapter<ExploreRepo
TinyDB tinyDb = new TinyDB(context); TinyDB tinyDb = new TinyDB(context);
tinyDb.putString("repoFullName", repoFullName.getText().toString()); tinyDb.putString("repoFullName", repoFullName.getText().toString());
tinyDb.putBoolean("resumeIssues", true); tinyDb.putBoolean("resumeIssues", true);
context.startActivity(intent); tinyDb.putBoolean("isRepoAdmin", isRepoAdmin.isChecked());
//store if user is watching this repo
{
final String instanceUrl = tinyDb.getString("instanceUrl");
String[] parts = repoFullName.getText().toString().split("/");
final String repoOwner = parts[0];
final String repoName = parts[1];
final String token = "token " + tinyDb.getString(tinyDb.getString("loginUid") + "-token");
WatchRepository watch = new WatchRepository();
Call<WatchRepository> call;
call = RetrofitClient.getInstance(instanceUrl, context).getApiInterface().checkRepoWatchStatus(token, repoOwner, repoName);
call.enqueue(new Callback<WatchRepository>() {
@Override
public void onResponse(@NonNull Call<WatchRepository> call, @NonNull retrofit2.Response<WatchRepository> response) {
if(response.isSuccessful()) {
assert response.body() != null;
tinyDb.putBoolean("repoWatch", response.body().getSubscribed());
} else {
tinyDb.putBoolean("repoWatch", false);
if(response.code() != 404) {
Toasty.info(context, context.getString(R.string.genericApiStatusError));
}
}
}
@Override
public void onFailure(@NonNull Call<WatchRepository> call, @NonNull Throwable t) {
tinyDb.putBoolean("repoWatch", false);
Toasty.info(context, context.getString(R.string.genericApiStatusError));
} }
}); });
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); context.startActivity(intent);
break;
case R.id.repoWatchers: });
Intent intentW = new Intent(context, RepoWatchersActivity.class); reposDropdownMenu.setOnClickListener(v -> {
intentW.putExtra("repoFullNameForWatchers", fullName.getText());
context.startActivity(intentW);
break;
case R.id.repoOpenInBrowser: final Context context = v.getContext();
@SuppressLint("InflateParams") View view = LayoutInflater.from(context).inflate(R.layout.bottom_sheet_repository_in_list, null);
TextView repoOpenInBrowser = view.findViewById(R.id.repoOpenInBrowser);
TextView repoStargazers = view.findViewById(R.id.repoStargazers);
TextView repoWatchers = view.findViewById(R.id.repoWatchers);
TextView bottomSheetHeader = view.findViewById(R.id.bottomSheetHeader);
bottomSheetHeader.setText(fullName.getText());
BottomSheetDialog dialog = new BottomSheetDialog(context);
dialog.setContentView(view);
dialog.show();
repoOpenInBrowser.setOnClickListener(openInBrowser -> {
Intent intentOpenInBrowser = new Intent(context, OpenRepoInBrowserActivity.class); Intent intentOpenInBrowser = new Intent(context, OpenRepoInBrowserActivity.class);
intentOpenInBrowser.putExtra("repoFullNameBrowser", fullName.getText()); intentOpenInBrowser.putExtra("repoFullNameBrowser", fullName.getText());
context.startActivity(intentOpenInBrowser); context.startActivity(intentOpenInBrowser);
break; dialog.dismiss();
}
return false;
}
}); });
popupMenu.show(); repoStargazers.setOnClickListener(stargazers -> {
Intent intent = new Intent(context, RepoStargazersActivity.class);
intent.putExtra("repoFullNameForStars", fullName.getText());
context.startActivity(intent);
dialog.dismiss();
});
repoWatchers.setOnClickListener(watchers -> {
Intent intentW = new Intent(context, RepoWatchersActivity.class);
intentW.putExtra("repoFullNameForWatchers", fullName.getText());
context.startActivity(intentW);
dialog.dismiss();
});
}
}); });
} }
@ -154,7 +191,8 @@ public class ExploreRepositoriesAdapter extends RecyclerView.Adapter<ExploreRepo
@NonNull @NonNull
@Override @Override
public ExploreRepositoriesAdapter.ReposSearchViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { public ExploreRepositoriesAdapter.ReposSearchViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.repos_list, parent, false);
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_repos, parent, false);
return new ExploreRepositoriesAdapter.ReposSearchViewHolder(v); return new ExploreRepositoriesAdapter.ReposSearchViewHolder(v);
} }
@ -164,26 +202,19 @@ public class ExploreRepositoriesAdapter extends RecyclerView.Adapter<ExploreRepo
final UserRepositories currentItem = searchedReposList.get(position); final UserRepositories currentItem = searchedReposList.get(position);
holder.mTextView2.setVisibility(View.GONE); holder.repoDescription.setVisibility(View.GONE);
ColorGenerator generator = ColorGenerator.MATERIAL; ColorGenerator generator = ColorGenerator.MATERIAL;
int color = generator.getColor(currentItem.getName()); int color = generator.getColor(currentItem.getName());
String firstCharacter = String.valueOf(currentItem.getName().charAt(0)); String firstCharacter = String.valueOf(currentItem.getName().charAt(0));
TextDrawable drawable = TextDrawable.builder() TextDrawable drawable = TextDrawable.builder().beginConfig().useFont(Typeface.DEFAULT).fontSize(18).toUpperCase().width(28).height(28).endConfig().buildRoundRect(firstCharacter, color, 3);
.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() != null) {
if(!currentItem.getAvatar_url().equals("")) { if(!currentItem.getAvatar_url().equals("")) {
Picasso.get().load(currentItem.getAvatar_url()).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(holder.image); PicassoService.getInstance(mCtx).get().load(currentItem.getAvatar_url()).placeholder(R.drawable.loader_animated).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(holder.image);
} else { }
else {
holder.image.setImageDrawable(drawable); holder.image.setImageDrawable(drawable);
} }
} }
@ -191,10 +222,10 @@ public class ExploreRepositoriesAdapter extends RecyclerView.Adapter<ExploreRepo
holder.image.setImageDrawable(drawable); holder.image.setImageDrawable(drawable);
} }
holder.mTextView1.setText(currentItem.getName()); holder.repoName.setText(currentItem.getName());
if(!currentItem.getDescription().equals("")) { if(!currentItem.getDescription().equals("")) {
holder.mTextView2.setVisibility(View.VISIBLE); holder.repoDescription.setVisibility(View.VISIBLE);
holder.mTextView2.setText(currentItem.getDescription()); holder.repoDescription.setText(currentItem.getDescription());
} }
holder.fullName.setText(currentItem.getFullname()); holder.fullName.setText(currentItem.getFullname());
if(currentItem.getPrivateFlag()) { if(currentItem.getPrivateFlag()) {
@ -206,11 +237,17 @@ public class ExploreRepositoriesAdapter extends RecyclerView.Adapter<ExploreRepo
holder.repoStars.setText(currentItem.getStars_count()); holder.repoStars.setText(currentItem.getStars_count());
holder.repoForks.setText(currentItem.getForks_count()); holder.repoForks.setText(currentItem.getForks_count());
holder.repoOpenIssuesCount.setText(currentItem.getOpen_issues_count()); holder.repoOpenIssuesCount.setText(currentItem.getOpen_issues_count());
if(holder.isRepoAdmin == null) {
holder.isRepoAdmin = new CheckBox(mCtx);
}
holder.isRepoAdmin.setChecked(currentItem.getPermissions().isAdmin());
} }
@Override @Override
public int getItemCount() { public int getItemCount() {
return searchedReposList.size(); return searchedReposList.size();
} }
} }

View File

@ -13,6 +13,7 @@ import androidx.recyclerview.widget.RecyclerView;
import org.mian.gitnex.R; import org.mian.gitnex.R;
import org.mian.gitnex.helpers.Toasty; import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.models.Files; import org.mian.gitnex.models.Files;
import org.mian.gitnex.util.AppUtil;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -38,6 +39,7 @@ public class FilesAdapter extends RecyclerView.Adapter<FilesAdapter.FilesViewHol
private ImageView fileTypeImage; private ImageView fileTypeImage;
private TextView fileName; private TextView fileName;
private TextView fileType; private TextView fileType;
private TextView fileInfo;
private FilesViewHolder(View itemView) { private FilesViewHolder(View itemView) {
@ -45,6 +47,7 @@ public class FilesAdapter extends RecyclerView.Adapter<FilesAdapter.FilesViewHol
fileName = itemView.findViewById(R.id.fileName); fileName = itemView.findViewById(R.id.fileName);
fileTypeImage = itemView.findViewById(R.id.fileImage); fileTypeImage = itemView.findViewById(R.id.fileImage);
fileType = itemView.findViewById(R.id.fileType); fileType = itemView.findViewById(R.id.fileType);
fileInfo = itemView.findViewById(R.id.fileInfo);
//ImageView filesDropdownMenu = itemView.findViewById(R.id.filesDropdownMenu); //ImageView filesDropdownMenu = itemView.findViewById(R.id.filesDropdownMenu);
@ -144,7 +147,7 @@ public class FilesAdapter extends RecyclerView.Adapter<FilesAdapter.FilesViewHol
@NonNull @NonNull
@Override @Override
public FilesAdapter.FilesViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { public FilesAdapter.FilesViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.files_list, parent, false); View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_files, parent, false);
return new FilesAdapter.FilesViewHolder(v); return new FilesAdapter.FilesViewHolder(v);
} }
@ -158,6 +161,8 @@ public class FilesAdapter extends RecyclerView.Adapter<FilesAdapter.FilesViewHol
if(currentItem.getType().equals("file")) { if(currentItem.getType().equals("file")) {
holder.fileTypeImage.setImageDrawable(mCtx.getResources().getDrawable(R.drawable.ic_file_new)); holder.fileTypeImage.setImageDrawable(mCtx.getResources().getDrawable(R.drawable.ic_file_new));
holder.fileInfo.setVisibility(View.VISIBLE);
holder.fileInfo.setText(AppUtil.formatFileSizeInDetail(currentItem.getSize()));
} }
else if(currentItem.getType().equals("dir")) { else if(currentItem.getType().equals("dir")) {
holder.fileTypeImage.setImageDrawable(mCtx.getResources().getDrawable(R.drawable.ic_folder_24)); holder.fileTypeImage.setImageDrawable(mCtx.getResources().getDrawable(R.drawable.ic_folder_24));

View File

@ -0,0 +1,138 @@
package org.mian.gitnex.adapters;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.HorizontalScrollView;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import org.mian.gitnex.R;
import org.mian.gitnex.models.FileDiffView;
import java.util.List;
/**
* Author M M Arif
*/
public class FilesDiffAdapter extends RecyclerView.Adapter<FilesDiffAdapter.FilesDiffViewHolder> {
private List<FileDiffView> dataList;
private Context ctx;
static class FilesDiffViewHolder extends RecyclerView.ViewHolder {
private TextView fileContents;
private TextView fileName;
private TextView fileInfo;
private ImageView fileImage;
private HorizontalScrollView fileContentsView;
private LinearLayout allLines;
private FilesDiffViewHolder(View itemView) {
super(itemView);
fileContents = itemView.findViewById(R.id.fileContents);
fileName = itemView.findViewById(R.id.fileName);
fileInfo = itemView.findViewById(R.id.fileInfo);
fileImage = itemView.findViewById(R.id.fileImage);
fileContentsView = itemView.findViewById(R.id.fileContentsView);
allLines = itemView.findViewById(R.id.allLinesLayout);
}
}
public FilesDiffAdapter(List<FileDiffView> dataListMain, Context ctx) {
this.dataList = dataListMain;
this.ctx = ctx;
}
@NonNull
@Override
public FilesDiffAdapter.FilesDiffViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_files_diffs, parent, false);
return new FilesDiffAdapter.FilesDiffViewHolder(v);
}
@Override
public void onBindViewHolder(@NonNull FilesDiffViewHolder holder, int position) {
FileDiffView data = dataList.get(position);
if(data.isFileType()) {
holder.fileName.setText(data.getFileName());
holder.fileInfo.setVisibility(View.GONE);
//byte[] imageData = Base64.decode(data.getFileContents(), Base64.DEFAULT);
//Drawable imageDrawable = new BitmapDrawable(ctx.getResources(), BitmapFactory.decodeByteArray(imageData, 0, imageData.length));
//holder.fileImage.setImageDrawable(imageDrawable);
holder.fileContentsView.setVisibility(View.GONE);
}
else {
String[] splitData = data.getFileContents().split("\\R");
for (String eachSplit : splitData) {
TextView textLine = new TextView(ctx);
textLine.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
if (eachSplit.startsWith("+")) {
textLine.setText(eachSplit);
holder.allLines.addView(textLine);
textLine.setTextColor(ctx.getResources().getColor(R.color.colorPrimary));
textLine.setPadding(5, 5, 5, 5);
textLine.setBackgroundColor(ctx.getResources().getColor(R.color.diffAddedColor));
}
else if (eachSplit.startsWith("-")) {
textLine.setText(eachSplit);
holder.allLines.addView(textLine);
textLine.setTextColor(ctx.getResources().getColor(R.color.colorPrimary));
textLine.setPadding(5, 5, 5, 5);
textLine.setBackgroundColor(ctx.getResources().getColor(R.color.diffRemovedColor));
}
else {
if(eachSplit.length() > 0) {
textLine.setText(eachSplit);
holder.allLines.addView(textLine);
textLine.setTextColor(ctx.getResources().getColor(R.color.colorPrimary));
textLine.setPadding(5, 5, 5, 5);
textLine.setBackgroundColor(ctx.getResources().getColor(R.color.white));
}
}
}
holder.fileName.setText(data.getFileName());
if(!data.getFileInfo().equals("")) {
holder.fileInfo.setText(ctx.getResources().getString(R.string.fileDiffInfoChanges, data.getFileInfo()));
}
else {
holder.fileInfo.setVisibility(View.GONE);
}
}
}
@Override
public int getItemCount() {
return dataList.size();
}
}

View File

@ -7,15 +7,15 @@ import android.graphics.drawable.Drawable;
import android.net.Uri; import android.net.Uri;
import android.text.Spanned; import android.text.Spanned;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import com.squareup.picasso.Picasso; import com.google.android.material.bottomsheet.BottomSheetDialog;
import com.vdurmont.emoji.EmojiParser; import com.vdurmont.emoji.EmojiParser;
import org.mian.gitnex.R; import org.mian.gitnex.R;
import org.mian.gitnex.activities.ReplyToIssueActivity; import org.mian.gitnex.activities.ReplyToIssueActivity;
import org.mian.gitnex.clients.PicassoService;
import org.mian.gitnex.helpers.TimeHelper; import org.mian.gitnex.helpers.TimeHelper;
import org.mian.gitnex.helpers.UserMentions; import org.mian.gitnex.helpers.UserMentions;
import org.mian.gitnex.models.IssueComments; import org.mian.gitnex.models.IssueComments;
@ -23,7 +23,7 @@ import org.mian.gitnex.helpers.RoundedTransformation;
import org.mian.gitnex.util.TinyDB; import org.mian.gitnex.util.TinyDB;
import org.mian.gitnex.helpers.ClickListener; import org.mian.gitnex.helpers.ClickListener;
import org.ocpsoft.prettytime.PrettyTime; import org.ocpsoft.prettytime.PrettyTime;
import java.lang.reflect.Field; import java.sql.Time;
import java.text.DateFormat; import java.text.DateFormat;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Collection; import java.util.Collection;
@ -33,8 +33,6 @@ import java.util.Locale;
import java.util.Objects; import java.util.Objects;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.appcompat.view.ContextThemeWrapper;
import androidx.appcompat.widget.PopupMenu;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import io.noties.markwon.AbstractMarkwonPlugin; import io.noties.markwon.AbstractMarkwonPlugin;
import io.noties.markwon.Markwon; import io.noties.markwon.Markwon;
@ -72,8 +70,11 @@ public class IssueCommentsAdapter extends RecyclerView.Adapter<IssueCommentsAdap
private ImageView commentsOptionsMenu; private ImageView commentsOptionsMenu;
private TextView commendBodyRaw; private TextView commendBodyRaw;
private TextView commentModified; private TextView commentModified;
private TextView commenterUsername;
private TextView htmlUrl;
private IssueCommentViewHolder(View itemView) { private IssueCommentViewHolder(View itemView) {
super(itemView); super(itemView);
issueNumber = itemView.findViewById(R.id.issueNumber); issueNumber = itemView.findViewById(R.id.issueNumber);
@ -84,75 +85,84 @@ public class IssueCommentsAdapter extends RecyclerView.Adapter<IssueCommentsAdap
commentsOptionsMenu = itemView.findViewById(R.id.commentsOptionsMenu); commentsOptionsMenu = itemView.findViewById(R.id.commentsOptionsMenu);
commendBodyRaw = itemView.findViewById(R.id.commendBodyRaw); commendBodyRaw = itemView.findViewById(R.id.commendBodyRaw);
commentModified = itemView.findViewById(R.id.commentModified); commentModified = itemView.findViewById(R.id.commentModified);
commenterUsername = itemView.findViewById(R.id.commenterUsername);
htmlUrl = itemView.findViewById(R.id.htmlUrl);
commentsOptionsMenu.setOnClickListener(new View.OnClickListener() { commentsOptionsMenu.setOnClickListener(v -> {
@Override
public void onClick(View v) {
final Context context = v.getContext(); final Context context = v.getContext();
Context context_ = new ContextThemeWrapper(context, R.style.popupMenuStyle); final TinyDB tinyDb = new TinyDB(context);
final String loginUid = tinyDb.getString("loginUid");
PopupMenu popupMenu = new PopupMenu(context_, v); @SuppressLint("InflateParams") View view = LayoutInflater.from(context).inflate(R.layout.bottom_sheet_issue_comments, null);
popupMenu.inflate(R.menu.issue_comment_menu);
Object menuHelper; TextView commentMenuEdit = view.findViewById(R.id.commentMenuEdit);
Class[] argTypes; TextView commentShare = view.findViewById(R.id.issueCommentShare);
try { //TextView commentMenuDelete = view.findViewById(R.id.commentMenuDelete);
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;
if(!loginUid.contentEquals(commenterUsername.getText())) {
commentMenuEdit.setVisibility(View.GONE);
//commentMenuDelete.setVisibility(View.GONE);
} }
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { BottomSheetDialog dialog = new BottomSheetDialog(context);
@Override dialog.setContentView(view);
public boolean onMenuItemClick(MenuItem item) { dialog.show();
switch (item.getItemId()) {
case R.id.commentMenuEdit: commentMenuEdit.setOnClickListener(ediComment -> {
Intent intent = new Intent(context, ReplyToIssueActivity.class); Intent intent = new Intent(context, ReplyToIssueActivity.class);
intent.putExtra("commentId", commendId.getText()); intent.putExtra("commentId", commendId.getText());
intent.putExtra("commentAction", "edit"); intent.putExtra("commentAction", "edit");
intent.putExtra("commentBody", commendBodyRaw.getText()); intent.putExtra("commentBody", commendBodyRaw.getText());
context.startActivity(intent); context.startActivity(intent);
break; dialog.dismiss();
case R.id.commentMenuDelete:
break;
}
return false;
}
}); });
popupMenu.show(); commentShare.setOnClickListener(ediComment -> {
// get comment Url
CharSequence commentUrl = htmlUrl.getText();
// share issue comment
Intent sharingIntent = new Intent(android.content.Intent.ACTION_SEND);
sharingIntent.setType("text/plain");
String intentHeader = tinyDb.getString("issueNumber") + context.getResources().getString(R.string.hash) + "issuecomment-" + commendId.getText() + " " + tinyDb.getString("issueTitle");
sharingIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, intentHeader);
sharingIntent.putExtra(android.content.Intent.EXTRA_TEXT, commentUrl);
context.startActivity(Intent.createChooser(sharingIntent, intentHeader));
dialog.dismiss();
});
/*commentMenuDelete.setOnClickListener(deleteComment -> {
dialog.dismiss();
});*/
}
}); });
} }
} }
public IssueCommentsAdapter(Context mCtx, List<IssueComments> issuesCommentsMain) { public IssueCommentsAdapter(Context mCtx, List<IssueComments> issuesCommentsMain) {
this.mCtx = mCtx; this.mCtx = mCtx;
this.issuesComments = issuesCommentsMain; this.issuesComments = issuesCommentsMain;
} }
@NonNull @NonNull
@Override @Override
public IssueCommentsAdapter.IssueCommentViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { public IssueCommentsAdapter.IssueCommentViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.issue_comments, parent, false);
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_issue_comments, parent, false);
return new IssueCommentsAdapter.IssueCommentViewHolder(v); return new IssueCommentsAdapter.IssueCommentViewHolder(v);
} }
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
@ -162,61 +172,58 @@ public class IssueCommentsAdapter extends RecyclerView.Adapter<IssueCommentsAdap
final TinyDB tinyDb = new TinyDB(mCtx); final TinyDB tinyDb = new TinyDB(mCtx);
final String locale = tinyDb.getString("locale"); final String locale = tinyDb.getString("locale");
final String timeFormat = tinyDb.getString("dateFormat"); final String timeFormat = tinyDb.getString("dateFormat");
final String loginUid = tinyDb.getString("loginUid");
IssueComments currentItem = issuesComments.get(position); IssueComments currentItem = issuesComments.get(position);
if(!loginUid.equals(currentItem.getUser().getUsername())) { holder.htmlUrl.setText(currentItem.getHtml_url());
holder.commentsOptionsMenu.setVisibility(View.INVISIBLE); holder.commenterUsername.setText(currentItem.getUser().getUsername());
}
holder.commendId.setText(String.valueOf(currentItem.getId())); holder.commendId.setText(String.valueOf(currentItem.getId()));
holder.commendBodyRaw.setText(currentItem.getBody()); holder.commendBodyRaw.setText(currentItem.getBody());
if(!currentItem.getUser().getFull_name().equals("")) { if(!currentItem.getUser().getFull_name().equals("")) {
holder.issueCommenterAvatar.setOnClickListener(new ClickListener(mCtx.getResources().getString(R.string.issueCommenter) + currentItem.getUser().getFull_name(), mCtx)); holder.issueCommenterAvatar.setOnClickListener(new ClickListener(mCtx.getResources().getString(R.string.issueCommenter) + currentItem.getUser().getFull_name(), mCtx));
} else { }
else {
holder.issueCommenterAvatar.setOnClickListener(new ClickListener(mCtx.getResources().getString(R.string.issueCommenter) + currentItem.getUser().getLogin(), mCtx)); holder.issueCommenterAvatar.setOnClickListener(new ClickListener(mCtx.getResources().getString(R.string.issueCommenter) + currentItem.getUser().getLogin(), mCtx));
} }
if (currentItem.getUser().getAvatar_url() != null) { PicassoService.getInstance(mCtx).get().load(currentItem.getUser().getAvatar_url()).placeholder(R.drawable.loader_animated).transform(new RoundedTransformation(8, 0)).resize(120, 120).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(8, 0)).resize(120, 120).centerCrop().into(holder.issueCommenterAvatar);
}
String cleanIssueComments = currentItem.getBody().trim(); String cleanIssueComments = currentItem.getBody().trim();
final Markwon markwon = Markwon.builder(Objects.requireNonNull(mCtx)) final Markwon markwon = Markwon.builder(Objects.requireNonNull(mCtx)).usePlugin(CorePlugin.create()).usePlugin(ImagesPlugin.create(new ImagesPlugin.ImagesConfigure() {
.usePlugin(CorePlugin.create())
.usePlugin(ImagesPlugin.create(new ImagesPlugin.ImagesConfigure() {
@Override @Override
public void configureImages(@NonNull ImagesPlugin plugin) { public void configureImages(@NonNull ImagesPlugin plugin) {
plugin.addSchemeHandler(new SchemeHandler() { plugin.addSchemeHandler(new SchemeHandler() {
@NonNull @NonNull
@Override @Override
public ImageItem handle(@NonNull String raw, @NonNull Uri uri) { public ImageItem handle(@NonNull String raw, @NonNull Uri uri) {
final int resourceId = mCtx.getResources().getIdentifier( final int resourceId = mCtx.getResources().getIdentifier(raw.substring("drawable://".length()), "drawable", mCtx.getPackageName());
raw.substring("drawable://".length()),
"drawable",
mCtx.getPackageName());
final Drawable drawable = mCtx.getDrawable(resourceId); final Drawable drawable = mCtx.getDrawable(resourceId);
assert drawable != null; assert drawable != null;
return ImageItem.withResult(drawable); return ImageItem.withResult(drawable);
} }
@NonNull @NonNull
@Override @Override
public Collection<String> supportedSchemes() { public Collection<String> supportedSchemes() {
return Collections.singleton("drawable"); return Collections.singleton("drawable");
} }
}); });
plugin.placeholderProvider(new ImagesPlugin.PlaceholderProvider() { plugin.placeholderProvider(new ImagesPlugin.PlaceholderProvider() {
@Nullable @Nullable
@Override @Override
public Drawable providePlaceholder(@NonNull AsyncDrawable drawable) { public Drawable providePlaceholder(@NonNull AsyncDrawable drawable) {
return null; return null;
} }
}); });
@ -226,22 +233,15 @@ public class IssueCommentsAdapter extends RecyclerView.Adapter<IssueCommentsAdap
plugin.defaultMediaDecoder(DefaultMediaDecoder.create(mCtx.getResources())); plugin.defaultMediaDecoder(DefaultMediaDecoder.create(mCtx.getResources()));
plugin.defaultMediaDecoder(DefaultMediaDecoder.create()); plugin.defaultMediaDecoder(DefaultMediaDecoder.create());
} }
})) })).usePlugin(new AbstractMarkwonPlugin() {
.usePlugin(new AbstractMarkwonPlugin() {
@Override @Override
public void configureTheme(@NonNull MarkwonTheme.Builder builder) { public void configureTheme(@NonNull MarkwonTheme.Builder builder) {
builder
.codeTextColor(tinyDb.getInt("codeBlockColor")) builder.codeTextColor(tinyDb.getInt("codeBlockColor")).codeBackgroundColor(tinyDb.getInt("codeBlockBackground")).linkColor(mCtx.getResources().getColor(R.color.lightBlue));
.codeBackgroundColor(tinyDb.getInt("codeBlockBackground"))
.linkColor(mCtx.getResources().getColor(R.color.lightBlue));
} }
})
.usePlugin(TablePlugin.create(mCtx)) }).usePlugin(TablePlugin.create(mCtx)).usePlugin(TaskListPlugin.create(mCtx)).usePlugin(HtmlPlugin.create()).usePlugin(StrikethroughPlugin.create()).usePlugin(LinkifyPlugin.create()).build();
.usePlugin(TaskListPlugin.create(mCtx))
.usePlugin(HtmlPlugin.create())
.usePlugin(StrikethroughPlugin.create())
.usePlugin(LinkifyPlugin.create())
.build();
Spanned bodyWithMD = markwon.toMarkdown(EmojiParser.parseToUnicode(cleanIssueComments)); Spanned bodyWithMD = markwon.toMarkdown(EmojiParser.parseToUnicode(cleanIssueComments));
markwon.setParsedMarkdown(holder.issueComment, UserMentions.UserMentionsFunc(mCtx, bodyWithMD, cleanIssueComments)); markwon.setParsedMarkdown(holder.issueComment, UserMentions.UserMentionsFunc(mCtx, bodyWithMD, cleanIssueComments));
@ -249,42 +249,31 @@ public class IssueCommentsAdapter extends RecyclerView.Adapter<IssueCommentsAdap
String edited; String edited;
if(!currentItem.getUpdated_at().equals(currentItem.getCreated_at())) { if(!currentItem.getUpdated_at().equals(currentItem.getCreated_at())) {
edited = mCtx.getResources().getString(R.string.colorfulBulletSpan) + mCtx.getResources().getString(R.string.modifiedText); edited = mCtx.getResources().getString(R.string.colorfulBulletSpan) + mCtx.getResources().getString(R.string.modifiedText);
holder.commentModified.setVisibility(View.VISIBLE); holder.commentModified.setVisibility(View.VISIBLE);
holder.commentModified.setText(edited); holder.commentModified.setText(edited);
holder.commentModified.setOnClickListener(new ClickListener(TimeHelper.customDateFormatForToastDateFormat(currentItem.getUpdated_at()), mCtx)); holder.commentModified.setOnClickListener(new ClickListener(TimeHelper.customDateFormatForToastDateFormat(currentItem.getUpdated_at()), mCtx));
} }
else { else {
holder.commentModified.setVisibility(View.INVISIBLE); holder.commentModified.setVisibility(View.INVISIBLE);
} }
switch (timeFormat) { holder.issueCommentDate.setText(TimeHelper.formatTime(currentItem.getCreated_at(), new Locale(locale), timeFormat, mCtx));
case "pretty": {
PrettyTime prettyTime = new PrettyTime(new Locale(locale)); if(timeFormat.equals("pretty")) {
String createdTime = prettyTime.format(currentItem.getCreated_at());
holder.issueCommentDate.setText(createdTime);
holder.issueCommentDate.setOnClickListener(new ClickListener(TimeHelper.customDateFormatForToastDateFormat(currentItem.getCreated_at()), mCtx)); holder.issueCommentDate.setOnClickListener(new ClickListener(TimeHelper.customDateFormatForToastDateFormat(currentItem.getCreated_at()), mCtx));
break;
} }
case "normal": {
DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd '" + mCtx.getResources().getString(R.string.timeAtText) + "' HH:mm", new Locale(locale));
String createdTime = formatter.format(currentItem.getCreated_at());
holder.issueCommentDate.setText(createdTime);
break;
}
case "normal1": {
DateFormat formatter = new SimpleDateFormat("dd-MM-yyyy '" + mCtx.getResources().getString(R.string.timeAtText) + "' HH:mm", new Locale(locale));
String createdTime = formatter.format(currentItem.getCreated_at());
holder.issueCommentDate.setText(createdTime);
break;
}
}
} }
@Override @Override
public int getItemCount() { public int getItemCount() {
return issuesComments.size(); return issuesComments.size();
} }
} }

View File

@ -1,117 +1,150 @@
package org.mian.gitnex.adapters; package org.mian.gitnex.adapters;
import android.annotation.SuppressLint;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.text.Html; import android.text.Html;
import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView; import android.widget.TextView;
import com.squareup.picasso.Picasso; import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;
import com.mikepenz.fastadapter.FastAdapter;
import com.mikepenz.fastadapter.items.AbstractItem;
import com.mikepenz.fastadapter.listeners.ClickEventHook;
import com.mikepenz.fastadapter.utils.EventHookUtil;
import org.mian.gitnex.R; import org.mian.gitnex.R;
import org.mian.gitnex.activities.IssueDetailActivity; import org.mian.gitnex.activities.IssueDetailActivity;
import org.mian.gitnex.clients.PicassoService;
import org.mian.gitnex.helpers.ClickListener; import org.mian.gitnex.helpers.ClickListener;
import org.mian.gitnex.helpers.RoundedTransformation; import org.mian.gitnex.helpers.RoundedTransformation;
import org.mian.gitnex.helpers.TimeHelper; import org.mian.gitnex.helpers.TimeHelper;
import org.mian.gitnex.models.Issues;
import org.mian.gitnex.util.TinyDB; import org.mian.gitnex.util.TinyDB;
import org.ocpsoft.prettytime.PrettyTime; import org.ocpsoft.prettytime.PrettyTime;
import java.text.DateFormat; import java.text.DateFormat;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
/** /**
* Author M M Arif * Author M M Arif
*/ */
public class IssuesAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> implements Filterable { public class IssuesAdapter extends AbstractItem<IssuesAdapter, IssuesAdapter.ViewHolder> {
private Context context; final private Context ctx;
private final int TYPE_LOAD = 0; private String issueTitle;
private List<Issues> issuesList; private int issueNumber;
private List<Issues> issuesListFull; private String issueAssigneeAvatar;
private OnLoadMoreListener loadMoreListener; private Date issueCreatedTime;
private boolean isLoading = false, isMoreDataAvailable = true; private int issueCommentsCount;
private String userFullname;
private String userLogin;
public IssuesAdapter(Context context, List<Issues> issuesListMain) { private boolean isSelectable = true;
this.context = context; public IssuesAdapter(Context ctx) {
this.issuesList = issuesListMain; this.ctx = ctx;
issuesListFull = new ArrayList<>(issuesList); }
public IssuesAdapter withNewItems(String issueTitle, int issueNumber, String issueAssigneeAvatar, Date issueCreatedTime, int issueCommentsCount, String userFullname, String userLogin) {
this.setNewItems(issueTitle, issueNumber, issueAssigneeAvatar, issueCreatedTime, issueCommentsCount, userFullname, userLogin);
return this;
}
private void setNewItems(String issueTitle, int issueNumber, String issueAssigneeAvatar, Date issueCreatedTime, int issueCommentsCount, String userFullname, String userLogin) {
this.issueTitle = issueTitle;
this.issueNumber = issueNumber;
this.issueAssigneeAvatar = issueAssigneeAvatar;
this.issueCreatedTime = issueCreatedTime;
this.issueCommentsCount = issueCommentsCount;
this.userFullname = userFullname;
this.userLogin = userLogin;
}
private int getIssueNumber() {
return issueNumber;
}
public String getIssueTitle() {
return issueTitle;
}
private String getIssueAssigneeAvatar() {
return issueAssigneeAvatar;
}
private Date getIssueCreatedTime() {
return issueCreatedTime;
}
private int getIssueCommentsCount() {
return issueCommentsCount;
}
private String getUserFullname() {
return userFullname;
}
private String getUserLogin() {
return userLogin;
}
@Override
public boolean isEnabled() {
return true;
}
@Override
public IssuesAdapter withEnabled(boolean enabled) {
return null;
}
@Override
public boolean isSelectable() {
return isSelectable;
}
@Override
public IssuesAdapter withSelectable(boolean selectable) {
this.isSelectable = selectable;
return this;
}
@Override
public int getType() {
return R.id.relativeLayoutFrameIssuesList;
}
@Override
public int getLayoutRes() {
return R.layout.list_issues;
} }
@NonNull @NonNull
@Override @Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { public IssuesAdapter.ViewHolder getViewHolder(@NonNull View v) {
return new IssuesAdapter.ViewHolder(v);
LayoutInflater inflater = LayoutInflater.from(context);
if(viewType == TYPE_LOAD){
return new IssuesHolder(inflater.inflate(R.layout.repo_detail_issues_list, parent,false));
}
else {
return new LoadHolder(inflater.inflate(R.layout.row_load,parent,false));
} }
} public class ViewHolder extends FastAdapter.ViewHolder<IssuesAdapter> {
@Override final TinyDB tinyDb = new TinyDB(ctx);
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { final String locale = tinyDb.getString("locale");
final String timeFormat = tinyDb.getString("dateFormat");
if(position >= getItemCount()-1 && isMoreDataAvailable && !isLoading && loadMoreListener!=null) {
isLoading = true;
loadMoreListener.onLoadMore();
}
if(getItemViewType(position) == TYPE_LOAD) {
((IssuesHolder)holder).bindData(issuesList.get(position));
}
}
@Override
public int getItemViewType(int position) {
if(issuesList.get(position).getTitle() != null) {
return TYPE_LOAD;
}
else {
return 1;
}
}
@Override
public int getItemCount() {
return issuesList.size();
}
class IssuesHolder extends RecyclerView.ViewHolder {
private TextView issueNumber; private TextView issueNumber;
private ImageView issueAssigneeAvatar; private ImageView issueAssigneeAvatar;
private TextView issueTitle; private TextView issueTitle;
private TextView issueCreatedTime; private TextView issueCreatedTime;
private TextView issueCommentsCount; private TextView issueCommentsCount;
private ImageView issueType;
IssuesHolder(View itemView) { public ViewHolder(View itemView) {
super(itemView); super(itemView);
@ -119,171 +152,94 @@ public class IssuesAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
issueAssigneeAvatar = itemView.findViewById(R.id.assigneeAvatar); issueAssigneeAvatar = itemView.findViewById(R.id.assigneeAvatar);
issueTitle = itemView.findViewById(R.id.issueTitle); issueTitle = itemView.findViewById(R.id.issueTitle);
issueCommentsCount = itemView.findViewById(R.id.issueCommentsCount); issueCommentsCount = itemView.findViewById(R.id.issueCommentsCount);
LinearLayout frameCommentsCount = itemView.findViewById(R.id.frameCommentsCount);
issueCreatedTime = itemView.findViewById(R.id.issueCreatedTime); issueCreatedTime = itemView.findViewById(R.id.issueCreatedTime);
issueType = itemView.findViewById(R.id.issueType);
issueTitle.setOnClickListener(new View.OnClickListener() { }
@Override @Override
public void onClick(View v) { public void bindView(@NonNull IssuesAdapter item, @NonNull List<Object> payloads) {
Context context = v.getContext();
//Log.i("issueNumber", issueNumber.getText().toString());
Intent intent = new Intent(context, IssueDetailActivity.class);
intent.putExtra("issueNumber", issueNumber.getText());
TinyDB tinyDb = new TinyDB(context);
tinyDb.putString("issueNumber", issueNumber.getText().toString());
context.startActivity(intent);
if (!item.getUserFullname().equals("")) {
issueAssigneeAvatar.setOnClickListener(new ClickListener(ctx.getResources().getString(R.string.issueCreator) + item.getUserFullname(), ctx));
} }
}); else {
frameCommentsCount.setOnClickListener(new View.OnClickListener() { issueAssigneeAvatar.setOnClickListener(new ClickListener(ctx.getResources().getString(R.string.issueCreator) + item.getUserLogin(), ctx));
@Override
public void onClick(View v) {
Context context = v.getContext();
//Log.i("issueNumber", issueNumber.getText().toString());
Intent intent = new Intent(context, IssueDetailActivity.class);
intent.putExtra("issueNumber", issueNumber.getText());
TinyDB tinyDb = new TinyDB(context);
tinyDb.putString("issueNumber", issueNumber.getText().toString());
context.startActivity(intent);
}
});
} }
@SuppressLint("SetTextI18n") PicassoService.getInstance(ctx).get().load(item.getIssueAssigneeAvatar()).placeholder(R.drawable.loader_animated).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(issueAssigneeAvatar);
void bindData(Issues issuesModel){
final TinyDB tinyDb = new TinyDB(context); String issueNumber_ = "<font color='" + ctx.getResources().getColor(R.color.lightGray) + "'>" + ctx.getResources().getString(R.string.hash) + item.getIssueNumber() + "</font>";
final String locale = tinyDb.getString("locale"); issueTitle.setText(Html.fromHtml(issueNumber_ + " " + item.getIssueTitle()));
final String timeFormat = tinyDb.getString("dateFormat");
if (!issuesModel.getUser().getFull_name().equals("")) { issueNumber.setText(String.valueOf(item.getIssueNumber()));
issueAssigneeAvatar.setOnClickListener(new ClickListener(context.getResources().getString(R.string.issueCreator) + issuesModel.getUser().getFull_name(), context)); issueCommentsCount.setText(String.valueOf(item.getIssueCommentsCount()));
} else {
issueAssigneeAvatar.setOnClickListener(new ClickListener(context.getResources().getString(R.string.issueCreator) + issuesModel.getUser().getLogin(), context));
}
if (issuesModel.getUser().getAvatar_url() != null) {
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(8, 0)).resize(120, 120).centerCrop().into(issueAssigneeAvatar);
}
if (issuesModel.getPull_request() == null) {
issueType.setImageResource(R.drawable.ic_issues);
issueType.setOnClickListener(new ClickListener(context.getResources().getString(R.string.issueTypeIssue), context));
} else {
issueType.setImageResource(R.drawable.ic_merge);
issueType.setOnClickListener(new ClickListener(context.getResources().getString(R.string.issueTypePullRequest), context));
}
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()));
switch (timeFormat) { switch (timeFormat) {
case "pretty": { case "pretty": {
PrettyTime prettyTime = new PrettyTime(new Locale(locale)); PrettyTime prettyTime = new PrettyTime(new Locale(locale));
String createdTime = prettyTime.format(issuesModel.getCreated_at()); String createdTime = prettyTime.format(item.getIssueCreatedTime());
issueCreatedTime.setText(createdTime); issueCreatedTime.setText(createdTime);
issueCreatedTime.setOnClickListener(new ClickListener(TimeHelper.customDateFormatForToastDateFormat(issuesModel.getCreated_at()), context)); issueCreatedTime.setOnClickListener(new ClickListener(TimeHelper.customDateFormatForToastDateFormat(item.getIssueCreatedTime()), ctx));
break; break;
} }
case "normal": { case "normal": {
DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd '" + context.getResources().getString(R.string.timeAtText) + "' HH:mm", new Locale(locale)); DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd '" + ctx.getResources().getString(R.string.timeAtText) + "' HH:mm", new Locale(locale));
String createdTime = formatter.format(issuesModel.getCreated_at()); String createdTime = formatter.format(item.getIssueCreatedTime());
issueCreatedTime.setText(createdTime); issueCreatedTime.setText(createdTime);
break; break;
} }
case "normal1": { case "normal1": {
DateFormat formatter = new SimpleDateFormat("dd-MM-yyyy '" + context.getResources().getString(R.string.timeAtText) + "' HH:mm", new Locale(locale)); DateFormat formatter = new SimpleDateFormat("dd-MM-yyyy '" + ctx.getResources().getString(R.string.timeAtText) + "' HH:mm", new Locale(locale));
String createdTime = formatter.format(issuesModel.getCreated_at()); String createdTime = formatter.format(item.getIssueCreatedTime());
issueCreatedTime.setText(createdTime); issueCreatedTime.setText(createdTime);
break; break;
} }
}
} }
} }
static class LoadHolder extends RecyclerView.ViewHolder {
LoadHolder(View itemView) {
super(itemView);
}
}
public void setMoreDataAvailable(boolean moreDataAvailable) {
isMoreDataAvailable = moreDataAvailable;
}
public void notifyDataChanged() {
notifyDataSetChanged();
isLoading = false;
}
public interface OnLoadMoreListener {
void onLoadMore();
}
public void setLoadMoreListener(OnLoadMoreListener loadMoreListener) {
this.loadMoreListener = loadMoreListener;
}
@Override @Override
public Filter getFilter() { public void unbindView(@NonNull IssuesAdapter item) {
return issuesFilter;
issueTitle.setText(null);
issueCommentsCount.setText(null);
issueCreatedTime.setText(null);
} }
private Filter issuesFilter = new Filter() { }
public static class IssueTitleClickEvent extends ClickEventHook<IssuesAdapter> {
@Nullable
@Override @Override
protected FilterResults performFiltering(CharSequence constraint) { public List<View> onBindMany(@NonNull RecyclerView.ViewHolder viewHolder) {
List<Issues> filteredList = new ArrayList<>();
if (constraint == null || constraint.length() == 0) { if (viewHolder instanceof IssuesAdapter.ViewHolder) {
filteredList.addAll(issuesList); return EventHookUtil.toList(((ViewHolder) viewHolder).issueTitle);
} else {
String filterPattern = constraint.toString().toLowerCase().trim();
for (Issues item : issuesList) {
if (item.getTitle().toLowerCase().contains(filterPattern) || item.getBody().toLowerCase().contains(filterPattern)) {
filteredList.add(item);
}
}
} }
FilterResults results = new FilterResults(); return super.onBindMany(viewHolder);
results.values = filteredList;
return results;
} }
@Override @Override
protected void publishResults(CharSequence constraint, FilterResults results) { public void onClick(View v, int position, @NonNull FastAdapter<IssuesAdapter> fastAdapter, IssuesAdapter item) {
issuesList.clear();
issuesList.addAll((List) results.values); Context context = v.getContext();
notifyDataSetChanged();
} Intent intent = new Intent(context, IssueDetailActivity.class);
}; intent.putExtra("issueNumber", item.getIssueNumber());
TinyDB tinyDb = new TinyDB(context);
tinyDb.putString("issueNumber", String.valueOf(item.getIssueNumber()));
tinyDb.putString("issueType", "issue");
context.startActivity(intent);
}
}
} }

View File

@ -1,28 +1,27 @@
package org.mian.gitnex.adapters; package org.mian.gitnex.adapters;
import android.annotation.SuppressLint;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.graphics.Color; import android.graphics.Color;
import android.graphics.Typeface;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import com.amulyakhare.textdrawable.TextDrawable; import com.amulyakhare.textdrawable.TextDrawable;
import com.google.android.material.bottomsheet.BottomSheetDialog;
import org.mian.gitnex.R; import org.mian.gitnex.R;
import org.mian.gitnex.activities.CreateLabelActivity; import org.mian.gitnex.activities.CreateLabelActivity;
import org.mian.gitnex.helpers.AlertDialogs; import org.mian.gitnex.helpers.AlertDialogs;
import org.mian.gitnex.helpers.ColorInverter; import org.mian.gitnex.helpers.ColorInverter;
import org.mian.gitnex.helpers.LabelWidthCalculator; import org.mian.gitnex.helpers.LabelWidthCalculator;
import org.mian.gitnex.models.Labels; import org.mian.gitnex.models.Labels;
import java.lang.reflect.Field;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.appcompat.view.ContextThemeWrapper;
import androidx.appcompat.widget.PopupMenu;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
/** /**
@ -51,39 +50,23 @@ public class LabelsAdapter extends RecyclerView.Adapter<LabelsAdapter.LabelsView
labelId = itemView.findViewById(R.id.labelId); labelId = itemView.findViewById(R.id.labelId);
labelColor = itemView.findViewById(R.id.labelColor); labelColor = itemView.findViewById(R.id.labelColor);
labelsOptionsMenu.setOnClickListener(new View.OnClickListener() { labelsOptionsMenu.setOnClickListener(v -> {
@Override
public void onClick(View v) {
final Context context = v.getContext(); final Context context = v.getContext();
Context context_ = new ContextThemeWrapper(context, R.style.popupMenuStyle);
PopupMenu popupMenu = new PopupMenu(context_, v); @SuppressLint("InflateParams")
popupMenu.inflate(R.menu.labels_menu); View view = LayoutInflater.from(context).inflate(R.layout.bottom_sheet_labels_in_list, null);
Object menuHelper; TextView labelMenuEdit = view.findViewById(R.id.labelMenuEdit);
Class[] argTypes; TextView labelMenuDelete = view.findViewById(R.id.labelMenuDelete);
try { TextView bottomSheetHeader = view.findViewById(R.id.bottomSheetHeader);
Field fMenuHelper = PopupMenu.class.getDeclaredField("mPopup"); bottomSheetHeader.setText(labelTitle.getText());
fMenuHelper.setAccessible(true); BottomSheetDialog dialog = new BottomSheetDialog(context);
menuHelper = fMenuHelper.get(popupMenu); dialog.setContentView(view);
argTypes = new Class[] { boolean.class }; dialog.show();
menuHelper.getClass().getDeclaredMethod("setForceShowIcon",
argTypes).invoke(menuHelper, true);
} catch (Exception e) { labelMenuEdit.setOnClickListener(editLabel -> {
popupMenu.show();
return;
}
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case R.id.labelMenuEdit:
Intent intent = new Intent(context, CreateLabelActivity.class); Intent intent = new Intent(context, CreateLabelActivity.class);
intent.putExtra("labelId", labelId.getText()); intent.putExtra("labelId", labelId.getText());
@ -91,25 +74,21 @@ public class LabelsAdapter extends RecyclerView.Adapter<LabelsAdapter.LabelsView
intent.putExtra("labelColor", labelColor.getText()); intent.putExtra("labelColor", labelColor.getText());
intent.putExtra("labelAction", "edit"); intent.putExtra("labelAction", "edit");
context.startActivity(intent); context.startActivity(intent);
break; dialog.dismiss();
case R.id.labelMenuDelete: });
labelMenuDelete.setOnClickListener(deleteLabel -> {
AlertDialogs.labelDeleteDialog(context, labelTitle.getText().toString(), labelId.getText().toString(), AlertDialogs.labelDeleteDialog(context, labelTitle.getText().toString(), labelId.getText().toString(),
context.getResources().getString(R.string.labelDeleteTitle), context.getResources().getString(R.string.labelDeleteTitle),
context.getResources().getString(R.string.labelDeleteMessage), context.getResources().getString(R.string.labelDeleteMessage),
context.getResources().getString(R.string.labelDeletePositiveButton), context.getResources().getString(R.string.labelDeletePositiveButton),
context.getResources().getString(R.string.labelDeleteNegativeButton)); context.getResources().getString(R.string.labelDeleteNegativeButton));
break; dialog.dismiss();
}
return false;
}
}); });
popupMenu.show();
}
}); });
} }
@ -123,7 +102,7 @@ public class LabelsAdapter extends RecyclerView.Adapter<LabelsAdapter.LabelsView
@NonNull @NonNull
@Override @Override
public LabelsAdapter.LabelsViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { public LabelsAdapter.LabelsViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.labels_list, parent, false); View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_labels, parent, false);
return new LabelsAdapter.LabelsViewHolder(v); return new LabelsAdapter.LabelsViewHolder(v);
} }
@ -131,7 +110,6 @@ public class LabelsAdapter extends RecyclerView.Adapter<LabelsAdapter.LabelsView
public void onBindViewHolder(@NonNull LabelsAdapter.LabelsViewHolder holder, int position) { public void onBindViewHolder(@NonNull LabelsAdapter.LabelsViewHolder holder, int position) {
Labels currentItem = labelsList.get(position); Labels currentItem = labelsList.get(position);
int width = 33;
holder.labelTitle.setText(currentItem.getName()); holder.labelTitle.setText(currentItem.getName());
holder.labelId.setText(String.valueOf(currentItem.getId())); holder.labelId.setText(String.valueOf(currentItem.getId()));
@ -139,35 +117,24 @@ public class LabelsAdapter extends RecyclerView.Adapter<LabelsAdapter.LabelsView
String labelColor = currentItem.getColor(); String labelColor = currentItem.getColor();
String labelName = currentItem.getName(); String labelName = currentItem.getName();
int color = Color.parseColor("#" + labelColor); int color = Color.parseColor("#" + labelColor);
TextDrawable drawable = TextDrawable.builder() TextDrawable drawable = TextDrawable.builder()
.beginConfig() .beginConfig()
//.useFont(Typeface.DEFAULT) .useFont(Typeface.DEFAULT)
.bold() .bold()
.textColor(new ColorInverter().getContrastColor(color)) .textColor(new ColorInverter().getContrastColor(color))
.fontSize(36) .fontSize(35)
.width(LabelWidthCalculator.customWidth(getMaxLabelLength())) .width(LabelWidthCalculator.calculateLabelWidth(labelName, Typeface.DEFAULT, 40, 20))
.height(60) .height(55)
.endConfig() .endConfig()
.buildRoundRect(labelName, color, 8); .buildRoundRect(labelName, color, 10);
holder.labelsView.setImageDrawable(drawable); holder.labelsView.setImageDrawable(drawable);
} }
private int getMaxLabelLength() {
for(int i = 0; i < labelsList.size(); i++) {
Labels labelItem = labelsList.get(i);
labelsArray.add(labelItem.getName().length());
}
return Collections.max(labelsArray);
}
@Override @Override
public int getItemCount() { public int getItemCount() {
return labelsList.size(); return labelsList.size();

View File

@ -10,8 +10,8 @@ import android.widget.Filter;
import android.widget.Filterable; import android.widget.Filterable;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import com.squareup.picasso.Picasso;
import org.mian.gitnex.R; import org.mian.gitnex.R;
import org.mian.gitnex.clients.PicassoService;
import org.mian.gitnex.helpers.RoundedTransformation; import org.mian.gitnex.helpers.RoundedTransformation;
import org.mian.gitnex.models.UserInfo; import org.mian.gitnex.models.UserInfo;
import java.util.ArrayList; import java.util.ArrayList;
@ -67,7 +67,7 @@ public class MembersByOrgAdapter extends BaseAdapter implements Filterable {
MembersByOrgAdapter.ViewHolder viewHolder = null; MembersByOrgAdapter.ViewHolder viewHolder = null;
if (finalView == null) { if (finalView == null) {
finalView = LayoutInflater.from(mCtx).inflate(R.layout.members_by_org_list, null); finalView = LayoutInflater.from(mCtx).inflate(R.layout.list_members_by_org, null);
viewHolder = new MembersByOrgAdapter.ViewHolder(finalView); viewHolder = new MembersByOrgAdapter.ViewHolder(finalView);
finalView.setTag(viewHolder); finalView.setTag(viewHolder);
} }
@ -83,7 +83,7 @@ public class MembersByOrgAdapter extends BaseAdapter implements Filterable {
private void initData(MembersByOrgAdapter.ViewHolder viewHolder, int position) { private void initData(MembersByOrgAdapter.ViewHolder viewHolder, int position) {
UserInfo currentItem = membersList.get(position); UserInfo currentItem = membersList.get(position);
Picasso.get().load(currentItem.getAvatar()).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(viewHolder.memberAvatar); PicassoService.getInstance(mCtx).get().load(currentItem.getAvatar()).placeholder(R.drawable.loader_animated).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(viewHolder.memberAvatar);
if(!currentItem.getFullname().equals("")) { if(!currentItem.getFullname().equals("")) {
viewHolder.memberName.setText(currentItem.getFullname()); viewHolder.memberName.setText(currentItem.getFullname());

View File

@ -15,8 +15,10 @@ import android.widget.ImageView;
import android.widget.ProgressBar; import android.widget.ProgressBar;
import android.widget.TextView; import android.widget.TextView;
import com.amulyakhare.textdrawable.TextDrawable; import com.amulyakhare.textdrawable.TextDrawable;
import com.google.android.material.bottomsheet.BottomSheetDialog;
import com.vdurmont.emoji.EmojiParser; import com.vdurmont.emoji.EmojiParser;
import org.mian.gitnex.R; import org.mian.gitnex.R;
import org.mian.gitnex.actions.MilestoneActions;
import org.mian.gitnex.helpers.ClickListener; import org.mian.gitnex.helpers.ClickListener;
import org.mian.gitnex.helpers.TimeHelper; import org.mian.gitnex.helpers.TimeHelper;
import org.mian.gitnex.models.Milestones; import org.mian.gitnex.models.Milestones;
@ -32,7 +34,6 @@ import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Objects; import java.util.Objects;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import io.noties.markwon.AbstractMarkwonPlugin; import io.noties.markwon.AbstractMarkwonPlugin;
import io.noties.markwon.Markwon; import io.noties.markwon.Markwon;
@ -42,7 +43,6 @@ import io.noties.markwon.ext.strikethrough.StrikethroughPlugin;
import io.noties.markwon.ext.tables.TablePlugin; import io.noties.markwon.ext.tables.TablePlugin;
import io.noties.markwon.ext.tasklist.TaskListPlugin; import io.noties.markwon.ext.tasklist.TaskListPlugin;
import io.noties.markwon.html.HtmlPlugin; import io.noties.markwon.html.HtmlPlugin;
import io.noties.markwon.image.AsyncDrawable;
import io.noties.markwon.image.DefaultMediaDecoder; import io.noties.markwon.image.DefaultMediaDecoder;
import io.noties.markwon.image.ImageItem; import io.noties.markwon.image.ImageItem;
import io.noties.markwon.image.ImagesPlugin; import io.noties.markwon.image.ImagesPlugin;
@ -63,6 +63,7 @@ public class MilestonesAdapter extends RecyclerView.Adapter<MilestonesAdapter.Mi
static class MilestonesViewHolder extends RecyclerView.ViewHolder { static class MilestonesViewHolder extends RecyclerView.ViewHolder {
private TextView milestoneId;
private TextView msTitle; private TextView msTitle;
private TextView msDescription; private TextView msDescription;
private TextView msOpenIssues; private TextView msOpenIssues;
@ -70,10 +71,12 @@ public class MilestonesAdapter extends RecyclerView.Adapter<MilestonesAdapter.Mi
private TextView msDueDate; private TextView msDueDate;
private ImageView msStatus; private ImageView msStatus;
private ProgressBar msProgress; private ProgressBar msProgress;
private TextView milestoneStatus;
private MilestonesViewHolder(View itemView) { private MilestonesViewHolder(View itemView) {
super(itemView); super(itemView);
milestoneId = itemView.findViewById(R.id.milestoneId);
msTitle = itemView.findViewById(R.id.milestoneTitle); msTitle = itemView.findViewById(R.id.milestoneTitle);
msStatus = itemView.findViewById(R.id.milestoneState); msStatus = itemView.findViewById(R.id.milestoneState);
msDescription = itemView.findViewById(R.id.milestoneDescription); msDescription = itemView.findViewById(R.id.milestoneDescription);
@ -81,23 +84,52 @@ public class MilestonesAdapter extends RecyclerView.Adapter<MilestonesAdapter.Mi
msClosedIssues = itemView.findViewById(R.id.milestoneIssuesClosed); msClosedIssues = itemView.findViewById(R.id.milestoneIssuesClosed);
msDueDate = itemView.findViewById(R.id.milestoneDueDate); msDueDate = itemView.findViewById(R.id.milestoneDueDate);
msProgress = itemView.findViewById(R.id.milestoneProgress); msProgress = itemView.findViewById(R.id.milestoneProgress);
ImageView milestonesMenu = itemView.findViewById(R.id.milestonesMenu);
milestoneStatus = itemView.findViewById(R.id.milestoneStatus);
/*msTitle.setOnClickListener(new View.OnClickListener() { milestonesMenu.setOnClickListener(v -> {
@Override
public void onClick(View v) {
Context context = v.getContext(); Context ctx = v.getContext();
Log.i("issueNumber", issueNumber.getText().toString()); int milestoneId_ = Integer.parseInt(milestoneId.getText().toString());
Intent intent = new Intent(context, IssueDetailActivity.class); @SuppressLint("InflateParams") View view = LayoutInflater.from(ctx).inflate(R.layout.bottom_sheet_milestones_in_list, null);
intent.putExtra("issueNumber", issueNumber.getText());
TinyDB tinyDb = new TinyDB(context); TextView closeMilestone = view.findViewById(R.id.closeMilestone);
tinyDb.putString("issueNumber", issueNumber.getText().toString()); TextView openMilestone = view.findViewById(R.id.openMilestone);
context.startActivity(intent);
BottomSheetDialog dialog = new BottomSheetDialog(ctx);
dialog.setContentView(view);
dialog.show();
if(milestoneStatus.getText().toString().equals("open")) {
closeMilestone.setVisibility(View.VISIBLE);
openMilestone.setVisibility(View.GONE);
} }
});*/ else {
closeMilestone.setVisibility(View.GONE);
openMilestone.setVisibility(View.VISIBLE);
}
closeMilestone.setOnClickListener(v12 -> {
MilestoneActions.closeMilestone(ctx, milestoneId_);
dialog.dismiss();
});
openMilestone.setOnClickListener(v12 -> {
MilestoneActions.openMilestone(ctx, milestoneId_);
dialog.dismiss();
});
});
} }
} }
@ -110,7 +142,7 @@ public class MilestonesAdapter extends RecyclerView.Adapter<MilestonesAdapter.Mi
@NonNull @NonNull
@Override @Override
public MilestonesAdapter.MilestonesViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { public MilestonesAdapter.MilestonesViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.milestones_list, parent, false); View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_milestones, parent, false);
return new MilestonesAdapter.MilestonesViewHolder(v); return new MilestonesAdapter.MilestonesViewHolder(v);
} }
@ -123,11 +155,12 @@ public class MilestonesAdapter extends RecyclerView.Adapter<MilestonesAdapter.Mi
Milestones currentItem = milestonesList.get(position); Milestones currentItem = milestonesList.get(position);
holder.milestoneId.setText(String.valueOf(currentItem.getId()));
holder.milestoneStatus.setText(currentItem.getState());
final Markwon markwon = Markwon.builder(Objects.requireNonNull(mCtx)) final Markwon markwon = Markwon.builder(Objects.requireNonNull(mCtx))
.usePlugin(CorePlugin.create()) .usePlugin(CorePlugin.create())
.usePlugin(ImagesPlugin.create(new ImagesPlugin.ImagesConfigure() { .usePlugin(ImagesPlugin.create(plugin -> {
@Override
public void configureImages(@NonNull ImagesPlugin plugin) {
plugin.addSchemeHandler(new SchemeHandler() { plugin.addSchemeHandler(new SchemeHandler() {
@NonNull @NonNull
@Override @Override
@ -150,19 +183,12 @@ public class MilestonesAdapter extends RecyclerView.Adapter<MilestonesAdapter.Mi
return Collections.singleton("drawable"); return Collections.singleton("drawable");
} }
}); });
plugin.placeholderProvider(new ImagesPlugin.PlaceholderProvider() { plugin.placeholderProvider(drawable -> null);
@Nullable
@Override
public Drawable providePlaceholder(@NonNull AsyncDrawable drawable) {
return null;
}
});
plugin.addMediaDecoder(GifMediaDecoder.create(false)); plugin.addMediaDecoder(GifMediaDecoder.create(false));
plugin.addMediaDecoder(SvgMediaDecoder.create(mCtx.getResources())); plugin.addMediaDecoder(SvgMediaDecoder.create(mCtx.getResources()));
plugin.addMediaDecoder(SvgMediaDecoder.create()); plugin.addMediaDecoder(SvgMediaDecoder.create());
plugin.defaultMediaDecoder(DefaultMediaDecoder.create(mCtx.getResources())); plugin.defaultMediaDecoder(DefaultMediaDecoder.create(mCtx.getResources()));
plugin.defaultMediaDecoder(DefaultMediaDecoder.create()); plugin.defaultMediaDecoder(DefaultMediaDecoder.create());
}
})) }))
.usePlugin(new AbstractMarkwonPlugin() { .usePlugin(new AbstractMarkwonPlugin() {
@Override @Override
@ -182,7 +208,6 @@ public class MilestonesAdapter extends RecyclerView.Adapter<MilestonesAdapter.Mi
Spanned msTitle = markwon.toMarkdown(currentItem.getTitle()); Spanned msTitle = markwon.toMarkdown(currentItem.getTitle());
markwon.setParsedMarkdown(holder.msTitle, msTitle); markwon.setParsedMarkdown(holder.msTitle, msTitle);
//holder.msStatus.setText(currentItem.getState());
if(currentItem.getState().equals("open")) { if(currentItem.getState().equals("open")) {
@ -224,7 +249,7 @@ public class MilestonesAdapter extends RecyclerView.Adapter<MilestonesAdapter.Mi
holder.msDescription.setText(bodyWithMD); holder.msDescription.setText(bodyWithMD);
} }
else { else {
holder.msDescription.setVisibility(View.GONE); holder.msDescription.setText("");
} }
holder.msOpenIssues.setText(String.valueOf(currentItem.getOpen_issues())); holder.msOpenIssues.setText(String.valueOf(currentItem.getOpen_issues()));
@ -261,13 +286,14 @@ public class MilestonesAdapter extends RecyclerView.Adapter<MilestonesAdapter.Mi
} catch (ParseException e) { } catch (ParseException e) {
e.printStackTrace(); e.printStackTrace();
} }
String dueDate = formatter.format(date);
assert date != null; assert date != null;
String dueDate = formatter.format(date);
if(date.before(new Date())) { if(date.before(new Date())) {
holder.msDueDate.setTextColor(mCtx.getResources().getColor(R.color.darkRed)); holder.msDueDate.setTextColor(mCtx.getResources().getColor(R.color.darkRed));
} }
holder.msDueDate.setText(dueDate); holder.msDueDate.setText(mCtx.getResources().getString(R.string.dueDate, dueDate));
holder.msDueDate.setOnClickListener(new ClickListener(TimeHelper.customDateFormatForToast(currentItem.getDue_on()), mCtx)); holder.msDueDate.setOnClickListener(new ClickListener(TimeHelper.customDateFormatForToast(currentItem.getDue_on()), mCtx));
} else if (timeFormat.equals("normal1")) { } else if (timeFormat.equals("normal1")) {
@ -278,13 +304,14 @@ public class MilestonesAdapter extends RecyclerView.Adapter<MilestonesAdapter.Mi
} catch (ParseException e) { } catch (ParseException e) {
e.printStackTrace(); e.printStackTrace();
} }
assert date1 != null;
String dueDate = formatter.format(date1); String dueDate = formatter.format(date1);
holder.msDueDate.setText(dueDate); holder.msDueDate.setText(mCtx.getResources().getString(R.string.dueDate, dueDate));
} }
} }
else { else {
holder.msDueDate.setVisibility(View.GONE); holder.msDueDate.setText("");
} }
} }
@ -300,6 +327,7 @@ public class MilestonesAdapter extends RecyclerView.Adapter<MilestonesAdapter.Mi
} }
private Filter milestoneFilter = new Filter() { private Filter milestoneFilter = new Filter() {
@Override @Override
protected FilterResults performFiltering(CharSequence constraint) { protected FilterResults performFiltering(CharSequence constraint) {
List<Milestones> filteredList = new ArrayList<>(); List<Milestones> filteredList = new ArrayList<>();
@ -328,6 +356,7 @@ public class MilestonesAdapter extends RecyclerView.Adapter<MilestonesAdapter.Mi
milestonesList.addAll((List) results.values); milestonesList.addAll((List) results.values);
notifyDataSetChanged(); notifyDataSetChanged();
} }
}; };
} }

View File

@ -1,10 +1,10 @@
package org.mian.gitnex.adapters; package org.mian.gitnex.adapters;
import android.annotation.SuppressLint;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.graphics.Typeface; import android.graphics.Typeface;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.Filter; import android.widget.Filter;
@ -13,22 +13,25 @@ import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import com.amulyakhare.textdrawable.TextDrawable; import com.amulyakhare.textdrawable.TextDrawable;
import com.amulyakhare.textdrawable.util.ColorGenerator; import com.amulyakhare.textdrawable.util.ColorGenerator;
import com.squareup.picasso.Picasso; import com.google.android.material.bottomsheet.BottomSheetDialog;
import org.mian.gitnex.R; import org.mian.gitnex.R;
import org.mian.gitnex.activities.OpenRepoInBrowserActivity; import org.mian.gitnex.activities.OpenRepoInBrowserActivity;
import org.mian.gitnex.activities.RepoDetailActivity; import org.mian.gitnex.activities.RepoDetailActivity;
import org.mian.gitnex.activities.RepoStargazersActivity; import org.mian.gitnex.activities.RepoStargazersActivity;
import org.mian.gitnex.activities.RepoWatchersActivity; import org.mian.gitnex.activities.RepoWatchersActivity;
import org.mian.gitnex.clients.PicassoService;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.helpers.RoundedTransformation; import org.mian.gitnex.helpers.RoundedTransformation;
import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.models.UserRepositories; import org.mian.gitnex.models.UserRepositories;
import org.mian.gitnex.models.WatchRepository;
import org.mian.gitnex.util.TinyDB; import org.mian.gitnex.util.TinyDB;
import java.lang.reflect.Field;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.appcompat.view.ContextThemeWrapper;
import androidx.appcompat.widget.PopupMenu;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import retrofit2.Call;
import retrofit2.Callback;
/** /**
* Author M M Arif * Author M M Arif
@ -50,6 +53,7 @@ public class MyReposListAdapter extends RecyclerView.Adapter<MyReposListAdapter.
private TextView repoStarsMy; private TextView repoStarsMy;
private TextView repoForksMy; private TextView repoForksMy;
private TextView repoOpenIssuesCountMy; private TextView repoOpenIssuesCountMy;
private TextView repoType;
private MyReposViewHolder(View itemView) { private MyReposViewHolder(View itemView) {
super(itemView); super(itemView);
@ -62,10 +66,9 @@ public class MyReposListAdapter extends RecyclerView.Adapter<MyReposListAdapter.
repoForksMy = itemView.findViewById(R.id.repoForksMy); repoForksMy = itemView.findViewById(R.id.repoForksMy);
repoOpenIssuesCountMy = itemView.findViewById(R.id.repoOpenIssuesCountMy); repoOpenIssuesCountMy = itemView.findViewById(R.id.repoOpenIssuesCountMy);
ImageView reposDropdownMenu = itemView.findViewById(R.id.reposDropdownMenu); ImageView reposDropdownMenu = itemView.findViewById(R.id.reposDropdownMenu);
repoType = itemView.findViewById(R.id.repoType);
itemView.setOnClickListener(new View.OnClickListener() { itemView.setOnClickListener(v -> {
@Override
public void onClick(View v) {
Context context = v.getContext(); Context context = v.getContext();
@ -74,73 +77,105 @@ public class MyReposListAdapter extends RecyclerView.Adapter<MyReposListAdapter.
TinyDB tinyDb = new TinyDB(context); TinyDB tinyDb = new TinyDB(context);
tinyDb.putString("repoFullName", fullNameMy.getText().toString()); tinyDb.putString("repoFullName", fullNameMy.getText().toString());
tinyDb.putBoolean("resumeIssues", true); tinyDb.putString("repoType", repoType.getText().toString());
context.startActivity(intent); //tinyDb.putBoolean("resumeIssues", true);
//store if user is watching this repo
{
final String instanceUrl = tinyDb.getString("instanceUrl");
String[] parts = fullNameMy.getText().toString().split("/");
final String repoOwner = parts[0];
final String repoName = parts[1];
final String token = "token " + tinyDb.getString(tinyDb.getString("loginUid") + "-token");
WatchRepository watch = new WatchRepository();
Call<WatchRepository> call;
call = RetrofitClient.getInstance(instanceUrl, context).getApiInterface().checkRepoWatchStatus(token, repoOwner, repoName);
call.enqueue(new Callback<WatchRepository>() {
@Override
public void onResponse(@NonNull Call<WatchRepository> call, @NonNull retrofit2.Response<WatchRepository> response) {
if(response.isSuccessful()) {
assert response.body() != null;
tinyDb.putBoolean("repoWatch", response.body().getSubscribed());
} else {
tinyDb.putBoolean("repoWatch", false);
if(response.code() != 404) {
Toasty.info(context, context.getString(R.string.genericApiStatusError));
}
}
}
@Override
public void onFailure(@NonNull Call<WatchRepository> call, @NonNull Throwable t) {
tinyDb.putBoolean("repoWatch", false);
Toasty.info(context, context.getString(R.string.genericApiStatusError));
} }
}); });
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); context.startActivity(intent);
break;
case R.id.repoWatchers: });
Intent intentW = new Intent(context, RepoWatchersActivity.class); reposDropdownMenu.setOnClickListener(v -> {
intentW.putExtra("repoFullNameForWatchers", fullNameMy.getText());
context.startActivity(intentW);
break;
case R.id.repoOpenInBrowser: final Context context = v.getContext();
@SuppressLint("InflateParams")
View view = LayoutInflater.from(context).inflate(R.layout.bottom_sheet_repository_in_list, null);
TextView repoOpenInBrowser = view.findViewById(R.id.repoOpenInBrowser);
TextView repoStargazers = view.findViewById(R.id.repoStargazers);
TextView repoWatchers = view.findViewById(R.id.repoWatchers);
TextView bottomSheetHeader = view.findViewById(R.id.bottomSheetHeader);
bottomSheetHeader.setText(fullNameMy.getText());
BottomSheetDialog dialog = new BottomSheetDialog(context);
dialog.setContentView(view);
dialog.show();
repoOpenInBrowser.setOnClickListener(openInBrowser -> {
Intent intentOpenInBrowser = new Intent(context, OpenRepoInBrowserActivity.class); Intent intentOpenInBrowser = new Intent(context, OpenRepoInBrowserActivity.class);
intentOpenInBrowser.putExtra("repoFullNameBrowser", fullNameMy.getText()); intentOpenInBrowser.putExtra("repoFullNameBrowser", fullNameMy.getText());
context.startActivity(intentOpenInBrowser); context.startActivity(intentOpenInBrowser);
break; dialog.dismiss();
}
return false;
}
}); });
popupMenu.show(); repoStargazers.setOnClickListener(stargazers -> {
Intent intent = new Intent(context, RepoStargazersActivity.class);
intent.putExtra("repoFullNameForStars", fullNameMy.getText());
context.startActivity(intent);
dialog.dismiss();
});
repoWatchers.setOnClickListener(watchers -> {
Intent intentW = new Intent(context, RepoWatchersActivity.class);
intentW.putExtra("repoFullNameForWatchers", fullNameMy.getText());
context.startActivity(intentW);
dialog.dismiss();
});
}
}); });
} }
@ -155,7 +190,7 @@ public class MyReposListAdapter extends RecyclerView.Adapter<MyReposListAdapter.
@NonNull @NonNull
@Override @Override
public MyReposListAdapter.MyReposViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { public MyReposListAdapter.MyReposViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.my_repos_list, parent, false); View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_my_repos, parent, false);
return new MyReposListAdapter.MyReposViewHolder(v); return new MyReposListAdapter.MyReposViewHolder(v);
} }
@ -181,7 +216,7 @@ public class MyReposListAdapter extends RecyclerView.Adapter<MyReposListAdapter.
if (currentItem.getAvatar_url() != null) { if (currentItem.getAvatar_url() != null) {
if (!currentItem.getAvatar_url().equals("")) { if (!currentItem.getAvatar_url().equals("")) {
Picasso.get().load(currentItem.getAvatar_url()).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(holder.imageMy); PicassoService.getInstance(mCtx).get().load(currentItem.getAvatar_url()).placeholder(R.drawable.loader_animated).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(holder.imageMy);
} else { } else {
holder.imageMy.setImageDrawable(drawable); holder.imageMy.setImageDrawable(drawable);
} }
@ -198,9 +233,11 @@ public class MyReposListAdapter extends RecyclerView.Adapter<MyReposListAdapter.
holder.fullNameMy.setText(currentItem.getFullname()); holder.fullNameMy.setText(currentItem.getFullname());
if(currentItem.getPrivateFlag()) { if(currentItem.getPrivateFlag()) {
holder.repoPrivatePublicMy.setImageResource(R.drawable.ic_lock_bold); holder.repoPrivatePublicMy.setImageResource(R.drawable.ic_lock_bold);
holder.repoType.setText(R.string.strPrivate);
} }
else { else {
holder.repoPrivatePublicMy.setImageResource(R.drawable.ic_public); holder.repoPrivatePublicMy.setImageResource(R.drawable.ic_public);
holder.repoType.setText(R.string.strPublic);
} }
holder.repoStarsMy.setText(currentItem.getStars_count()); holder.repoStarsMy.setText(currentItem.getStars_count());
holder.repoForksMy.setText(currentItem.getForks_count()); holder.repoForksMy.setText(currentItem.getForks_count());

View File

@ -2,6 +2,7 @@ package org.mian.gitnex.adapters;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import android.annotation.SuppressLint;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.view.LayoutInflater; import android.view.LayoutInflater;
@ -11,9 +12,9 @@ import android.widget.Filter;
import android.widget.Filterable; import android.widget.Filterable;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import com.squareup.picasso.Picasso;
import org.mian.gitnex.R; import org.mian.gitnex.R;
import org.mian.gitnex.activities.OrgDetailActivity; import org.mian.gitnex.activities.OrganizationDetailActivity;
import org.mian.gitnex.clients.PicassoService;
import org.mian.gitnex.models.UserOrganizations; import org.mian.gitnex.models.UserOrganizations;
import org.mian.gitnex.helpers.RoundedTransformation; import org.mian.gitnex.helpers.RoundedTransformation;
import org.mian.gitnex.util.TinyDB; import org.mian.gitnex.util.TinyDB;
@ -35,23 +36,27 @@ public class OrganizationsListAdapter extends RecyclerView.Adapter<Organizations
private ImageView image; private ImageView image;
private TextView mTextView1; private TextView mTextView1;
private TextView mTextView2; private TextView mTextView2;
private TextView organizationId;
private OrganizationsViewHolder(View itemView) { private OrganizationsViewHolder(View itemView) {
super(itemView); super(itemView);
mTextView1 = itemView.findViewById(R.id.orgUsername); mTextView1 = itemView.findViewById(R.id.orgUsername);
mTextView2 = itemView.findViewById(R.id.orgDescription); mTextView2 = itemView.findViewById(R.id.orgDescription);
image = itemView.findViewById(R.id.imageAvatar); image = itemView.findViewById(R.id.imageAvatar);
organizationId = itemView.findViewById(R.id.organizationId);
itemView.setOnClickListener(new View.OnClickListener() { itemView.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
Context context = v.getContext(); Context context = v.getContext();
Intent intent = new Intent(context, OrgDetailActivity.class); Intent intent = new Intent(context, OrganizationDetailActivity.class);
intent.putExtra("orgName", mTextView1.getText().toString()); intent.putExtra("orgName", mTextView1.getText().toString());
TinyDB tinyDb = new TinyDB(context); TinyDB tinyDb = new TinyDB(context);
tinyDb.putString("orgName", mTextView1.getText().toString()); tinyDb.putString("orgName", mTextView1.getText().toString());
tinyDb.putString("organizationId", organizationId.getText().toString());
tinyDb.putBoolean("organizationAction", true);
context.startActivity(intent); context.startActivity(intent);
} }
@ -69,17 +74,19 @@ public class OrganizationsListAdapter extends RecyclerView.Adapter<Organizations
@NonNull @NonNull
@Override @Override
public OrganizationsViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { public OrganizationsViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.organizations_list, parent, false); View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_organizations, parent, false);
return new OrganizationsViewHolder(v); return new OrganizationsViewHolder(v);
} }
@SuppressLint("SetTextI18n")
@Override @Override
public void onBindViewHolder(@NonNull OrganizationsViewHolder holder, int position) { public void onBindViewHolder(@NonNull OrganizationsViewHolder holder, int position) {
UserOrganizations currentItem = orgList.get(position); UserOrganizations currentItem = orgList.get(position);
holder.mTextView2.setVisibility(View.GONE); holder.mTextView2.setVisibility(View.GONE);
holder.organizationId.setText(Integer.toString(currentItem.getId()));
Picasso.get().load(currentItem.getAvatar_url()).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(holder.image); PicassoService.getInstance(mCtx).get().load(currentItem.getAvatar_url()).placeholder(R.drawable.loader_animated).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(holder.image);
holder.mTextView1.setText(currentItem.getUsername()); holder.mTextView1.setText(currentItem.getUsername());
if (!currentItem.getDescription().equals("")) { if (!currentItem.getDescription().equals("")) {
holder.mTextView2.setVisibility(View.VISIBLE); holder.mTextView2.setVisibility(View.VISIBLE);

View File

@ -44,7 +44,7 @@ public class ProfileEmailsAdapter extends RecyclerView.Adapter<ProfileEmailsAdap
@NonNull @NonNull
@Override @Override
public ProfileEmailsAdapter.EmailsViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { public ProfileEmailsAdapter.EmailsViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.profile_emails_list, parent, false); View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_profile_emails, parent, false);
return new ProfileEmailsAdapter.EmailsViewHolder(v); return new ProfileEmailsAdapter.EmailsViewHolder(v);
} }

View File

@ -6,8 +6,8 @@ import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import com.squareup.picasso.Picasso;
import org.mian.gitnex.R; import org.mian.gitnex.R;
import org.mian.gitnex.clients.PicassoService;
import org.mian.gitnex.helpers.RoundedTransformation; import org.mian.gitnex.helpers.RoundedTransformation;
import org.mian.gitnex.models.UserInfo; import org.mian.gitnex.models.UserInfo;
import java.util.List; import java.util.List;
@ -47,7 +47,7 @@ public class ProfileFollowersAdapter extends RecyclerView.Adapter<ProfileFollowe
@NonNull @NonNull
@Override @Override
public ProfileFollowersAdapter.FollowersViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { public ProfileFollowersAdapter.FollowersViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.profile_followers_list, parent, false); View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_profile_followers, parent, false);
return new ProfileFollowersAdapter.FollowersViewHolder(v); return new ProfileFollowersAdapter.FollowersViewHolder(v);
} }
@ -65,7 +65,7 @@ public class ProfileFollowersAdapter extends RecyclerView.Adapter<ProfileFollowe
holder.userName.setVisibility(View.GONE); holder.userName.setVisibility(View.GONE);
} }
Picasso.get().load(currentItem.getAvatar()).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(holder.userAvatar); PicassoService.getInstance(mCtx).get().load(currentItem.getAvatar()).placeholder(R.drawable.loader_animated).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(holder.userAvatar);
} }
@Override @Override

View File

@ -6,8 +6,8 @@ import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import com.squareup.picasso.Picasso;
import org.mian.gitnex.R; import org.mian.gitnex.R;
import org.mian.gitnex.clients.PicassoService;
import org.mian.gitnex.helpers.RoundedTransformation; import org.mian.gitnex.helpers.RoundedTransformation;
import org.mian.gitnex.models.UserInfo; import org.mian.gitnex.models.UserInfo;
import java.util.List; import java.util.List;
@ -47,7 +47,7 @@ public class ProfileFollowingAdapter extends RecyclerView.Adapter<ProfileFollowi
@NonNull @NonNull
@Override @Override
public ProfileFollowingAdapter.FollowingViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { public ProfileFollowingAdapter.FollowingViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.profile_following_list, parent, false); View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_profile_following, parent, false);
return new ProfileFollowingAdapter.FollowingViewHolder(v); return new ProfileFollowingAdapter.FollowingViewHolder(v);
} }
@ -65,7 +65,7 @@ public class ProfileFollowingAdapter extends RecyclerView.Adapter<ProfileFollowi
holder.userName.setVisibility(View.GONE); holder.userName.setVisibility(View.GONE);
} }
Picasso.get().load(currentItem.getAvatar()).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(holder.userAvatar); PicassoService.getInstance(mCtx).get().load(currentItem.getAvatar()).placeholder(R.drawable.loader_animated).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(holder.userAvatar);
} }
@Override @Override

View File

@ -0,0 +1,263 @@
package org.mian.gitnex.adapters;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
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 androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import org.mian.gitnex.R;
import org.mian.gitnex.activities.IssueDetailActivity;
import org.mian.gitnex.clients.PicassoService;
import org.mian.gitnex.helpers.ClickListener;
import org.mian.gitnex.helpers.RoundedTransformation;
import org.mian.gitnex.helpers.TimeHelper;
import org.mian.gitnex.models.PullRequests;
import org.mian.gitnex.util.TinyDB;
import org.ocpsoft.prettytime.PrettyTime;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
/**
* Author M M Arif
*/
public class PullRequestsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> implements Filterable {
private Context context;
private final int TYPE_LOAD = 0;
private List<PullRequests> prList;
private List<PullRequests> prListFull;
private PullRequestsAdapter.OnLoadMoreListener loadMoreListener;
private boolean isLoading = false, isMoreDataAvailable = true;
public PullRequestsAdapter(Context context, List<PullRequests> prListMain) {
this.context = context;
this.prList = prListMain;
prListFull = new ArrayList<>(prList);
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(context);
if(viewType == TYPE_LOAD){
return new PullRequestsAdapter.PullRequestsHolder(inflater.inflate(R.layout.list_pr, parent,false));
}
else {
return new PullRequestsAdapter.LoadHolder(inflater.inflate(R.layout.row_load,parent,false));
}
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
if(position >= getItemCount()-1 && isMoreDataAvailable && !isLoading && loadMoreListener!=null) {
isLoading = true;
loadMoreListener.onLoadMore();
}
if(getItemViewType(position) == TYPE_LOAD) {
((PullRequestsAdapter.PullRequestsHolder)holder).bindData(prList.get(position));
}
}
@Override
public int getItemViewType(int position) {
if(prList.get(position).getTitle() != null) {
return TYPE_LOAD;
}
else {
return 1;
}
}
@Override
public int getItemCount() {
return prList.size();
}
class PullRequestsHolder extends RecyclerView.ViewHolder {
private TextView prNumber;
private ImageView assigneeAvatar;
private TextView prTitle;
private TextView prCreatedTime;
private TextView prCommentsCount;
PullRequestsHolder(View itemView) {
super(itemView);
prNumber = itemView.findViewById(R.id.prNumber);
assigneeAvatar = itemView.findViewById(R.id.assigneeAvatar);
prTitle = itemView.findViewById(R.id.prTitle);
prCommentsCount = itemView.findViewById(R.id.prCommentsCount);
LinearLayout frameCommentsCount = itemView.findViewById(R.id.frameCommentsCount);
prCreatedTime = itemView.findViewById(R.id.prCreatedTime);
prTitle.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Context context = v.getContext();
Intent intent = new Intent(context, IssueDetailActivity.class);
intent.putExtra("issueNumber", prNumber.getText());
TinyDB tinyDb = new TinyDB(context);
tinyDb.putString("issueNumber", prNumber.getText().toString());
tinyDb.putString("issueType", "pr");
context.startActivity(intent);
}
});
frameCommentsCount.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Context context = v.getContext();
Intent intent = new Intent(context, IssueDetailActivity.class);
intent.putExtra("issueNumber", prNumber.getText());
TinyDB tinyDb = new TinyDB(context);
tinyDb.putString("issueNumber", prNumber.getText().toString());
tinyDb.putString("issueType", "pr");
context.startActivity(intent);
}
});
}
@SuppressLint("SetTextI18n")
void bindData(PullRequests prModel){
final TinyDB tinyDb = new TinyDB(context);
final String locale = tinyDb.getString("locale");
final String timeFormat = tinyDb.getString("dateFormat");
if (!prModel.getUser().getFull_name().equals("")) {
assigneeAvatar.setOnClickListener(new ClickListener(context.getResources().getString(R.string.prCreator) + prModel.getUser().getFull_name(), context));
} else {
assigneeAvatar.setOnClickListener(new ClickListener(context.getResources().getString(R.string.prCreator) + prModel.getUser().getLogin(), context));
}
if (prModel.getUser().getAvatar_url() != null) {
PicassoService.getInstance(context).get().load(prModel.getUser().getAvatar_url()).placeholder(R.drawable.loader_animated).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(assigneeAvatar);
} else {
PicassoService.getInstance(context).get().load(prModel.getUser().getAvatar_url()).placeholder(R.drawable.loader_animated).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(assigneeAvatar);
}
String prNumber_ = "<font color='" + context.getResources().getColor(R.color.lightGray) + "'>" + context.getResources().getString(R.string.hash) + prModel.getNumber() + "</font>";
prTitle.setText(Html.fromHtml(prNumber_ + " " + prModel.getTitle()));
prNumber.setText(String.valueOf(prModel.getNumber()));
prCommentsCount.setText(String.valueOf(prModel.getComments()));
prCreatedTime.setText(TimeHelper.formatTime(prModel.getCreated_at(), new Locale(locale), timeFormat, context));
if(timeFormat.equals("pretty")) {
prCreatedTime.setOnClickListener(new ClickListener(TimeHelper.customDateFormatForToastDateFormat(prModel.getCreated_at()), context));
}
}
}
static class LoadHolder extends RecyclerView.ViewHolder {
LoadHolder(View itemView) {
super(itemView);
}
}
public void setMoreDataAvailable(boolean moreDataAvailable) {
isMoreDataAvailable = moreDataAvailable;
}
public void notifyDataChanged() {
notifyDataSetChanged();
isLoading = false;
}
public interface OnLoadMoreListener {
void onLoadMore();
}
public void setLoadMoreListener(PullRequestsAdapter.OnLoadMoreListener loadMoreListener) {
this.loadMoreListener = loadMoreListener;
}
@Override
public Filter getFilter() {
return prFilter;
}
private Filter prFilter = new Filter() {
@Override
protected FilterResults performFiltering(CharSequence constraint) {
List<PullRequests> filteredList = new ArrayList<>();
if (constraint == null || constraint.length() == 0) {
filteredList.addAll(prList);
} else {
String filterPattern = constraint.toString().toLowerCase().trim();
for (PullRequests item : prList) {
if (item.getTitle().toLowerCase().contains(filterPattern) || item.getBody().toLowerCase().contains(filterPattern)) {
filteredList.add(item);
}
}
}
FilterResults results = new FilterResults();
results.values = filteredList;
return results;
}
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
prList.clear();
prList.addAll((List) results.values);
notifyDataSetChanged();
}
};
}

View File

@ -80,7 +80,7 @@ public class ReleasesAdapter extends RecyclerView.Adapter<ReleasesAdapter.Releas
@NonNull @NonNull
@Override @Override
public ReleasesAdapter.ReleasesViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { public ReleasesAdapter.ReleasesViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.releases_list, parent, false); View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_releases, parent, false);
return new ReleasesAdapter.ReleasesViewHolder(v); return new ReleasesAdapter.ReleasesViewHolder(v);
} }

View File

@ -2,16 +2,18 @@ package org.mian.gitnex.adapters;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.content.Context; import android.content.Context;
import android.graphics.Typeface;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.BaseAdapter; import android.widget.BaseAdapter;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import com.squareup.picasso.Picasso;
import org.mian.gitnex.R; import org.mian.gitnex.R;
import org.mian.gitnex.clients.PicassoService;
import org.mian.gitnex.helpers.RoundedTransformation; import org.mian.gitnex.helpers.RoundedTransformation;
import org.mian.gitnex.models.UserInfo; import org.mian.gitnex.models.UserInfo;
import org.mian.gitnex.util.TinyDB;
import java.util.List; import java.util.List;
/** /**
@ -23,7 +25,7 @@ public class RepoStargazersAdapter extends BaseAdapter {
private List<UserInfo> stargazersList; private List<UserInfo> stargazersList;
private Context mCtx; private Context mCtx;
private class ViewHolder { private static class ViewHolder {
private ImageView memberAvatar; private ImageView memberAvatar;
private TextView memberName; private TextView memberName;
@ -61,8 +63,8 @@ public class RepoStargazersAdapter extends BaseAdapter {
RepoStargazersAdapter.ViewHolder viewHolder; RepoStargazersAdapter.ViewHolder viewHolder;
if (finalView == null) { if (finalView == null) {
finalView = LayoutInflater.from(mCtx).inflate(R.layout.repo_stargazers_list, null); finalView = LayoutInflater.from(mCtx).inflate(R.layout.list_repo_stargazers, null);
viewHolder = new RepoStargazersAdapter.ViewHolder(finalView); viewHolder = new ViewHolder(finalView);
finalView.setTag(viewHolder); finalView.setTag(viewHolder);
} }
else { else {
@ -77,13 +79,41 @@ public class RepoStargazersAdapter extends BaseAdapter {
private void initData(RepoStargazersAdapter.ViewHolder viewHolder, int position) { private void initData(RepoStargazersAdapter.ViewHolder viewHolder, int position) {
UserInfo currentItem = stargazersList.get(position); UserInfo currentItem = stargazersList.get(position);
Picasso.get().load(currentItem.getAvatar()).transform(new RoundedTransformation(8, 0)).resize(180, 180).centerCrop().into(viewHolder.memberAvatar); PicassoService.getInstance(mCtx).get().load(currentItem.getAvatar()).placeholder(R.drawable.loader_animated).transform(new RoundedTransformation(8, 0)).resize(180, 180).centerCrop().into(viewHolder.memberAvatar);
final TinyDB tinyDb = new TinyDB(mCtx);
Typeface myTypeface;
switch(tinyDb.getInt("customFontId", -1)) {
case 0:
myTypeface = Typeface.createFromAsset(mCtx.getAssets(), "fonts/roboto.ttf");
break;
case 2:
myTypeface = Typeface.createFromAsset(mCtx.getAssets(), "fonts/sourcecodeproregular.ttf");
break;
default:
myTypeface = Typeface.createFromAsset(mCtx.getAssets(), "fonts/manroperegular.ttf");
break;
}
if(!currentItem.getFullname().equals("")) { if(!currentItem.getFullname().equals("")) {
viewHolder.memberName.setText(currentItem.getFullname()); viewHolder.memberName.setText(currentItem.getFullname());
viewHolder.memberName.setTypeface(myTypeface);
} }
else { else {
viewHolder.memberName.setText(currentItem.getLogin()); viewHolder.memberName.setText(currentItem.getLogin());
viewHolder.memberName.setTypeface(myTypeface);
}
if(tinyDb.getInt("themeId") == 1) { //light
viewHolder.memberName.setTextColor(mCtx.getResources().getColor(R.color.lightThemeTextColor));
}
else { // dark
viewHolder.memberName.setTextColor(mCtx.getResources().getColor(R.color.white));
} }
} }

View File

@ -2,16 +2,18 @@ package org.mian.gitnex.adapters;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.content.Context; import android.content.Context;
import android.graphics.Typeface;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.BaseAdapter; import android.widget.BaseAdapter;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import com.squareup.picasso.Picasso;
import org.mian.gitnex.R; import org.mian.gitnex.R;
import org.mian.gitnex.clients.PicassoService;
import org.mian.gitnex.helpers.RoundedTransformation; import org.mian.gitnex.helpers.RoundedTransformation;
import org.mian.gitnex.models.UserInfo; import org.mian.gitnex.models.UserInfo;
import org.mian.gitnex.util.TinyDB;
import java.util.List; import java.util.List;
/** /**
@ -23,7 +25,7 @@ public class RepoWatchersAdapter extends BaseAdapter {
private List<UserInfo> watchersList; private List<UserInfo> watchersList;
private Context mCtx; private Context mCtx;
private class ViewHolder { private static class ViewHolder {
private ImageView memberAvatar; private ImageView memberAvatar;
private TextView memberName; private TextView memberName;
@ -61,8 +63,8 @@ public class RepoWatchersAdapter extends BaseAdapter {
RepoWatchersAdapter.ViewHolder viewHolder; RepoWatchersAdapter.ViewHolder viewHolder;
if (finalView == null) { if (finalView == null) {
finalView = LayoutInflater.from(mCtx).inflate(R.layout.repo_watchers_list, null); finalView = LayoutInflater.from(mCtx).inflate(R.layout.list_repo_watchers, null);
viewHolder = new RepoWatchersAdapter.ViewHolder(finalView); viewHolder = new ViewHolder(finalView);
finalView.setTag(viewHolder); finalView.setTag(viewHolder);
} }
else { else {
@ -77,13 +79,41 @@ public class RepoWatchersAdapter extends BaseAdapter {
private void initData(RepoWatchersAdapter.ViewHolder viewHolder, int position) { private void initData(RepoWatchersAdapter.ViewHolder viewHolder, int position) {
UserInfo currentItem = watchersList.get(position); UserInfo currentItem = watchersList.get(position);
Picasso.get().load(currentItem.getAvatar()).transform(new RoundedTransformation(8, 0)).resize(180, 180).centerCrop().into(viewHolder.memberAvatar); PicassoService.getInstance(mCtx).get().load(currentItem.getAvatar()).placeholder(R.drawable.loader_animated).transform(new RoundedTransformation(8, 0)).resize(180, 180).centerCrop().into(viewHolder.memberAvatar);
final TinyDB tinyDb = new TinyDB(mCtx);
Typeface myTypeface;
switch(tinyDb.getInt("customFontId", -1)) {
case 0:
myTypeface = Typeface.createFromAsset(mCtx.getAssets(), "fonts/roboto.ttf");
break;
case 2:
myTypeface = Typeface.createFromAsset(mCtx.getAssets(), "fonts/sourcecodeproregular.ttf");
break;
default:
myTypeface = Typeface.createFromAsset(mCtx.getAssets(), "fonts/manroperegular.ttf");
break;
}
if(!currentItem.getFullname().equals("")) { if(!currentItem.getFullname().equals("")) {
viewHolder.memberName.setText(currentItem.getFullname()); viewHolder.memberName.setText(currentItem.getFullname());
viewHolder.memberName.setTypeface(myTypeface);
} }
else { else {
viewHolder.memberName.setText(currentItem.getLogin()); viewHolder.memberName.setText(currentItem.getLogin());
viewHolder.memberName.setTypeface(myTypeface);
}
if(tinyDb.getInt("themeId") == 1) { //light
viewHolder.memberName.setTextColor(mCtx.getResources().getColor(R.color.lightThemeTextColor));
}
else { // dark
viewHolder.memberName.setTextColor(mCtx.getResources().getColor(R.color.white));
} }
} }

View File

@ -1,34 +1,38 @@
package org.mian.gitnex.adapters; package org.mian.gitnex.adapters;
import android.annotation.SuppressLint;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.graphics.Typeface; 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.LayoutInflater;
import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.Filter; import android.widget.Filter;
import android.widget.Filterable; import android.widget.Filterable;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.amulyakhare.textdrawable.TextDrawable; import com.amulyakhare.textdrawable.TextDrawable;
import com.amulyakhare.textdrawable.util.ColorGenerator; import com.amulyakhare.textdrawable.util.ColorGenerator;
import com.squareup.picasso.Picasso; import com.google.android.material.bottomsheet.BottomSheetDialog;
import org.mian.gitnex.R; import org.mian.gitnex.R;
import org.mian.gitnex.activities.OpenRepoInBrowserActivity; import org.mian.gitnex.activities.OpenRepoInBrowserActivity;
import org.mian.gitnex.activities.RepoDetailActivity; import org.mian.gitnex.activities.RepoDetailActivity;
import org.mian.gitnex.activities.RepoStargazersActivity; import org.mian.gitnex.activities.RepoStargazersActivity;
import org.mian.gitnex.activities.RepoWatchersActivity; import org.mian.gitnex.activities.RepoWatchersActivity;
import org.mian.gitnex.clients.PicassoService;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.helpers.RoundedTransformation; import org.mian.gitnex.helpers.RoundedTransformation;
import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.models.UserRepositories; import org.mian.gitnex.models.UserRepositories;
import org.mian.gitnex.models.WatchRepository;
import org.mian.gitnex.util.TinyDB; import org.mian.gitnex.util.TinyDB;
import java.lang.reflect.Field;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
/** /**
* Author M M Arif * Author M M Arif
@ -43,19 +47,22 @@ public class ReposListAdapter extends RecyclerView.Adapter<ReposListAdapter.Repo
static class ReposViewHolder extends RecyclerView.ViewHolder { static class ReposViewHolder extends RecyclerView.ViewHolder {
private ImageView image; private ImageView image;
private TextView mTextView1; private TextView repoName;
private TextView mTextView2; private TextView repoDescription;
private TextView fullName; private TextView fullName;
private CheckBox isRepoAdmin;
private ImageView repoPrivatePublic; private ImageView repoPrivatePublic;
private TextView repoStars; private TextView repoStars;
private TextView repoForks; private TextView repoForks;
private TextView repoOpenIssuesCount; private TextView repoOpenIssuesCount;
private TextView repoType;
private ReposViewHolder(View itemView) { private ReposViewHolder(View itemView) {
super(itemView); super(itemView);
mTextView1 = itemView.findViewById(R.id.repoName); repoName = itemView.findViewById(R.id.repoName);
mTextView2 = itemView.findViewById(R.id.repoDescription); repoDescription = itemView.findViewById(R.id.repoDescription);
isRepoAdmin = itemView.findViewById(R.id.repoIsAdmin);
image = itemView.findViewById(R.id.imageAvatar); image = itemView.findViewById(R.id.imageAvatar);
fullName = itemView.findViewById(R.id.repoFullName); fullName = itemView.findViewById(R.id.repoFullName);
repoPrivatePublic = itemView.findViewById(R.id.imageRepoType); repoPrivatePublic = itemView.findViewById(R.id.imageRepoType);
@ -63,92 +70,126 @@ public class ReposListAdapter extends RecyclerView.Adapter<ReposListAdapter.Repo
repoForks = itemView.findViewById(R.id.repoForks); repoForks = itemView.findViewById(R.id.repoForks);
repoOpenIssuesCount = itemView.findViewById(R.id.repoOpenIssuesCount); repoOpenIssuesCount = itemView.findViewById(R.id.repoOpenIssuesCount);
ImageView reposDropdownMenu = itemView.findViewById(R.id.reposDropdownMenu); ImageView reposDropdownMenu = itemView.findViewById(R.id.reposDropdownMenu);
repoType = itemView.findViewById(R.id.repoType);
itemView.setOnClickListener(new View.OnClickListener() { itemView.setOnClickListener(v -> {
@Override
public void onClick(View v) {
Context context = v.getContext(); Context context = v.getContext();
TextView repoFullName = v.findViewById(R.id.repoFullName); TextView repoFullName = v.findViewById(R.id.repoFullName);
TextView repoType_ = v.findViewById(R.id.repoType);
Intent intent = new Intent(context, RepoDetailActivity.class); Intent intent = new Intent(context, RepoDetailActivity.class);
intent.putExtra("repoFullName", repoFullName.getText().toString()); intent.putExtra("repoFullName", repoFullName.getText().toString());
TinyDB tinyDb = new TinyDB(context); TinyDB tinyDb = new TinyDB(context);
tinyDb.putString("repoFullName", repoFullName.getText().toString()); tinyDb.putString("repoFullName", repoFullName.getText().toString());
tinyDb.putBoolean("resumeIssues", true); tinyDb.putString("repoType", repoType_.getText().toString());
context.startActivity(intent); //tinyDb.putBoolean("resumeIssues", true);
tinyDb.putBoolean("isRepoAdmin", isRepoAdmin.isChecked());
//store if user is watching this repo
{
final String instanceUrl = tinyDb.getString("instanceUrl");
String[] parts = repoFullName.getText().toString().split("/");
final String repoOwner = parts[0];
final String repoName = parts[1];
final String token = "token " + tinyDb.getString(tinyDb.getString("loginUid") + "-token");
WatchRepository watch = new WatchRepository();
Call<WatchRepository> call;
call = RetrofitClient.getInstance(instanceUrl, context).getApiInterface().checkRepoWatchStatus(token, repoOwner, repoName);
call.enqueue(new Callback<WatchRepository>() {
@Override
public void onResponse(@NonNull Call<WatchRepository> call, @NonNull retrofit2.Response<WatchRepository> response) {
if(response.isSuccessful()) {
assert response.body() != null;
tinyDb.putBoolean("repoWatch", response.body().getSubscribed());
} else {
tinyDb.putBoolean("repoWatch", false);
if(response.code() != 404) {
Toasty.info(context, context.getString(R.string.genericApiStatusError));
}
}
}
@Override
public void onFailure(@NonNull Call<WatchRepository> call, @NonNull Throwable t) {
tinyDb.putBoolean("repoWatch", false);
Toasty.info(context, context.getString(R.string.genericApiStatusError));
} }
}); });
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); context.startActivity(intent);
break;
case R.id.repoWatchers: });
Intent intentW = new Intent(context, RepoWatchersActivity.class); reposDropdownMenu.setOnClickListener(v -> {
intentW.putExtra("repoFullNameForWatchers", fullName.getText());
context.startActivity(intentW);
break;
case R.id.repoOpenInBrowser: final Context context = v.getContext();
@SuppressLint("InflateParams") View view = LayoutInflater.from(context).inflate(R.layout.bottom_sheet_repository_in_list, null);
TextView repoOpenInBrowser = view.findViewById(R.id.repoOpenInBrowser);
TextView repoStargazers = view.findViewById(R.id.repoStargazers);
TextView repoWatchers = view.findViewById(R.id.repoWatchers);
TextView bottomSheetHeader = view.findViewById(R.id.bottomSheetHeader);
bottomSheetHeader.setText(fullName.getText());
BottomSheetDialog dialog = new BottomSheetDialog(context);
dialog.setContentView(view);
dialog.show();
repoOpenInBrowser.setOnClickListener(openInBrowser -> {
Intent intentOpenInBrowser = new Intent(context, OpenRepoInBrowserActivity.class); Intent intentOpenInBrowser = new Intent(context, OpenRepoInBrowserActivity.class);
intentOpenInBrowser.putExtra("repoFullNameBrowser", fullName.getText()); intentOpenInBrowser.putExtra("repoFullNameBrowser", fullName.getText());
context.startActivity(intentOpenInBrowser); context.startActivity(intentOpenInBrowser);
break; dialog.dismiss();
}
return false;
}
}); });
popupMenu.show(); repoStargazers.setOnClickListener(stargazers -> {
Intent intent = new Intent(context, RepoStargazersActivity.class);
intent.putExtra("repoFullNameForStars", fullName.getText());
context.startActivity(intent);
dialog.dismiss();
});
repoWatchers.setOnClickListener(watchers -> {
Intent intentW = new Intent(context, RepoWatchersActivity.class);
intentW.putExtra("repoFullNameForWatchers", fullName.getText());
context.startActivity(intentW);
dialog.dismiss();
});
}
}); });
} }
} }
public ReposListAdapter(Context mCtx, List<UserRepositories> reposListMain) { public ReposListAdapter(Context mCtx, List<UserRepositories> reposListMain) {
this.mCtx = mCtx; this.mCtx = mCtx;
this.reposList = reposListMain; this.reposList = reposListMain;
reposListFull = new ArrayList<>(reposList); reposListFull = new ArrayList<>(reposList);
@ -157,7 +198,8 @@ public class ReposListAdapter extends RecyclerView.Adapter<ReposListAdapter.Repo
@NonNull @NonNull
@Override @Override
public ReposViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { public ReposViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.repos_list, parent, false);
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_repos, parent, false);
return new ReposViewHolder(v); return new ReposViewHolder(v);
} }
@ -165,26 +207,19 @@ public class ReposListAdapter extends RecyclerView.Adapter<ReposListAdapter.Repo
public void onBindViewHolder(@NonNull ReposViewHolder holder, int position) { public void onBindViewHolder(@NonNull ReposViewHolder holder, int position) {
UserRepositories currentItem = reposList.get(position); UserRepositories currentItem = reposList.get(position);
holder.mTextView2.setVisibility(View.GONE); holder.repoDescription.setVisibility(View.GONE);
ColorGenerator generator = ColorGenerator.MATERIAL; ColorGenerator generator = ColorGenerator.MATERIAL;
int color = generator.getColor(currentItem.getName()); int color = generator.getColor(currentItem.getName());
String firstCharacter = String.valueOf(currentItem.getName().charAt(0)); String firstCharacter = String.valueOf(currentItem.getName().charAt(0));
TextDrawable drawable = TextDrawable.builder() TextDrawable drawable = TextDrawable.builder().beginConfig().useFont(Typeface.DEFAULT).fontSize(18).toUpperCase().width(28).height(28).endConfig().buildRoundRect(firstCharacter, color, 3);
.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() != null) {
if(!currentItem.getAvatar_url().equals("")) { if(!currentItem.getAvatar_url().equals("")) {
Picasso.get().load(currentItem.getAvatar_url()).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(holder.image); PicassoService.getInstance(mCtx).get().load(currentItem.getAvatar_url()).placeholder(R.drawable.loader_animated).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(holder.image);
} else { }
else {
holder.image.setImageDrawable(drawable); holder.image.setImageDrawable(drawable);
} }
} }
@ -192,42 +227,53 @@ public class ReposListAdapter extends RecyclerView.Adapter<ReposListAdapter.Repo
holder.image.setImageDrawable(drawable); holder.image.setImageDrawable(drawable);
} }
holder.mTextView1.setText(currentItem.getName()); holder.repoName.setText(currentItem.getName());
if(!currentItem.getDescription().equals("")) { if(!currentItem.getDescription().equals("")) {
holder.mTextView2.setVisibility(View.VISIBLE); holder.repoDescription.setVisibility(View.VISIBLE);
holder.mTextView2.setText(currentItem.getDescription()); holder.repoDescription.setText(currentItem.getDescription());
} }
holder.fullName.setText(currentItem.getFullname()); holder.fullName.setText(currentItem.getFullname());
if(currentItem.getPrivateFlag()) { if(currentItem.getPrivateFlag()) {
holder.repoPrivatePublic.setImageResource(R.drawable.ic_lock_bold); holder.repoPrivatePublic.setImageResource(R.drawable.ic_lock_bold);
holder.repoType.setText(R.string.strPrivate);
} }
else { else {
holder.repoPrivatePublic.setImageResource(R.drawable.ic_public); holder.repoPrivatePublic.setImageResource(R.drawable.ic_public);
holder.repoType.setText(R.string.strPublic);
} }
holder.repoStars.setText(currentItem.getStars_count()); holder.repoStars.setText(currentItem.getStars_count());
holder.repoForks.setText(currentItem.getForks_count()); holder.repoForks.setText(currentItem.getForks_count());
holder.repoOpenIssuesCount.setText(currentItem.getOpen_issues_count()); holder.repoOpenIssuesCount.setText(currentItem.getOpen_issues_count());
if(holder.isRepoAdmin == null) {
holder.isRepoAdmin = new CheckBox(mCtx);
}
holder.isRepoAdmin.setChecked(currentItem.getPermissions().isAdmin());
} }
@Override @Override
public int getItemCount() { public int getItemCount() {
return reposList.size(); return reposList.size();
} }
@Override @Override
public Filter getFilter() { public Filter getFilter() {
return reposFilter; return reposFilter;
} }
private Filter reposFilter = new Filter() { private Filter reposFilter = new Filter() {
@Override @Override
protected FilterResults performFiltering(CharSequence constraint) { protected FilterResults performFiltering(CharSequence constraint) {
List<UserRepositories> filteredList = new ArrayList<>(); List<UserRepositories> filteredList = new ArrayList<>();
if(constraint == null || constraint.length() == 0) { if(constraint == null || constraint.length() == 0) {
filteredList.addAll(reposListFull); filteredList.addAll(reposListFull);
} else { }
else {
String filterPattern = constraint.toString().toLowerCase().trim(); String filterPattern = constraint.toString().toLowerCase().trim();
for(UserRepositories item : reposListFull) { for(UserRepositories item : reposListFull) {
@ -245,6 +291,7 @@ public class ReposListAdapter extends RecyclerView.Adapter<ReposListAdapter.Repo
@Override @Override
protected void publishResults(CharSequence constraint, FilterResults results) { protected void publishResults(CharSequence constraint, FilterResults results) {
reposList.clear(); reposList.clear();
reposList.addAll((List) results.values); reposList.addAll((List) results.values);
notifyDataSetChanged(); notifyDataSetChanged();

View File

@ -1,34 +1,38 @@
package org.mian.gitnex.adapters; package org.mian.gitnex.adapters;
import android.annotation.SuppressLint;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.graphics.Typeface; import android.graphics.Typeface;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.Filter; import android.widget.Filter;
import android.widget.Filterable; import android.widget.Filterable;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import com.amulyakhare.textdrawable.TextDrawable; import com.amulyakhare.textdrawable.TextDrawable;
import com.amulyakhare.textdrawable.util.ColorGenerator; import com.amulyakhare.textdrawable.util.ColorGenerator;
import com.squareup.picasso.Picasso; import com.google.android.material.bottomsheet.BottomSheetDialog;
import org.mian.gitnex.R; import org.mian.gitnex.R;
import org.mian.gitnex.activities.OpenRepoInBrowserActivity; import org.mian.gitnex.activities.OpenRepoInBrowserActivity;
import org.mian.gitnex.activities.RepoDetailActivity; import org.mian.gitnex.activities.RepoDetailActivity;
import org.mian.gitnex.activities.RepoStargazersActivity; import org.mian.gitnex.activities.RepoStargazersActivity;
import org.mian.gitnex.activities.RepoWatchersActivity; import org.mian.gitnex.activities.RepoWatchersActivity;
import org.mian.gitnex.clients.PicassoService;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.helpers.RoundedTransformation; import org.mian.gitnex.helpers.RoundedTransformation;
import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.models.UserRepositories; import org.mian.gitnex.models.UserRepositories;
import org.mian.gitnex.models.WatchRepository;
import org.mian.gitnex.util.TinyDB; import org.mian.gitnex.util.TinyDB;
import java.lang.reflect.Field;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.appcompat.view.ContextThemeWrapper;
import androidx.appcompat.widget.PopupMenu;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import retrofit2.Call;
import retrofit2.Callback;
/** /**
* Author M M Arif * Author M M Arif
@ -43,18 +47,21 @@ public class RepositoriesByOrgAdapter extends RecyclerView.Adapter<RepositoriesB
static class OrgReposViewHolder extends RecyclerView.ViewHolder { static class OrgReposViewHolder extends RecyclerView.ViewHolder {
private ImageView image; private ImageView image;
private TextView mTextView1; private TextView repoName;
private TextView mTextView2; private TextView repoDescription;
private TextView fullName; private TextView fullName;
private CheckBox isRepoAdmin;
private ImageView repoPrivatePublic; private ImageView repoPrivatePublic;
private TextView repoStars; private TextView repoStars;
private TextView repoForks; private TextView repoForks;
private TextView repoOpenIssuesCount; private TextView repoOpenIssuesCount;
private TextView repoType;
private OrgReposViewHolder(View itemView) { private OrgReposViewHolder(View itemView) {
super(itemView); super(itemView);
mTextView1 = itemView.findViewById(R.id.repoName); repoName = itemView.findViewById(R.id.repoName);
mTextView2 = itemView.findViewById(R.id.repoDescription); repoDescription = itemView.findViewById(R.id.repoDescription);
isRepoAdmin = itemView.findViewById(R.id.repoIsAdmin);
image = itemView.findViewById(R.id.imageAvatar); image = itemView.findViewById(R.id.imageAvatar);
fullName = itemView.findViewById(R.id.repoFullName); fullName = itemView.findViewById(R.id.repoFullName);
repoPrivatePublic = itemView.findViewById(R.id.imageRepoType); repoPrivatePublic = itemView.findViewById(R.id.imageRepoType);
@ -62,10 +69,9 @@ public class RepositoriesByOrgAdapter extends RecyclerView.Adapter<RepositoriesB
repoForks = itemView.findViewById(R.id.repoForks); repoForks = itemView.findViewById(R.id.repoForks);
repoOpenIssuesCount = itemView.findViewById(R.id.repoOpenIssuesCount); repoOpenIssuesCount = itemView.findViewById(R.id.repoOpenIssuesCount);
ImageView reposDropdownMenu = itemView.findViewById(R.id.reposDropdownMenu); ImageView reposDropdownMenu = itemView.findViewById(R.id.reposDropdownMenu);
repoType = itemView.findViewById(R.id.repoType);
itemView.setOnClickListener(new View.OnClickListener() { itemView.setOnClickListener(v -> {
@Override
public void onClick(View v) {
Context context = v.getContext(); Context context = v.getContext();
@ -74,73 +80,105 @@ public class RepositoriesByOrgAdapter extends RecyclerView.Adapter<RepositoriesB
TinyDB tinyDb = new TinyDB(context); TinyDB tinyDb = new TinyDB(context);
tinyDb.putString("repoFullName", fullName.getText().toString()); tinyDb.putString("repoFullName", fullName.getText().toString());
tinyDb.putBoolean("resumeIssues", true); tinyDb.putString("repoType", repoType.getText().toString());
context.startActivity(intent); //tinyDb.putBoolean("resumeIssues", true);
tinyDb.putBoolean("isRepoAdmin", isRepoAdmin.isChecked());
//store if user is watching this repo
{
final String instanceUrl = tinyDb.getString("instanceUrl");
String[] parts = fullName.getText().toString().split("/");
final String repoOwner = parts[0];
final String repoName = parts[1];
final String token = "token " + tinyDb.getString(tinyDb.getString("loginUid") + "-token");
WatchRepository watch = new WatchRepository();
Call<WatchRepository> call;
call = RetrofitClient.getInstance(instanceUrl, context).getApiInterface().checkRepoWatchStatus(token, repoOwner, repoName);
call.enqueue(new Callback<WatchRepository>() {
@Override
public void onResponse(@NonNull Call<WatchRepository> call, @NonNull retrofit2.Response<WatchRepository> response) {
if(response.isSuccessful()) {
assert response.body() != null;
tinyDb.putBoolean("repoWatch", response.body().getSubscribed());
} else {
tinyDb.putBoolean("repoWatch", false);
if(response.code() != 404) {
Toasty.info(context, context.getString(R.string.genericApiStatusError));
}
}
}
@Override
public void onFailure(@NonNull Call<WatchRepository> call, @NonNull Throwable t) {
tinyDb.putBoolean("repoWatch", false);
Toasty.info(context, context.getString(R.string.genericApiStatusError));
} }
}); });
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); context.startActivity(intent);
break; });
case R.id.repoWatchers: reposDropdownMenu.setOnClickListener(v -> {
Intent intentW = new Intent(context, RepoWatchersActivity.class); final Context context = v.getContext();
intentW.putExtra("repoFullNameForWatchers", fullName.getText());
context.startActivity(intentW);
break;
case R.id.repoOpenInBrowser: @SuppressLint("InflateParams")
View view = LayoutInflater.from(context).inflate(R.layout.bottom_sheet_repository_in_list, null);
TextView repoOpenInBrowser = view.findViewById(R.id.repoOpenInBrowser);
TextView repoStargazers = view.findViewById(R.id.repoStargazers);
TextView repoWatchers = view.findViewById(R.id.repoWatchers);
TextView bottomSheetHeader = view.findViewById(R.id.bottomSheetHeader);
bottomSheetHeader.setText(fullName.getText());
BottomSheetDialog dialog = new BottomSheetDialog(context);
dialog.setContentView(view);
dialog.show();
repoOpenInBrowser.setOnClickListener(openInBrowser -> {
Intent intentOpenInBrowser = new Intent(context, OpenRepoInBrowserActivity.class); Intent intentOpenInBrowser = new Intent(context, OpenRepoInBrowserActivity.class);
intentOpenInBrowser.putExtra("repoFullNameBrowser", fullName.getText()); intentOpenInBrowser.putExtra("repoFullNameBrowser", fullName.getText());
context.startActivity(intentOpenInBrowser); context.startActivity(intentOpenInBrowser);
break; dialog.dismiss();
}
return false;
}
}); });
popupMenu.show(); repoStargazers.setOnClickListener(openInBrowser -> {
Intent intent = new Intent(context, RepoStargazersActivity.class);
intent.putExtra("repoFullNameForStars", fullName.getText());
context.startActivity(intent);
dialog.dismiss();
});
repoWatchers.setOnClickListener(openInBrowser -> {
Intent intentW = new Intent(context, RepoWatchersActivity.class);
intentW.putExtra("repoFullNameForWatchers", fullName.getText());
context.startActivity(intentW);
dialog.dismiss();
});
}
}); });
} }
@ -156,7 +194,7 @@ public class RepositoriesByOrgAdapter extends RecyclerView.Adapter<RepositoriesB
@NonNull @NonNull
@Override @Override
public RepositoriesByOrgAdapter.OrgReposViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { public RepositoriesByOrgAdapter.OrgReposViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.repositories_by_org_list, parent, false); View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_repositories_by_org, parent, false);
return new RepositoriesByOrgAdapter.OrgReposViewHolder(v); return new RepositoriesByOrgAdapter.OrgReposViewHolder(v);
} }
@ -164,7 +202,7 @@ public class RepositoriesByOrgAdapter extends RecyclerView.Adapter<RepositoriesB
public void onBindViewHolder(@NonNull RepositoriesByOrgAdapter.OrgReposViewHolder holder, int position) { public void onBindViewHolder(@NonNull RepositoriesByOrgAdapter.OrgReposViewHolder holder, int position) {
UserRepositories currentItem = reposList.get(position); UserRepositories currentItem = reposList.get(position);
holder.mTextView2.setVisibility(View.GONE); holder.repoDescription.setVisibility(View.GONE);
ColorGenerator generator = ColorGenerator.MATERIAL; ColorGenerator generator = ColorGenerator.MATERIAL;
int color = generator.getColor(currentItem.getName()); int color = generator.getColor(currentItem.getName());
@ -182,7 +220,7 @@ public class RepositoriesByOrgAdapter extends RecyclerView.Adapter<RepositoriesB
if (currentItem.getAvatar_url() != null) { if (currentItem.getAvatar_url() != null) {
if (!currentItem.getAvatar_url().equals("")) { if (!currentItem.getAvatar_url().equals("")) {
Picasso.get().load(currentItem.getAvatar_url()).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(holder.image); PicassoService.getInstance(mCtx).get().load(currentItem.getAvatar_url()).placeholder(R.drawable.loader_animated).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(holder.image);
} else { } else {
holder.image.setImageDrawable(drawable); holder.image.setImageDrawable(drawable);
} }
@ -191,22 +229,29 @@ public class RepositoriesByOrgAdapter extends RecyclerView.Adapter<RepositoriesB
holder.image.setImageDrawable(drawable); holder.image.setImageDrawable(drawable);
} }
holder.mTextView1.setText(currentItem.getName()); holder.repoName.setText(currentItem.getName());
if (!currentItem.getDescription().equals("")) { if (!currentItem.getDescription().equals("")) {
holder.mTextView2.setVisibility(View.VISIBLE); holder.repoDescription.setVisibility(View.VISIBLE);
holder.mTextView2.setText(currentItem.getDescription()); holder.repoDescription.setText(currentItem.getDescription());
} }
holder.fullName.setText(currentItem.getFullname()); holder.fullName.setText(currentItem.getFullname());
if(currentItem.getPrivateFlag()) { if(currentItem.getPrivateFlag()) {
holder.repoPrivatePublic.setImageResource(R.drawable.ic_lock_bold); holder.repoPrivatePublic.setImageResource(R.drawable.ic_lock_bold);
holder.repoType.setText(R.string.strPrivate);
} }
else { else {
holder.repoPrivatePublic.setImageResource(R.drawable.ic_public); holder.repoPrivatePublic.setImageResource(R.drawable.ic_public);
holder.repoType.setText(R.string.strPublic);
} }
holder.repoStars.setText(currentItem.getStars_count()); holder.repoStars.setText(currentItem.getStars_count());
holder.repoForks.setText(currentItem.getForks_count()); holder.repoForks.setText(currentItem.getForks_count());
holder.repoOpenIssuesCount.setText(currentItem.getOpen_issues_count()); holder.repoOpenIssuesCount.setText(currentItem.getOpen_issues_count());
if (holder.isRepoAdmin == null) {
holder.isRepoAdmin = new CheckBox(mCtx);
}
holder.isRepoAdmin.setChecked(currentItem.getPermissions().isAdmin());
} }
@Override @Override

View File

@ -0,0 +1,59 @@
package org.mian.gitnex.adapters;
import android.text.SpannableStringBuilder;
import android.text.method.LinkMovementMethod;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import org.mian.gitnex.R;
import java.util.List;
/**
* Author M M Arif
*/
public class SponsorsAdapter extends RecyclerView.Adapter<SponsorsAdapter.SponsorsViewHolder> {
private List<CharSequence> sponsorsList;
static class SponsorsViewHolder extends RecyclerView.ViewHolder {
private TextView sponsorText;
private SponsorsViewHolder(View itemView) {
super(itemView);
sponsorText = itemView.findViewById(R.id.sponsorText);
}
}
public SponsorsAdapter(List<CharSequence> sponsorsListMain) {
this.sponsorsList = sponsorsListMain;
}
@NonNull
@Override
public SponsorsAdapter.SponsorsViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.sponsors, parent, false);
return new SponsorsAdapter.SponsorsViewHolder(v);
}
@Override
public void onBindViewHolder(@NonNull SponsorsAdapter.SponsorsViewHolder holder, int position) {
SpannableStringBuilder strBuilder = new SpannableStringBuilder(sponsorsList.get(position));
holder.sponsorText.setText((strBuilder));
holder.sponsorText.setMovementMethod(LinkMovementMethod.getInstance());
}
@Override
public int getItemCount() {
return sponsorsList.size();
}
}

View File

@ -1,34 +1,38 @@
package org.mian.gitnex.adapters; package org.mian.gitnex.adapters;
import android.annotation.SuppressLint;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.graphics.Typeface; import android.graphics.Typeface;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.Filter; import android.widget.Filter;
import android.widget.Filterable; import android.widget.Filterable;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import com.amulyakhare.textdrawable.TextDrawable; import com.amulyakhare.textdrawable.TextDrawable;
import com.amulyakhare.textdrawable.util.ColorGenerator; import com.amulyakhare.textdrawable.util.ColorGenerator;
import com.squareup.picasso.Picasso; import com.google.android.material.bottomsheet.BottomSheetDialog;
import org.mian.gitnex.R; import org.mian.gitnex.R;
import org.mian.gitnex.activities.OpenRepoInBrowserActivity; import org.mian.gitnex.activities.OpenRepoInBrowserActivity;
import org.mian.gitnex.activities.RepoDetailActivity; import org.mian.gitnex.activities.RepoDetailActivity;
import org.mian.gitnex.activities.RepoStargazersActivity; import org.mian.gitnex.activities.RepoStargazersActivity;
import org.mian.gitnex.activities.RepoWatchersActivity; import org.mian.gitnex.activities.RepoWatchersActivity;
import org.mian.gitnex.clients.PicassoService;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.helpers.RoundedTransformation; import org.mian.gitnex.helpers.RoundedTransformation;
import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.models.UserRepositories; import org.mian.gitnex.models.UserRepositories;
import org.mian.gitnex.models.WatchRepository;
import org.mian.gitnex.util.TinyDB; import org.mian.gitnex.util.TinyDB;
import java.lang.reflect.Field;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.appcompat.view.ContextThemeWrapper;
import androidx.appcompat.widget.PopupMenu;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import retrofit2.Call;
import retrofit2.Callback;
/** /**
* Author M M Arif * Author M M Arif
@ -43,18 +47,21 @@ public class StarredReposListAdapter extends RecyclerView.Adapter<StarredReposLi
static class StarredReposViewHolder extends RecyclerView.ViewHolder { static class StarredReposViewHolder extends RecyclerView.ViewHolder {
private ImageView image; private ImageView image;
private TextView mTextView1; private TextView repoName;
private TextView mTextView2; private TextView repoDescription;
private TextView fullName; private TextView fullName;
private CheckBox isRepoAdmin;
private ImageView repoPrivatePublic; private ImageView repoPrivatePublic;
private TextView repoStars; private TextView repoStars;
private TextView repoForks; private TextView repoForks;
private TextView repoOpenIssuesCount; private TextView repoOpenIssuesCount;
private TextView repoType;
private StarredReposViewHolder(View itemView) { private StarredReposViewHolder(View itemView) {
super(itemView); super(itemView);
mTextView1 = itemView.findViewById(R.id.repoName); repoName = itemView.findViewById(R.id.repoName);
mTextView2 = itemView.findViewById(R.id.repoDescription); repoDescription = itemView.findViewById(R.id.repoDescription);
isRepoAdmin = itemView.findViewById(R.id.repoIsAdmin);
image = itemView.findViewById(R.id.imageAvatar); image = itemView.findViewById(R.id.imageAvatar);
fullName = itemView.findViewById(R.id.repoFullName); fullName = itemView.findViewById(R.id.repoFullName);
repoPrivatePublic = itemView.findViewById(R.id.imageRepoType); repoPrivatePublic = itemView.findViewById(R.id.imageRepoType);
@ -62,10 +69,9 @@ public class StarredReposListAdapter extends RecyclerView.Adapter<StarredReposLi
repoForks = itemView.findViewById(R.id.repoForks); repoForks = itemView.findViewById(R.id.repoForks);
repoOpenIssuesCount = itemView.findViewById(R.id.repoOpenIssuesCount); repoOpenIssuesCount = itemView.findViewById(R.id.repoOpenIssuesCount);
ImageView reposDropdownMenu = itemView.findViewById(R.id.reposDropdownMenu); ImageView reposDropdownMenu = itemView.findViewById(R.id.reposDropdownMenu);
repoType = itemView.findViewById(R.id.repoType);
itemView.setOnClickListener(new View.OnClickListener() { itemView.setOnClickListener(v -> {
@Override
public void onClick(View v) {
Context context = v.getContext(); Context context = v.getContext();
@ -74,73 +80,106 @@ public class StarredReposListAdapter extends RecyclerView.Adapter<StarredReposLi
TinyDB tinyDb = new TinyDB(context); TinyDB tinyDb = new TinyDB(context);
tinyDb.putString("repoFullName", fullName.getText().toString()); tinyDb.putString("repoFullName", fullName.getText().toString());
tinyDb.putBoolean("resumeIssues", true); tinyDb.putString("repoType", repoType.getText().toString());
context.startActivity(intent); //tinyDb.putBoolean("resumeIssues", true);
tinyDb.putBoolean("isRepoAdmin", isRepoAdmin.isChecked());
//store if user is watching this repo
{
final String instanceUrl = tinyDb.getString("instanceUrl");
String[] parts = fullName.getText().toString().split("/");
final String repoOwner = parts[0];
final String repoName = parts[1];
final String token = "token " + tinyDb.getString(tinyDb.getString("loginUid") + "-token");
WatchRepository watch = new WatchRepository();
Call<WatchRepository> call;
call = RetrofitClient.getInstance(instanceUrl, context).getApiInterface().checkRepoWatchStatus(token, repoOwner, repoName);
call.enqueue(new Callback<WatchRepository>() {
@Override
public void onResponse(@NonNull Call<WatchRepository> call, @NonNull retrofit2.Response<WatchRepository> response) {
if(response.isSuccessful()) {
assert response.body() != null;
tinyDb.putBoolean("repoWatch", response.body().getSubscribed());
} else {
tinyDb.putBoolean("repoWatch", false);
if(response.code() != 404) {
Toasty.info(context, context.getString(R.string.genericApiStatusError));
}
}
}
@Override
public void onFailure(@NonNull Call<WatchRepository> call, @NonNull Throwable t) {
tinyDb.putBoolean("repoWatch", false);
Toasty.info(context, context.getString(R.string.genericApiStatusError));
} }
}); });
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); context.startActivity(intent);
break;
case R.id.repoWatchers: });
Intent intentW = new Intent(context, RepoWatchersActivity.class); reposDropdownMenu.setOnClickListener(v -> {
intentW.putExtra("repoFullNameForWatchers", fullName.getText());
context.startActivity(intentW);
break;
case R.id.repoOpenInBrowser: final Context context = v.getContext();
@SuppressLint("InflateParams")
View view = LayoutInflater.from(context).inflate(R.layout.bottom_sheet_repository_in_list, null);
TextView repoOpenInBrowser = view.findViewById(R.id.repoOpenInBrowser);
TextView repoStargazers = view.findViewById(R.id.repoStargazers);
TextView repoWatchers = view.findViewById(R.id.repoWatchers);
TextView bottomSheetHeader = view.findViewById(R.id.bottomSheetHeader);
bottomSheetHeader.setText(fullName.getText());
BottomSheetDialog dialog = new BottomSheetDialog(context);
dialog.setContentView(view);
dialog.show();
repoOpenInBrowser.setOnClickListener(openInBrowser -> {
Intent intentOpenInBrowser = new Intent(context, OpenRepoInBrowserActivity.class); Intent intentOpenInBrowser = new Intent(context, OpenRepoInBrowserActivity.class);
intentOpenInBrowser.putExtra("repoFullNameBrowser", fullName.getText()); intentOpenInBrowser.putExtra("repoFullNameBrowser", fullName.getText());
context.startActivity(intentOpenInBrowser); context.startActivity(intentOpenInBrowser);
break; dialog.dismiss();
}
return false;
}
}); });
popupMenu.show(); repoStargazers.setOnClickListener(stargazers -> {
Intent intent = new Intent(context, RepoStargazersActivity.class);
intent.putExtra("repoFullNameForStars", fullName.getText());
context.startActivity(intent);
dialog.dismiss();
});
repoWatchers.setOnClickListener(watchers -> {
Intent intentW = new Intent(context, RepoWatchersActivity.class);
intentW.putExtra("repoFullNameForWatchers", fullName.getText());
context.startActivity(intentW);
dialog.dismiss();
});
}
}); });
} }
@ -156,7 +195,7 @@ public class StarredReposListAdapter extends RecyclerView.Adapter<StarredReposLi
@NonNull @NonNull
@Override @Override
public StarredReposListAdapter.StarredReposViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { public StarredReposListAdapter.StarredReposViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.starred_repos_list, parent, false); View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_starred_repos, parent, false);
return new StarredReposListAdapter.StarredReposViewHolder(v); return new StarredReposListAdapter.StarredReposViewHolder(v);
} }
@ -164,7 +203,7 @@ public class StarredReposListAdapter extends RecyclerView.Adapter<StarredReposLi
public void onBindViewHolder(@NonNull StarredReposListAdapter.StarredReposViewHolder holder, int position) { public void onBindViewHolder(@NonNull StarredReposListAdapter.StarredReposViewHolder holder, int position) {
UserRepositories currentItem = reposList.get(position); UserRepositories currentItem = reposList.get(position);
holder.mTextView2.setVisibility(View.GONE); holder.repoDescription.setVisibility(View.GONE);
ColorGenerator generator = ColorGenerator.MATERIAL; ColorGenerator generator = ColorGenerator.MATERIAL;
int color = generator.getColor(currentItem.getName()); int color = generator.getColor(currentItem.getName());
@ -182,7 +221,7 @@ public class StarredReposListAdapter extends RecyclerView.Adapter<StarredReposLi
if (currentItem.getAvatar_url() != null) { if (currentItem.getAvatar_url() != null) {
if (!currentItem.getAvatar_url().equals("")) { if (!currentItem.getAvatar_url().equals("")) {
Picasso.get().load(currentItem.getAvatar_url()).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(holder.image); PicassoService.getInstance(mCtx).get().load(currentItem.getAvatar_url()).placeholder(R.drawable.loader_animated).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(holder.image);
} else { } else {
holder.image.setImageDrawable(drawable); holder.image.setImageDrawable(drawable);
} }
@ -191,21 +230,27 @@ public class StarredReposListAdapter extends RecyclerView.Adapter<StarredReposLi
holder.image.setImageDrawable(drawable); holder.image.setImageDrawable(drawable);
} }
holder.mTextView1.setText(currentItem.getName()); holder.repoName.setText(currentItem.getName());
if (!currentItem.getDescription().equals("")) { if (!currentItem.getDescription().equals("")) {
holder.mTextView2.setVisibility(View.VISIBLE); holder.repoDescription.setVisibility(View.VISIBLE);
holder.mTextView2.setText(currentItem.getDescription()); holder.repoDescription.setText(currentItem.getDescription());
} }
holder.fullName.setText(currentItem.getFullname()); holder.fullName.setText(currentItem.getFullname());
if(currentItem.getPrivateFlag()) { if(currentItem.getPrivateFlag()) {
holder.repoPrivatePublic.setImageResource(R.drawable.ic_lock_bold); holder.repoPrivatePublic.setImageResource(R.drawable.ic_lock_bold);
holder.repoType.setText(R.string.strPrivate);
} }
else { else {
holder.repoPrivatePublic.setImageResource(R.drawable.ic_public); holder.repoPrivatePublic.setImageResource(R.drawable.ic_public);
holder.repoType.setText(R.string.strPublic);
} }
holder.repoStars.setText(currentItem.getStars_count()); holder.repoStars.setText(currentItem.getStars_count());
holder.repoForks.setText(currentItem.getForks_count()); holder.repoForks.setText(currentItem.getForks_count());
holder.repoOpenIssuesCount.setText(currentItem.getOpen_issues_count()); holder.repoOpenIssuesCount.setText(currentItem.getOpen_issues_count());
if (holder.isRepoAdmin == null) {
holder.isRepoAdmin = new CheckBox(mCtx);
}
holder.isRepoAdmin.setChecked(currentItem.getPermissions().isAdmin());
} }

View File

@ -2,16 +2,19 @@ package org.mian.gitnex.adapters;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.content.Context; import android.content.Context;
import android.graphics.Typeface;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.BaseAdapter; import android.widget.BaseAdapter;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import com.squareup.picasso.Picasso;
import org.mian.gitnex.R; import org.mian.gitnex.R;
import org.mian.gitnex.clients.PicassoService;
import org.mian.gitnex.helpers.FontsOverride;
import org.mian.gitnex.helpers.RoundedTransformation; import org.mian.gitnex.helpers.RoundedTransformation;
import org.mian.gitnex.models.UserInfo; import org.mian.gitnex.models.UserInfo;
import org.mian.gitnex.util.TinyDB;
import java.util.List; import java.util.List;
/** /**
@ -23,7 +26,7 @@ public class TeamMembersByOrgAdapter extends BaseAdapter {
private List<UserInfo> teamMembersList; private List<UserInfo> teamMembersList;
private Context mCtx; private Context mCtx;
private class ViewHolder { private static class ViewHolder {
private ImageView memberAvatar; private ImageView memberAvatar;
private TextView memberName; private TextView memberName;
@ -62,8 +65,8 @@ public class TeamMembersByOrgAdapter extends BaseAdapter {
TeamMembersByOrgAdapter.ViewHolder viewHolder = null; TeamMembersByOrgAdapter.ViewHolder viewHolder = null;
if (finalView == null) { if (finalView == null) {
finalView = LayoutInflater.from(mCtx).inflate(R.layout.members_by_team_by_org_list, null); finalView = LayoutInflater.from(mCtx).inflate(R.layout.list_members_by_team_by_org, null);
viewHolder = new TeamMembersByOrgAdapter.ViewHolder(finalView); viewHolder = new ViewHolder(finalView);
finalView.setTag(viewHolder); finalView.setTag(viewHolder);
} }
else { else {
@ -78,13 +81,41 @@ public class TeamMembersByOrgAdapter extends BaseAdapter {
private void initData(TeamMembersByOrgAdapter.ViewHolder viewHolder, int position) { private void initData(TeamMembersByOrgAdapter.ViewHolder viewHolder, int position) {
UserInfo currentItem = teamMembersList.get(position); UserInfo currentItem = teamMembersList.get(position);
Picasso.get().load(currentItem.getAvatar()).transform(new RoundedTransformation(8, 0)).resize(180, 180).centerCrop().into(viewHolder.memberAvatar); PicassoService.getInstance(mCtx).get().load(currentItem.getAvatar()).placeholder(R.drawable.loader_animated).transform(new RoundedTransformation(8, 0)).resize(180, 180).centerCrop().into(viewHolder.memberAvatar);
final TinyDB tinyDb = new TinyDB(mCtx);
Typeface myTypeface;
switch(tinyDb.getInt("customFontId", -1)) {
case 0:
myTypeface = Typeface.createFromAsset(mCtx.getAssets(), "fonts/roboto.ttf");
break;
case 2:
myTypeface = Typeface.createFromAsset(mCtx.getAssets(), "fonts/sourcecodeproregular.ttf");
break;
default:
myTypeface = Typeface.createFromAsset(mCtx.getAssets(), "fonts/manroperegular.ttf");
break;
}
if(!currentItem.getFullname().equals("")) { if(!currentItem.getFullname().equals("")) {
viewHolder.memberName.setText(currentItem.getFullname()); viewHolder.memberName.setText(currentItem.getFullname());
viewHolder.memberName.setTypeface(myTypeface);
} }
else { else {
viewHolder.memberName.setText(currentItem.getLogin()); viewHolder.memberName.setText(currentItem.getLogin());
viewHolder.memberName.setTypeface(myTypeface);
}
if(tinyDb.getInt("themeId") == 1) { //light
viewHolder.memberName.setTextColor(mCtx.getResources().getColor(R.color.lightThemeTextColor));
}
else { // dark
viewHolder.memberName.setTextColor(mCtx.getResources().getColor(R.color.white));
} }
} }

View File

@ -9,7 +9,7 @@ import android.widget.Filter;
import android.widget.Filterable; import android.widget.Filterable;
import android.widget.TextView; import android.widget.TextView;
import org.mian.gitnex.R; import org.mian.gitnex.R;
import org.mian.gitnex.activities.OrgTeamMembersActivity; import org.mian.gitnex.activities.OrganizationTeamMembersActivity;
import org.mian.gitnex.models.Teams; import org.mian.gitnex.models.Teams;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -46,7 +46,7 @@ public class TeamsByOrgAdapter extends RecyclerView.Adapter<TeamsByOrgAdapter.Or
Context context = v.getContext(); Context context = v.getContext();
Intent intent = new Intent(context, OrgTeamMembersActivity.class); Intent intent = new Intent(context, OrganizationTeamMembersActivity.class);
intent.putExtra("teamTitle", teamTitle.getText().toString()); intent.putExtra("teamTitle", teamTitle.getText().toString());
intent.putExtra("teamId", teamId.getText().toString()); intent.putExtra("teamId", teamId.getText().toString());
context.startActivity(intent); context.startActivity(intent);
@ -67,7 +67,7 @@ public class TeamsByOrgAdapter extends RecyclerView.Adapter<TeamsByOrgAdapter.Or
@NonNull @NonNull
@Override @Override
public TeamsByOrgAdapter.OrgTeamsViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { public TeamsByOrgAdapter.OrgTeamsViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.teams_by_org_list, parent, false); View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_teams_by_org, parent, false);
return new TeamsByOrgAdapter.OrgTeamsViewHolder(v); return new TeamsByOrgAdapter.OrgTeamsViewHolder(v);
} }

View File

@ -9,9 +9,9 @@ import android.view.ViewGroup;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.ListView; import android.widget.ListView;
import android.widget.TextView; import android.widget.TextView;
import com.squareup.picasso.Picasso;
import org.mian.gitnex.R; import org.mian.gitnex.R;
import org.mian.gitnex.actions.CollaboratorActions; import org.mian.gitnex.actions.CollaboratorActions;
import org.mian.gitnex.clients.PicassoService;
import org.mian.gitnex.clients.RetrofitClient; import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.helpers.AlertDialogs; import org.mian.gitnex.helpers.AlertDialogs;
import org.mian.gitnex.helpers.Authorization; import org.mian.gitnex.helpers.Authorization;
@ -68,7 +68,7 @@ public class UserSearchAdapter extends RecyclerView.Adapter<UserSearchAdapter.Us
final Context context = v.getContext(); final Context context = v.getContext();
AlertDialog.Builder pBuilder = new AlertDialog.Builder(context, R.style.confirmDialog); AlertDialog.Builder pBuilder = new AlertDialog.Builder(context);
pBuilder.setTitle(R.string.newTeamPermission); pBuilder.setTitle(R.string.newTeamPermission);
pBuilder.setSingleChoiceItems(permissionList, permissionSelectedChoice, new DialogInterface.OnClickListener() { pBuilder.setSingleChoiceItems(permissionList, permissionSelectedChoice, new DialogInterface.OnClickListener() {
@ -120,7 +120,7 @@ public class UserSearchAdapter extends RecyclerView.Adapter<UserSearchAdapter.Us
@NonNull @NonNull
@Override @Override
public UserSearchAdapter.UserSearchViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { public UserSearchAdapter.UserSearchViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.collaborators_list_search, parent, false); View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_collaborators_search, parent, false);
return new UserSearchAdapter.UserSearchViewHolder(v); return new UserSearchAdapter.UserSearchViewHolder(v);
} }
@ -141,7 +141,7 @@ public class UserSearchAdapter extends RecyclerView.Adapter<UserSearchAdapter.Us
} }
if (!currentItem.getAvatar().equals("")) { if (!currentItem.getAvatar().equals("")) {
Picasso.get().load(currentItem.getAvatar()).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(holder.userAvatar); PicassoService.getInstance(mCtx).get().load(currentItem.getAvatar()).placeholder(R.drawable.loader_animated).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(holder.userAvatar);
} }
if(getItemCount() > 0) { if(getItemCount() > 0) {
@ -156,7 +156,7 @@ public class UserSearchAdapter extends RecyclerView.Adapter<UserSearchAdapter.Us
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token"); final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
Call<Collaborators> call = RetrofitClient Call<Collaborators> call = RetrofitClient
.getInstance(instanceUrl) .getInstance(instanceUrl, mCtx)
.getApiInterface() .getApiInterface()
.checkRepoCollaborator(Authorization.returnAuthentication(mCtx, loginUid, instanceToken), repoOwner, repoName, currentItem.getUsername()); .checkRepoCollaborator(Authorization.returnAuthentication(mCtx, loginUid, instanceToken), repoOwner, repoName, currentItem.getUsername());
@ -191,7 +191,7 @@ public class UserSearchAdapter extends RecyclerView.Adapter<UserSearchAdapter.Us
@Override @Override
public void onFailure(@NonNull Call<Collaborators> call, @NonNull Throwable t) { public void onFailure(@NonNull Call<Collaborators> call, @NonNull Throwable t) {
Log.i("onFailure", t.getMessage()); Log.i("onFailure", t.toString());
} }
}); });

View File

@ -1,6 +1,21 @@
package org.mian.gitnex.clients; package org.mian.gitnex.clients;
import android.content.Context;
import android.util.Log;
import androidx.annotation.NonNull;
import org.mian.gitnex.helpers.ssl.MemorizingTrustManager;
import org.mian.gitnex.util.AppUtil;
import java.io.File;
import java.io.IOException;
import java.security.SecureRandom;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.X509TrustManager;
import okhttp3.Cache;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient; import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.logging.HttpLoggingInterceptor; import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit; import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory; import retrofit2.converter.gson.GsonConverterFactory;
@ -11,23 +26,59 @@ import retrofit2.converter.gson.GsonConverterFactory;
public class IssuesService { public class IssuesService {
public static <S> S createService(Class<S> serviceClass, String instanceURL) { public static <S> S createService(Class<S> serviceClass, String instanceURL, Context ctx) {
final boolean connToInternet = AppUtil.haveNetworkConnection(ctx);
File httpCacheDirectory = new File(ctx.getCacheDir(), "responses");
int cacheSize = 50 * 1024 * 1024; // 50MB
Cache cache = new Cache(httpCacheDirectory, cacheSize);
HttpLoggingInterceptor logging = new HttpLoggingInterceptor(); HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY); logging.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient.Builder httpClient = new OkHttpClient.Builder(); try {
httpClient.addInterceptor(logging); SSLContext sslContext = SSLContext.getInstance("TLS");
Retrofit retrofit = new Retrofit.Builder() MemorizingTrustManager memorizingTrustManager = new MemorizingTrustManager(ctx);
sslContext.init(null, new X509TrustManager[]{memorizingTrustManager}, new SecureRandom());
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.cache(cache)
//.addInterceptor(logging)
.sslSocketFactory(sslContext.getSocketFactory(), memorizingTrustManager)
.hostnameVerifier(memorizingTrustManager.wrapHostnameVerifier(HttpsURLConnection.getDefaultHostnameVerifier()))
.addInterceptor(new Interceptor() {
@NonNull
@Override
public Response intercept(@NonNull Chain chain) throws IOException {
Request request = chain.request();
if(connToInternet) {
request = request.newBuilder().header("Cache-Control", "public, max-age=" + 60).build();
}
else {
request = request.newBuilder().header("Cache-Control", "public, only-if-cached, max-stale=" + 60 * 60 * 24 * 30).build();
}
return chain.proceed(request);
}
}).build();
Retrofit.Builder builder = new Retrofit.Builder()
.baseUrl(instanceURL) .baseUrl(instanceURL)
.addConverterFactory(GsonConverterFactory.create()) .client(okHttpClient)
//.client(httpClient.build()) .addConverterFactory(GsonConverterFactory.create());
.build();
Retrofit retrofit = builder.build();
return retrofit.create(serviceClass); return retrofit.create(serviceClass);
} }
catch(Exception e) {
Log.e("onFailure", e.toString());
}
return null;
}
} }

View File

@ -0,0 +1,76 @@
package org.mian.gitnex.clients;
import android.content.Context;
import android.util.Log;
import com.squareup.picasso.OkHttp3Downloader;
import com.squareup.picasso.Picasso;
import org.mian.gitnex.helpers.PicassoCache;
import org.mian.gitnex.helpers.ssl.MemorizingTrustManager;
import java.io.File;
import java.security.SecureRandom;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.X509TrustManager;
import okhttp3.OkHttpClient;
/**
* Author anonTree1417
*/
public class PicassoService {
private static PicassoService picassoService;
private Picasso picasso;
private PicassoService(Context context) {
Picasso.Builder builder = new Picasso.Builder(context);
try {
SSLContext sslContext = SSLContext.getInstance("TLS");
MemorizingTrustManager memorizingTrustManager = new MemorizingTrustManager(context);
sslContext.init(null, new X509TrustManager[]{memorizingTrustManager}, new SecureRandom());
OkHttpClient.Builder okHttpClient = new OkHttpClient.Builder()
.sslSocketFactory(sslContext.getSocketFactory(), memorizingTrustManager)
.hostnameVerifier(memorizingTrustManager.wrapHostnameVerifier(HttpsURLConnection.getDefaultHostnameVerifier()));
builder.downloader(new OkHttp3Downloader(okHttpClient.build()));
builder.listener((picasso, uri, exception) -> {
//Log.e("PicassoService", Objects.requireNonNull(uri.toString()));
//Log.e("PicassoService", exception.toString());
});
File cachePath = new File(context.getCacheDir() + "/picasso_cache/");
//noinspection ResultOfMethodCallIgnored
cachePath.mkdirs();
picasso = builder.memoryCache(new PicassoCache(cachePath)).build();
}
catch(Exception e) {
Log.e("PicassoService", e.toString());
}
}
public Picasso get() {
return picasso;
}
public static synchronized PicassoService getInstance(Context context) {
if(picassoService == null) {
picassoService = new PicassoService(context);
}
return picassoService;
}
}

View File

@ -0,0 +1,83 @@
package org.mian.gitnex.clients;
import android.content.Context;
import android.util.Log;
import androidx.annotation.NonNull;
import org.mian.gitnex.helpers.ssl.MemorizingTrustManager;
import org.mian.gitnex.util.AppUtil;
import java.io.File;
import java.io.IOException;
import java.security.SecureRandom;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.X509TrustManager;
import okhttp3.Cache;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
/**
* Author M M Arif
*/
public class PullRequestsService {
public static <S> S createService(Class<S> serviceClass, String instanceURL, Context ctx) {
final boolean connToInternet = AppUtil.haveNetworkConnection(ctx);
File httpCacheDirectory = new File(ctx.getCacheDir(), "responses");
int cacheSize = 50 * 1024 * 1024; // 50MB
Cache cache = new Cache(httpCacheDirectory, cacheSize);
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
try {
SSLContext sslContext = SSLContext.getInstance("TLS");
MemorizingTrustManager memorizingTrustManager = new MemorizingTrustManager(ctx);
sslContext.init(null, new X509TrustManager[]{memorizingTrustManager}, new SecureRandom());
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.cache(cache)
//.addInterceptor(logging)
.sslSocketFactory(sslContext.getSocketFactory(), memorizingTrustManager)
.hostnameVerifier(memorizingTrustManager.wrapHostnameVerifier(HttpsURLConnection.getDefaultHostnameVerifier()))
.addInterceptor(new Interceptor() {
@NonNull
@Override
public Response intercept(@NonNull Chain chain) throws IOException {
Request request = chain.request();
if(connToInternet) {
request = request.newBuilder().header("Cache-Control", "public, max-age=" + 60).build();
}
else {
request = request.newBuilder().header("Cache-Control", "public, only-if-cached, max-stale=" + 60 * 60 * 24 * 30).build();
}
return chain.proceed(request);
}
}).build();
Retrofit.Builder builder = new Retrofit.Builder()
.baseUrl(instanceURL)
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create());
Retrofit retrofit = builder.build();
return retrofit.create(serviceClass);
}
catch(Exception e) {
Log.e("onFailure", e.toString());
}
return null;
}
}

View File

@ -1,7 +1,19 @@
package org.mian.gitnex.clients; package org.mian.gitnex.clients;
import android.content.Context;
import android.util.Log;
import org.mian.gitnex.interfaces.ApiInterface; import org.mian.gitnex.interfaces.ApiInterface;
import org.mian.gitnex.interfaces.WebInterface;
import org.mian.gitnex.helpers.ssl.MemorizingTrustManager;
import org.mian.gitnex.util.AppUtil;
import java.io.File;
import java.security.SecureRandom;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.X509TrustManager;
import okhttp3.Cache;
import okhttp3.OkHttpClient; import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.logging.HttpLoggingInterceptor; import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit; import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory; import retrofit2.converter.gson.GsonConverterFactory;
@ -15,30 +27,65 @@ public class RetrofitClient {
private Retrofit retrofit; private Retrofit retrofit;
private RetrofitClient(String instanceUrl) { private RetrofitClient(String instanceUrl, Context ctx) {
final boolean connToInternet = AppUtil.haveNetworkConnection(ctx);
int cacheSize = 50 * 1024 * 1024; // 50MB
File httpCacheDirectory = new File(ctx.getCacheDir(), "responses");
Cache cache = new Cache(httpCacheDirectory, cacheSize);
HttpLoggingInterceptor logging = new HttpLoggingInterceptor(); HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY); logging.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient.Builder httpClient = new OkHttpClient.Builder(); try {
httpClient.addInterceptor(logging); SSLContext sslContext = SSLContext.getInstance("TLS");
retrofit = new Retrofit.Builder() MemorizingTrustManager memorizingTrustManager = new MemorizingTrustManager(ctx);
sslContext.init(null, new X509TrustManager[]{memorizingTrustManager}, new SecureRandom());
OkHttpClient.Builder okHttpClient = new OkHttpClient.Builder()
.cache(cache)
//.addInterceptor(logging)
.sslSocketFactory(sslContext.getSocketFactory(), memorizingTrustManager)
.hostnameVerifier(memorizingTrustManager.wrapHostnameVerifier(HttpsURLConnection.getDefaultHostnameVerifier()))
.addInterceptor(chain -> {
Request request = chain.request();
if(connToInternet) {
request = request.newBuilder().header("Cache-Control", "public, max-age=" + 60).build();
}
else {
request = request.newBuilder().header("Cache-Control", "public, only-if-cached, max-stale=" + 60 * 60 * 24 * 30).build();
}
return chain.proceed(request);
});
Retrofit.Builder builder = new Retrofit.Builder()
.baseUrl(instanceUrl) .baseUrl(instanceUrl)
.client(okHttpClient.build())
.addConverterFactory(ScalarsConverterFactory.create()) .addConverterFactory(ScalarsConverterFactory.create())
.addConverterFactory(GsonConverterFactory.create()) .addConverterFactory(GsonConverterFactory.create());
//.client(httpClient.build())
.build(); retrofit = builder.build();
}
catch(Exception e) {
Log.e("onFailure", e.toString());
}
} }
public static synchronized RetrofitClient getInstance(String instanceUrl) { public static synchronized RetrofitClient getInstance(String instanceUrl, Context ctx) {
return new RetrofitClient(instanceUrl); return new RetrofitClient(instanceUrl, ctx);
} }
public ApiInterface getApiInterface() { public ApiInterface getApiInterface() {
return retrofit.create(ApiInterface.class); return retrofit.create(ApiInterface.class);
} }
public WebInterface getWebInterface() {
return retrofit.create(WebInterface.class);
}
} }

View File

@ -6,27 +6,17 @@ import android.os.Bundle;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView; import android.widget.TextView;
import org.mian.gitnex.R; import org.mian.gitnex.R;
import org.mian.gitnex.activities.CreditsActivity; import org.mian.gitnex.activities.CreditsActivity;
import org.mian.gitnex.activities.MainActivity; import org.mian.gitnex.activities.MainActivity;
import org.mian.gitnex.activities.SponsorsActivity; import org.mian.gitnex.activities.SponsorsActivity;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.models.GiteaVersion;
import org.mian.gitnex.util.AppUtil; import org.mian.gitnex.util.AppUtil;
import org.mian.gitnex.util.TinyDB; import org.mian.gitnex.util.TinyDB;
import java.util.Objects; import java.util.Objects;
import retrofit2.Response;
import retrofit2.Call;
import retrofit2.Callback;
/** /**
* Author M M Arif * Author M M Arif
@ -34,17 +24,11 @@ import retrofit2.Callback;
public class AboutFragment extends Fragment { public class AboutFragment extends Fragment {
private TextView viewTextGiteaVersion;
private ProgressBar mProgressBar;
private LinearLayout pageContent;
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_about, container, false); View v = inflater.inflate(R.layout.fragment_about, container, false);
((MainActivity) Objects.requireNonNull(getActivity())).setActionBarTitle(getResources().getString(R.string.pageTitleAbout));
TinyDB tinyDb = new TinyDB(getContext()); TinyDB tinyDb = new TinyDB(getContext());
String instanceUrl = tinyDb.getString("instanceUrl");
final TextView appVerBuild; final TextView appVerBuild;
final TextView donationLink; final TextView donationLink;
@ -55,13 +39,8 @@ public class AboutFragment extends Fragment {
final TextView appWebsite; final TextView appWebsite;
final TextView appRepo; final TextView appRepo;
pageContent = v.findViewById(R.id.aboutFrame);
pageContent.setVisibility(View.GONE);
mProgressBar = v.findViewById(R.id.progress_bar);
appVerBuild = v.findViewById(R.id.appVerBuild); appVerBuild = v.findViewById(R.id.appVerBuild);
viewTextGiteaVersion = v.findViewById(R.id.giteaVersion); TextView viewTextGiteaVersion = v.findViewById(R.id.giteaVersion);
creditsButton = v.findViewById(R.id.creditsButton); creditsButton = v.findViewById(R.id.creditsButton);
donationLink = v.findViewById(R.id.donationLink); donationLink = v.findViewById(R.id.donationLink);
donationLinkPatreon = v.findViewById(R.id.donationLinkPatreon); donationLinkPatreon = v.findViewById(R.id.donationLinkPatreon);
@ -134,67 +113,10 @@ public class AboutFragment extends Fragment {
} }
}); });
boolean connToInternet = AppUtil.haveNetworkConnection(getContext()); String commit = getResources().getString(R.string.commitPage) + tinyDb.getString("giteaVersion");
viewTextGiteaVersion.setText(commit);
if(!connToInternet) {
mProgressBar.setVisibility(View.GONE);
pageContent.setVisibility(View.VISIBLE);
} else {
giteaVer(instanceUrl);
}
return v; return v;
} }
private void giteaVer(String instanceUrl) {
TinyDB tinyDb = new TinyDB(getContext());
final String loginUid = tinyDb.getString("loginUid");
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
Call<GiteaVersion> call = RetrofitClient
.getInstance(instanceUrl)
.getApiInterface()
.getGiteaVersion(Authorization.returnAuthentication(getContext(), loginUid, instanceToken));
call.enqueue(new Callback<GiteaVersion>() {
@Override
public void onResponse(@NonNull Call<GiteaVersion> call, @NonNull Response<GiteaVersion> response) {
if (response.isSuccessful()) {
if (response.code() == 200) {
GiteaVersion version = response.body();
assert version != null;
String commit = getResources().getString(R.string.commitPage) + version.getVersion();
viewTextGiteaVersion.setText(commit);
mProgressBar.setVisibility(View.GONE);
pageContent.setVisibility(View.VISIBLE);
}
}
else {
String commit = getResources().getString(R.string.commitPage);
viewTextGiteaVersion.setText(commit);
mProgressBar.setVisibility(View.GONE);
pageContent.setVisibility(View.VISIBLE);
}
}
@Override
public void onFailure(@NonNull Call<GiteaVersion> call, @NonNull Throwable t) {
Log.e("onFailure", t.toString());
}
});
}
} }

View File

@ -15,14 +15,14 @@ import org.mian.gitnex.R;
* Author M M Arif * Author M M Arif
*/ */
public class AdminUsersBottomSheetFragment extends BottomSheetDialogFragment { public class BottomSheetAdminUsersFragment extends BottomSheetDialogFragment {
private AdminUsersBottomSheetFragment.BottomSheetListener bmListener; private BottomSheetAdminUsersFragment.BottomSheetListener bmListener;
@Nullable @Nullable
@Override @Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.admin_users_bottom_sheet_layout, container, false); View v = inflater.inflate(R.layout.bottom_sheet_admin_users_layout, container, false);
TextView createNewUser = v.findViewById(R.id.createNewUser); TextView createNewUser = v.findViewById(R.id.createNewUser);
@ -46,7 +46,7 @@ public class AdminUsersBottomSheetFragment extends BottomSheetDialogFragment {
super.onAttach(context); super.onAttach(context);
try { try {
bmListener = (AdminUsersBottomSheetFragment.BottomSheetListener) context; bmListener = (BottomSheetAdminUsersFragment.BottomSheetListener) context;
} catch (ClassCastException e) { } catch (ClassCastException e) {
throw new ClassCastException(context.toString() throw new ClassCastException(context.toString()
+ " must implement BottomSheetListener"); + " must implement BottomSheetListener");

View File

@ -2,34 +2,35 @@ package org.mian.gitnex.fragments;
import android.content.Context; import android.content.Context;
import android.os.Bundle; import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.TextView; import android.widget.TextView;
import com.google.android.material.bottomsheet.BottomSheetDialogFragment; import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
import org.mian.gitnex.R; import org.mian.gitnex.R;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
/** /**
* Author M M Arif * Author M M Arif
*/ */
public class OrgBottomSheetFragment extends BottomSheetDialogFragment { public class BottomSheetFileViewerFragment extends BottomSheetDialogFragment {
private OrgBottomSheetFragment.BottomSheetListener bmListener; private BottomSheetFileViewerFragment.BottomSheetListener bmListener;
@Nullable @Nullable
@Override @Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.org_bottom_sheet_layout, container, false);
TextView createTeam = v.findViewById(R.id.createTeam); View v = inflater.inflate(R.layout.bottom_sheet_file_viewer, container, false);
createTeam.setOnClickListener(new View.OnClickListener() { TextView downloadFile = v.findViewById(R.id.downloadFile);
downloadFile.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
bmListener.onButtonClicked("team"); bmListener.onButtonClicked("downloadFile");
dismiss(); dismiss();
} }
}); });
@ -46,7 +47,7 @@ public class OrgBottomSheetFragment extends BottomSheetDialogFragment {
super.onAttach(context); super.onAttach(context);
try { try {
bmListener = (OrgBottomSheetFragment.BottomSheetListener) context; bmListener = (BottomSheetFileViewerFragment.BottomSheetListener) context;
} catch (ClassCastException e) { } catch (ClassCastException e) {
throw new ClassCastException(context.toString() throw new ClassCastException(context.toString()
+ " must implement BottomSheetListener"); + " must implement BottomSheetListener");

View File

@ -16,12 +16,12 @@ import androidx.annotation.Nullable;
* Author M M Arif * Author M M Arif
*/ */
public class NavSubMenuBottomSheetFragment extends BottomSheetDialogFragment { public class BottomSheetNavSubMenuFragment extends BottomSheetDialogFragment {
@Nullable @Nullable
@Override @Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.nav_sub_menu_bottom_sheet_layout, container, false); View v = inflater.inflate(R.layout.bottom_sheet_nav_sub_menu_layout, container, false);
TextView adminUsers = v.findViewById(R.id.adminUsers); TextView adminUsers = v.findViewById(R.id.adminUsers);

View File

@ -0,0 +1,65 @@
package org.mian.gitnex.fragments;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
import org.mian.gitnex.R;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
/**
* Author M M Arif
*/
public class BottomSheetOrganizationFragment extends BottomSheetDialogFragment {
private BottomSheetOrganizationFragment.BottomSheetListener bmListener;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.bottom_sheet_organization_layout, container, false);
TextView createTeam = v.findViewById(R.id.createTeam);
TextView createRepository = v.findViewById(R.id.createRepository);
createTeam.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
bmListener.onButtonClicked("team");
dismiss();
}
});
createRepository.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
bmListener.onButtonClicked("repository");
dismiss();
}
});
return v;
}
public interface BottomSheetListener {
void onButtonClicked(String text);
}
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
try {
bmListener = (BottomSheetOrganizationFragment.BottomSheetListener) context;
} catch (ClassCastException e) {
throw new ClassCastException(context.toString()
+ " must implement BottomSheetListener");
}
}
}

View File

@ -16,12 +16,12 @@ import androidx.annotation.Nullable;
* Author M M Arif * Author M M Arif
*/ */
public class ProfileBottomSheetFragment extends BottomSheetDialogFragment { public class BottomSheetProfileFragment extends BottomSheetDialogFragment {
@Nullable @Nullable
@Override @Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.profile_bottom_sheet_layout, container, false); View v = inflater.inflate(R.layout.bottom_sheet_profile_layout, container, false);
TextView addNewEmailAddress = v.findViewById(R.id.addNewEmailAddress); TextView addNewEmailAddress = v.findViewById(R.id.addNewEmailAddress);

View File

@ -17,14 +17,14 @@ import androidx.annotation.Nullable;
* Author M M Arif * Author M M Arif
*/ */
public class RepoBottomSheetFragment extends BottomSheetDialogFragment { public class BottomSheetRepoFragment extends BottomSheetDialogFragment {
private BottomSheetListener bmListener; private BottomSheetListener bmListener;
@Nullable @Nullable
@Override @Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.repo_bottom_sheet_layout, container, false); View v = inflater.inflate(R.layout.bottom_sheet_repo_layout, container, false);
final TinyDB tinyDb = new TinyDB(getContext()); final TinyDB tinyDb = new TinyDB(getContext());
@ -39,6 +39,7 @@ public class RepoBottomSheetFragment extends BottomSheetDialogFragment {
TextView unStarRepository = v.findViewById(R.id.unStarRepository); TextView unStarRepository = v.findViewById(R.id.unStarRepository);
TextView watchRepository = v.findViewById(R.id.watchRepository); TextView watchRepository = v.findViewById(R.id.watchRepository);
TextView unWatchRepository = v.findViewById(R.id.unWatchRepository); TextView unWatchRepository = v.findViewById(R.id.unWatchRepository);
TextView shareRepository = v.findViewById(R.id.shareRepository);
createLabel.setOnClickListener(new View.OnClickListener() { createLabel.setOnClickListener(new View.OnClickListener() {
@Override @Override
@ -86,6 +87,14 @@ public class RepoBottomSheetFragment extends BottomSheetDialogFragment {
} }
}); });
shareRepository.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
bmListener.onButtonClicked("shareRepo");
dismiss();
}
});
openWebRepo.setOnClickListener(new View.OnClickListener() { openWebRepo.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {

View File

@ -0,0 +1,241 @@
package org.mian.gitnex.fragments;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
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.IssueActions;
import org.mian.gitnex.activities.AddRemoveAssigneesActivity;
import org.mian.gitnex.activities.AddRemoveLabelsActivity;
import org.mian.gitnex.activities.EditIssueActivity;
import org.mian.gitnex.activities.FileDiffActivity;
import org.mian.gitnex.activities.MergePullRequestActivity;
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
*/
public class BottomSheetSingleIssueFragment extends BottomSheetDialogFragment {
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.bottom_sheet_single_issue_layout, container, false);
final Context ctx = getContext();
final TinyDB tinyDB = new TinyDB(ctx);
TextView editIssue = v.findViewById(R.id.editIssue);
TextView editLabels = v.findViewById(R.id.editLabels);
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);
TextView openFilesDiff = v.findViewById(R.id.openFilesDiff);
TextView mergePullRequest = v.findViewById(R.id.mergePullRequest);
TextView shareIssue = v.findViewById(R.id.shareIssue);
TextView subscribeIssue = v.findViewById(R.id.subscribeIssue);
TextView unsubscribeIssue = v.findViewById(R.id.unsubscribeIssue);
if(tinyDB.getString("issueType").equals("pr")) {
editIssue.setText(R.string.editPrText);
copyIssueUrl.setText(R.string.copyPrUrlText);
shareIssue.setText(R.string.sharePr);
if(tinyDB.getBoolean("prMerged")) {
mergePullRequest.setVisibility(View.GONE);
}
else {
mergePullRequest.setVisibility(View.VISIBLE);
}
if(tinyDB.getString("repoType").equals("public")) {
openFilesDiff.setVisibility(View.VISIBLE);
}
else {
openFilesDiff.setVisibility(View.GONE);
}
}
else {
mergePullRequest.setVisibility(View.GONE);
}
mergePullRequest.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(ctx, MergePullRequestActivity.class));
dismiss();
}
});
openFilesDiff.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(ctx, FileDiffActivity.class));
dismiss();
}
});
editIssue.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(ctx, EditIssueActivity.class));
dismiss();
}
});
editLabels.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(ctx, AddRemoveLabelsActivity.class));
dismiss();
}
});
addRemoveAssignees.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(ctx, AddRemoveAssigneesActivity.class));
dismiss();
}
});
shareIssue.setOnClickListener(v1 -> {
// 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");
// share issue
Intent sharingIntent = new Intent(android.content.Intent.ACTION_SEND);
sharingIntent.setType("text/plain");
sharingIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, getResources().getString(R.string.hash) + tinyDB.getString("issueNumber") + " " + tinyDB.getString("issueTitle"));
sharingIntent.putExtra(android.content.Intent.EXTRA_TEXT, issueUrl);
startActivity(Intent.createChooser(sharingIntent, getResources().getString(R.string.hash) + tinyDB.getString("issueNumber") + " " + tinyDB.getString("issueTitle")));
dismiss();
});
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(ctx).getSystemService(android.content.Context.CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText("issueUrl", issueUrl);
assert clipboard != null;
clipboard.setPrimaryClip(clip);
dismiss();
Toasty.info(ctx, ctx.getString(R.string.copyIssueUrlToastMsg));
}
});
if(tinyDB.getString("issueType").equals("issue")) {
if (tinyDB.getString("issueState").equals("open")) { // close issue
reOpenIssue.setVisibility(View.GONE);
closeIssue.setVisibility(View.VISIBLE);
closeIssue.setOnClickListener(closeSingleIssue -> {
IssueActions.closeReopenIssue(ctx, Integer.parseInt(tinyDB.getString("issueNumber")), "closed");
dismiss();
});
}
else if (tinyDB.getString("issueState").equals("closed")) {
closeIssue.setVisibility(View.GONE);
reOpenIssue.setVisibility(View.VISIBLE);
reOpenIssue.setOnClickListener(reOpenSingleIssue -> {
IssueActions.closeReopenIssue(ctx, Integer.parseInt(tinyDB.getString("issueNumber")), "open");
dismiss();
});
}
}
else {
reOpenIssue.setVisibility(View.GONE);
closeIssue.setVisibility(View.GONE);
}
subscribeIssue.setOnClickListener(subscribeToIssue -> {
IssueActions.subscribe(ctx, subscribeIssue, unsubscribeIssue);
//dismiss();
});
unsubscribeIssue.setOnClickListener(unsubscribeToIssue -> {
IssueActions.unsubscribe(ctx, subscribeIssue, unsubscribeIssue);
//dismiss();
});
//if RepoWatch True Provide Unsubscribe first
// ToDo: API to check if user is subscribed to an issue (do not exist can be guessed by many api endpoints :/)
if (tinyDB.getBoolean("repoWatch")) {
subscribeIssue.setVisibility(View.GONE);
unsubscribeIssue.setVisibility(View.VISIBLE);
}
return v;
}
}

View File

@ -96,7 +96,7 @@ public class BranchesFragment extends Fragment {
@Override @Override
public void run() { public void run() {
swipeRefresh.setRefreshing(false); swipeRefresh.setRefreshing(false);
BranchesViewModel.loadBranchesList(instanceUrl, instanceToken, repoOwner, repoName); BranchesViewModel.loadBranchesList(instanceUrl, instanceToken, repoOwner, repoName, getContext());
} }
}, 50); }, 50);
} }
@ -127,7 +127,7 @@ public class BranchesFragment extends Fragment {
BranchesViewModel branchesModel = new ViewModelProvider(this).get(BranchesViewModel.class); BranchesViewModel branchesModel = new ViewModelProvider(this).get(BranchesViewModel.class);
branchesModel.getBranchesList(instanceUrl, instanceToken, owner, repo).observe(this, new Observer<List<Branches>>() { branchesModel.getBranchesList(instanceUrl, instanceToken, owner, repo, getContext()).observe(getViewLifecycleOwner(), new Observer<List<Branches>>() {
@Override @Override
public void onChanged(@Nullable List<Branches> branchesListMain) { public void onChanged(@Nullable List<Branches> branchesListMain) {
adapter = new BranchesAdapter(getContext(), branchesListMain); adapter = new BranchesAdapter(getContext(), branchesListMain);

View File

@ -1,291 +0,0 @@
package org.mian.gitnex.fragments;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
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.ProgressBar;
import android.widget.TextView;
import org.mian.gitnex.R;
import org.mian.gitnex.adapters.ClosedIssuesAdapter;
import org.mian.gitnex.clients.IssuesService;
import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.interfaces.ApiInterface;
import org.mian.gitnex.models.Issues;
import org.mian.gitnex.util.AppUtil;
import org.mian.gitnex.util.TinyDB;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
/**
* Author M M Arif
*/
public class ClosedIssuesFragment extends Fragment {
private ProgressBar mProgressBarClosed;
private RecyclerView recyclerViewClosed;
private List<Issues> issuesListClosed;
private ClosedIssuesAdapter adapterClosed;
private ApiInterface apiClosed;
private String TAG = "closedIssuesListFragment - ";
private Context context;
private int pageSize = 1;
private TextView noDataIssuesClosed;
private String issueState = "closed";
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
final View v = inflater.inflate(R.layout.fragment_issues_closed, container, false);
setHasOptionsMenu(true);
TinyDB tinyDb = new TinyDB(getContext());
String repoFullName = tinyDb.getString("repoFullName");
//Log.i("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");
final SwipeRefreshLayout swipeRefresh = v.findViewById(R.id.pullToRefreshClosed);
context = getContext();
recyclerViewClosed = v.findViewById(R.id.recyclerViewClosed);
issuesListClosed = new ArrayList<>();
mProgressBarClosed = v.findViewById(R.id.progress_barClosed);
noDataIssuesClosed = v.findViewById(R.id.noDataIssuesClosed);
swipeRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
swipeRefresh.setRefreshing(false);
loadInitial(instanceToken, repoOwner, repoName, issueState);
adapterClosed.notifyDataChanged();
}
}, 200);
}
});
adapterClosed = new ClosedIssuesAdapter(getContext(), issuesListClosed);
adapterClosed.setLoadMoreListener(new ClosedIssuesAdapter.OnLoadMoreListener() {
@Override
public void onLoadMore() {
recyclerViewClosed.post(new Runnable() {
@Override
public void run() {
if(issuesListClosed.size() == 10 || pageSize == 10) {
int page = (issuesListClosed.size() + 10) / 10;
loadMore(Authorization.returnAuthentication(getContext(), loginUid, instanceToken), repoOwner, repoName, page, issueState);
}
/*else {
Toasty.info(context, getString(R.string.noMoreData));
}*/
}
});
}
});
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(recyclerViewClosed.getContext(),
DividerItemDecoration.VERTICAL);
recyclerViewClosed.setHasFixedSize(true);
recyclerViewClosed.addItemDecoration(dividerItemDecoration);
recyclerViewClosed.setLayoutManager(new LinearLayoutManager(context));
recyclerViewClosed.setAdapter(adapterClosed);
apiClosed = IssuesService.createService(ApiInterface.class, instanceUrl);
loadInitial(Authorization.returnAuthentication(getContext(), loginUid, instanceToken), repoOwner, repoName, issueState);
return v;
}
@Override
public void onResume() {
super.onResume();
TinyDB tinyDb = new TinyDB(getContext());
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");
if(tinyDb.getBoolean("resumeClosedIssues")) {
loadInitial(Authorization.returnAuthentication(getContext(), loginUid, instanceToken), repoOwner, repoName, issueState);
tinyDb.putBoolean("resumeClosedIssues", false);
}
}
private void loadInitial(String token, String repoOwner, String repoName, String issueState) {
Call<List<Issues>> call = apiClosed.getClosedIssues(token, repoOwner, repoName, 1, issueState);
call.enqueue(new Callback<List<Issues>>() {
@Override
public void onResponse(@NonNull Call<List<Issues>> call, @NonNull Response<List<Issues>> response) {
if(response.isSuccessful()) {
assert response.body() != null;
if(response.body().size() > 0) {
issuesListClosed.clear();
issuesListClosed.addAll(response.body());
adapterClosed.notifyDataChanged();
noDataIssuesClosed.setVisibility(View.GONE);
}
else {
issuesListClosed.clear();
adapterClosed.notifyDataChanged();
noDataIssuesClosed.setVisibility(View.VISIBLE);
}
mProgressBarClosed.setVisibility(View.GONE);
}
else {
Log.e(TAG, String.valueOf(response.code()));
}
}
@Override
public void onFailure(@NonNull Call<List<Issues>> call, @NonNull Throwable t) {
Log.e(TAG, t.getMessage());
}
});
}
private void loadMore(String token, String repoOwner, String repoName, int page, String issueState){
//add loading progress view
issuesListClosed.add(new Issues("load"));
adapterClosed.notifyItemInserted((issuesListClosed.size() - 1));
Call<List<Issues>> call = apiClosed.getClosedIssues(token, repoOwner, repoName, page, issueState);
call.enqueue(new Callback<List<Issues>>() {
@Override
public void onResponse(@NonNull Call<List<Issues>> call, @NonNull Response<List<Issues>> response) {
if(response.isSuccessful()){
//remove loading view
issuesListClosed.remove(issuesListClosed.size()-1);
List<Issues> result = response.body();
assert result != null;
if(result.size() > 0) {
pageSize = result.size();
issuesListClosed.addAll(result);
}
else {
Toasty.info(context, getString(R.string.noMoreData));
adapterClosed.setMoreDataAvailable(false);
}
adapterClosed.notifyDataChanged();
}
else {
Log.e(TAG, String.valueOf(response.code()));
}
}
@Override
public void onFailure(@NonNull Call<List<Issues>> call, @NonNull Throwable t) {
Log.e(TAG, t.getMessage());
}
});
}
@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) {
adapterClosed.getFilter().filter(newText);
return false;
}
});
}
}

View File

@ -100,7 +100,7 @@ public class CollaboratorsFragment extends Fragment {
CollaboratorsViewModel collaboratorsModel = new ViewModelProvider(this).get(CollaboratorsViewModel.class); CollaboratorsViewModel collaboratorsModel = new ViewModelProvider(this).get(CollaboratorsViewModel.class);
collaboratorsModel.getCollaboratorsList(instanceUrl, instanceToken, owner, repo).observe(this, new Observer<List<Collaborators>>() { collaboratorsModel.getCollaboratorsList(instanceUrl, instanceToken, owner, repo, getContext()).observe(getViewLifecycleOwner(), new Observer<List<Collaborators>>() {
@Override @Override
public void onChanged(@Nullable List<Collaborators> collaboratorsListMain) { public void onChanged(@Nullable List<Collaborators> collaboratorsListMain) {
adapter = new CollaboratorsAdapter(getContext(), collaboratorsListMain); adapter = new CollaboratorsAdapter(getContext(), collaboratorsListMain);

View File

@ -17,13 +17,11 @@ import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import org.mian.gitnex.R; import org.mian.gitnex.R;
import org.mian.gitnex.activities.MainActivity;
import org.mian.gitnex.adapters.ExploreRepositoriesAdapter; import org.mian.gitnex.adapters.ExploreRepositoriesAdapter;
import org.mian.gitnex.clients.RetrofitClient; import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.helpers.Authorization; import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.models.ExploreRepositories; import org.mian.gitnex.models.ExploreRepositories;
import org.mian.gitnex.models.UserRepositories; import org.mian.gitnex.models.UserRepositories;
import org.mian.gitnex.util.AppUtil;
import org.mian.gitnex.util.TinyDB; import org.mian.gitnex.util.TinyDB;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
@ -32,9 +30,10 @@ import retrofit2.Callback;
import retrofit2.Response; import retrofit2.Response;
/** /**
+ * Template Author M M Arif * + * Template Author M M Arif
+ * Author 6543 * + * Author 6543
+ */ * +
*/
public class ExploreRepositoriesFragment extends Fragment { public class ExploreRepositoriesFragment extends Fragment {
@ -46,16 +45,17 @@ public class ExploreRepositoriesFragment extends Fragment {
private TextView searchKeyword; private TextView searchKeyword;
private Boolean repoTypeInclude = true; private Boolean repoTypeInclude = true;
private String sort = "updated"; private String sort = "updated";
private String order = "asc"; private String order = "desc";
private int limit = 50;
private ExploreRepositoriesAdapter adapter;
private OnFragmentInteractionListener mListener; private OnFragmentInteractionListener mListener;
public ExploreRepositoriesFragment() { public ExploreRepositoriesFragment() {
} }
public static ExploreRepositoriesFragment newInstance(String param1, String param2) { public static ExploreRepositoriesFragment newInstance(String param1, String param2) {
ExploreRepositoriesFragment fragment = new ExploreRepositoriesFragment(); ExploreRepositoriesFragment fragment = new ExploreRepositoriesFragment();
Bundle args = new Bundle(); Bundle args = new Bundle();
args.putString(repoOwnerF, param1); args.putString(repoOwnerF, param1);
@ -66,6 +66,7 @@ public class ExploreRepositoriesFragment extends Fragment {
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
if(getArguments() != null) { if(getArguments() != null) {
String repoName = getArguments().getString(repoNameF); String repoName = getArguments().getString(repoNameF);
@ -74,14 +75,10 @@ public class ExploreRepositoriesFragment extends Fragment {
} }
@Override @Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Bundle savedInstanceState) {
boolean connToInternet = AppUtil.haveNetworkConnection(Objects.requireNonNull(getContext()));
final View v = inflater.inflate(R.layout.fragment_explore_repo, container, false); final View v = inflater.inflate(R.layout.fragment_explore_repo, container, false);
//setHasOptionsMenu(true); //setHasOptionsMenu(true);
((MainActivity) Objects.requireNonNull(getActivity())).setActionBarTitle(getResources().getString(R.string.pageTitleExplore));
TinyDB tinyDb = new TinyDB(getContext()); TinyDB tinyDb = new TinyDB(getContext());
final String instanceUrl = tinyDb.getString("instanceUrl"); final String instanceUrl = tinyDb.getString("instanceUrl");
@ -93,37 +90,34 @@ public class ExploreRepositoriesFragment extends Fragment {
mProgressBar = v.findViewById(R.id.progress_bar); mProgressBar = v.findViewById(R.id.progress_bar);
mRecyclerView = v.findViewById(R.id.recyclerViewReposSearch); mRecyclerView = v.findViewById(R.id.recyclerViewReposSearch);
if(connToInternet) { mProgressBar.setVisibility(View.VISIBLE);
searchKeyword.setOnEditorActionListener(new TextView.OnEditorActionListener() { searchKeyword.setOnEditorActionListener(new TextView.OnEditorActionListener() {
@Override @Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if(actionId == EditorInfo.IME_ACTION_SEND) { if(actionId == EditorInfo.IME_ACTION_SEND) {
if(!searchKeyword.getText().toString().equals("")) { if(!searchKeyword.getText().toString().equals("")) {
mProgressBar.setVisibility(View.VISIBLE); mProgressBar.setVisibility(View.VISIBLE);
mRecyclerView.setVisibility(View.GONE); mRecyclerView.setVisibility(View.GONE);
loadSearchReposList(instanceUrl, instanceToken, loginUid, searchKeyword.getText().toString(), repoTypeInclude, sort, order, getContext()); loadSearchReposList(instanceUrl, instanceToken, loginUid, searchKeyword.getText().toString(), repoTypeInclude, sort, order, getContext(), limit);
} }
} }
return false; return false;
} }
}); });
} int limitDefault = 10;
else { loadDefaultList(instanceUrl, instanceToken, loginUid, repoTypeInclude, sort, order, getContext(), limitDefault);
mProgressBar.setVisibility(View.GONE);
}
return v; return v;
} }
private void loadSearchReposList(String instanceUrl, String instanceToken, String loginUid, String searchKeyword, Boolean repoTypeInclude, String sort, String order, final Context context) { private void loadDefaultList(String instanceUrl, String instanceToken, String loginUid, Boolean repoTypeInclude, String sort, String order, final Context context, int limit) {
Call<ExploreRepositories> call = RetrofitClient Call<ExploreRepositories> call = RetrofitClient.getInstance(instanceUrl, getContext()).getApiInterface().queryRepos(Authorization.returnAuthentication(getContext(), loginUid, instanceToken), null, repoTypeInclude, sort, order, limit);
.getInstance(instanceUrl)
.getApiInterface()
.queryRepos(Authorization.returnAuthentication(getContext(), loginUid, instanceToken), searchKeyword, repoTypeInclude, sort, order);
call.enqueue(new Callback<ExploreRepositories>() { call.enqueue(new Callback<ExploreRepositories>() {
@ -133,7 +127,8 @@ public class ExploreRepositoriesFragment extends Fragment {
if(response.isSuccessful()) { if(response.isSuccessful()) {
assert response.body() != null; assert response.body() != null;
getReposList(response.body().getSearchedData(), context); getReposList(response.body().getSearchedData(), context);
} else { }
else {
Log.i("onResponse", String.valueOf(response.code())); Log.i("onResponse", String.valueOf(response.code()));
} }
@ -141,7 +136,37 @@ public class ExploreRepositoriesFragment extends Fragment {
@Override @Override
public void onFailure(@NonNull Call<ExploreRepositories> call, @NonNull Throwable t) { public void onFailure(@NonNull Call<ExploreRepositories> call, @NonNull Throwable t) {
Log.i("onFailure", t.getMessage());
Log.i("onFailure", Objects.requireNonNull(t.getMessage()));
}
});
}
private void loadSearchReposList(String instanceUrl, String instanceToken, String loginUid, String searchKeyword, Boolean repoTypeInclude, String sort, String order, final Context context, int limit) {
Call<ExploreRepositories> call = RetrofitClient.getInstance(instanceUrl, getContext()).getApiInterface().queryRepos(Authorization.returnAuthentication(getContext(), loginUid, instanceToken), searchKeyword, repoTypeInclude, sort, order, limit);
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", Objects.requireNonNull(t.getMessage()));
} }
}); });
@ -150,14 +175,13 @@ public class ExploreRepositoriesFragment extends Fragment {
private void getReposList(List<UserRepositories> dataList, Context context) { private void getReposList(List<UserRepositories> dataList, Context context) {
adapter = new ExploreRepositoriesAdapter(dataList, context); ExploreRepositoriesAdapter adapter = new ExploreRepositoriesAdapter(dataList, context);
mRecyclerView.setVisibility(View.VISIBLE); mRecyclerView.setVisibility(View.VISIBLE);
mRecyclerView.setHasFixedSize(true); mRecyclerView.setHasFixedSize(true);
mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext())); mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(mRecyclerView.getContext(), DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(mRecyclerView.getContext(), DividerItemDecoration.VERTICAL);
DividerItemDecoration.VERTICAL);
mRecyclerView.addItemDecoration(dividerItemDecoration); mRecyclerView.addItemDecoration(dividerItemDecoration);
if(adapter.getItemCount() > 0) { if(adapter.getItemCount() > 0) {
@ -177,6 +201,7 @@ public class ExploreRepositoriesFragment extends Fragment {
} }
public void onButtonPressed(Uri uri) { public void onButtonPressed(Uri uri) {
if(mListener != null) { if(mListener != null) {
mListener.onFragmentInteraction(uri); mListener.onFragmentInteraction(uri);
} }
@ -184,11 +209,15 @@ public class ExploreRepositoriesFragment extends Fragment {
@Override @Override
public void onDetach() { public void onDetach() {
super.onDetach(); super.onDetach();
mListener = null; mListener = null;
} }
public interface OnFragmentInteractionListener { public interface OnFragmentInteractionListener {
void onFragmentInteraction(Uri uri); void onFragmentInteraction(Uri uri);
} }
} }

View File

@ -1,5 +1,6 @@
package org.mian.gitnex.fragments; package org.mian.gitnex.fragments;
import android.annotation.SuppressLint;
import android.content.Intent; import android.content.Intent;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
@ -140,8 +141,14 @@ public class FilesFragment extends Fragment implements FilesAdapter.FilesAdapter
fileStructure.setText(breadcrumbBuilder); fileStructure.setText(breadcrumbBuilder);
String dirName_ = fileStructure.getText().toString();
dirName_ = dirName_.startsWith("/") ? dirName_.substring(1) : dirName_;
final String finalDirName_ = dirName_;
mBreadcrumbsView.addItem(createItem(dirName)); mBreadcrumbsView.addItem(createItem(dirName));
//noinspection unchecked
mBreadcrumbsView.setCallback(new DefaultBreadcrumbsCallback<BreadcrumbItem>() { mBreadcrumbsView.setCallback(new DefaultBreadcrumbsCallback<BreadcrumbItem>() {
@SuppressLint("SetTextI18n")
@Override @Override
public void onNavigateBack(BreadcrumbItem item, int position) { public void onNavigateBack(BreadcrumbItem item, int position) {
@ -154,7 +161,10 @@ public class FilesFragment extends Fragment implements FilesAdapter.FilesAdapter
String filterDir = fileStructure.getText().toString(); String filterDir = fileStructure.getText().toString();
String result = filterDir.substring(0, filterDir.indexOf(item.getSelectedItem())); String result = filterDir.substring(0, filterDir.indexOf(item.getSelectedItem()));
fileStructure.setText(result + item.getSelectedItem()); fileStructure.setText(result + item.getSelectedItem());
fetchDataAsyncSub(instanceUrl, Authorization.returnAuthentication(getContext(), loginUid, instanceToken), repoOwner, repoName, fileStructure.getText().toString());
String currentIndex = (result + item.getSelectedItem()).substring(1);
fetchDataAsyncSub(instanceUrl, Authorization.returnAuthentication(getContext(), loginUid, instanceToken), repoOwner, repoName, currentIndex);
} }
@ -164,7 +174,7 @@ public class FilesFragment extends Fragment implements FilesAdapter.FilesAdapter
} }
}); });
fetchDataAsyncSub(instanceUrl, Authorization.returnAuthentication(getContext(), loginUid, instanceToken), repoOwner, repoName, fileStructure.getText().toString()); fetchDataAsyncSub(instanceUrl, Authorization.returnAuthentication(getContext(), loginUid, instanceToken), repoOwner, repoName, finalDirName_);
} }
@ -192,7 +202,7 @@ public class FilesFragment extends Fragment implements FilesAdapter.FilesAdapter
FilesViewModel filesModel = new ViewModelProvider(this).get(FilesViewModel.class); FilesViewModel filesModel = new ViewModelProvider(this).get(FilesViewModel.class);
filesModel.getFilesList(instanceUrl, instanceToken, owner, repo, getContext()).observe(this, new Observer<List<Files>>() { filesModel.getFilesList(instanceUrl, instanceToken, owner, repo, getContext()).observe(getViewLifecycleOwner(), new Observer<List<Files>>() {
@Override @Override
public void onChanged(@Nullable List<Files> filesListMain) { public void onChanged(@Nullable List<Files> filesListMain) {
adapter = new FilesAdapter(getContext(), filesListMain, FilesFragment.this); adapter = new FilesAdapter(getContext(), filesListMain, FilesFragment.this);
@ -260,11 +270,11 @@ public class FilesFragment extends Fragment implements FilesAdapter.FilesAdapter
MenuItem searchItem = menu.findItem(R.id.action_search); MenuItem searchItem = menu.findItem(R.id.action_search);
androidx.appcompat.widget.SearchView searchView = (androidx.appcompat.widget.SearchView) searchItem.getActionView(); androidx.appcompat.widget.SearchView searchView = (androidx.appcompat.widget.SearchView) searchItem.getActionView();
searchView.setImeOptions(EditorInfo.IME_ACTION_DONE); searchView.setImeOptions(EditorInfo.IME_ACTION_DONE);
searchView.setQueryHint(getContext().getString(R.string.strFilter)); //searchView.setQueryHint(getContext().getString(R.string.search));
if(!connToInternet) { /*if(!connToInternet) {
return; return;
} }*/
searchView.setOnQueryTextListener(new androidx.appcompat.widget.SearchView.OnQueryTextListener() { searchView.setOnQueryTextListener(new androidx.appcompat.widget.SearchView.OnQueryTextListener() {
@Override @Override

View File

@ -0,0 +1,311 @@
package org.mian.gitnex.fragments;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
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.ProgressBar;
import android.widget.TextView;
import org.mian.gitnex.R;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.helpers.StaticGlobalVariables;
import org.mian.gitnex.helpers.VersionCheck;
import org.mian.gitnex.adapters.IssuesAdapter;
import org.mian.gitnex.models.Issues;
import org.mian.gitnex.util.TinyDB;
import java.util.ArrayList;
import java.util.List;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.DefaultItemAnimator;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import com.mikepenz.fastadapter.IItemAdapter;
import com.mikepenz.fastadapter.adapters.ItemAdapter;
import com.mikepenz.fastadapter.commons.adapters.FastItemAdapter;
import com.mikepenz.fastadapter.listeners.ItemFilterListener;
import com.mikepenz.fastadapter_extensions.items.ProgressItem;
import com.mikepenz.fastadapter_extensions.scroll.EndlessRecyclerOnScrollListener;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import static com.mikepenz.fastadapter.adapters.ItemAdapter.items;
/**
* Author M M Arif
*/
public class IssuesClosedFragment extends Fragment implements ItemFilterListener<IssuesAdapter> {
private Context ctx;
private ProgressBar mProgressBarClosed;
private boolean loadNextFlag = false;
private String TAG = StaticGlobalVariables.tagIssuesListClosed;
private TextView noDataIssuesClosed;
private int resultLimit = StaticGlobalVariables.resultLimitOldGiteaInstances;
private String requestType = StaticGlobalVariables.issuesRequestType;
private String issueState = StaticGlobalVariables.issueStateClosed;
private List<IssuesAdapter> items = new ArrayList<>();
private FastItemAdapter<IssuesAdapter> fastItemAdapter;
private ItemAdapter footerAdapter;
private EndlessRecyclerOnScrollListener endlessRecyclerOnScrollListener;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
final View v = inflater.inflate(R.layout.fragment_issues_closed, 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");
String repoFullName = tinyDb.getString("repoFullName");
String[] parts = repoFullName.split("/");
final String repoOwner = parts[0];
final String repoName = parts[1];
if (VersionCheck.compareVersion("1.12.0", tinyDb.getString("giteaVersion")) < 1) {
resultLimit = StaticGlobalVariables.resultLimitNewGiteaInstances;
}
noDataIssuesClosed = v.findViewById(R.id.noDataIssuesClosed);
mProgressBarClosed = v.findViewById(R.id.progress_barClosed);
final SwipeRefreshLayout swipeRefreshLayout = v.findViewById(R.id.pullToRefreshClosed);
RecyclerView recyclerView = v.findViewById(R.id.recyclerViewClosed);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
recyclerView.setHasFixedSize(true);
fastItemAdapter = new FastItemAdapter<>();
fastItemAdapter.withSelectable(true);
footerAdapter = items();
//noinspection unchecked
fastItemAdapter.addAdapter(StaticGlobalVariables.issuesPageInit, footerAdapter);
fastItemAdapter.getItemFilter().withFilterPredicate((IItemAdapter.Predicate<IssuesAdapter>) (item, constraint) -> item.getIssueTitle().toLowerCase().contains(constraint.toString().toLowerCase()));
fastItemAdapter.getItemFilter().withItemFilterListener(this);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.setAdapter(fastItemAdapter);
endlessRecyclerOnScrollListener = new EndlessRecyclerOnScrollListener(footerAdapter) {
@Override
public void onLoadMore(final int currentPage) {
loadNext(instanceUrl, instanceToken, repoOwner, repoName, resultLimit, issueState, requestType, currentPage);
}
};
swipeRefreshLayout.setOnRefreshListener(() -> {
mProgressBarClosed.setVisibility(View.VISIBLE);
fastItemAdapter.clear();
endlessRecyclerOnScrollListener.resetPageCount();
swipeRefreshLayout.setRefreshing(false);
});
recyclerView.addOnScrollListener(endlessRecyclerOnScrollListener);
loadInitial(instanceUrl, instanceToken, repoOwner, repoName, issueState, resultLimit, requestType);
fastItemAdapter.withEventHook(new IssuesAdapter.IssueTitleClickEvent());
assert savedInstanceState != null;
fastItemAdapter.withSavedInstanceState(savedInstanceState);
return v;
}
@Override
public void onResume() {
super.onResume();
TinyDB tinyDb = new TinyDB(getContext());
if(tinyDb.getBoolean("resumeClosedIssues")) {
mProgressBarClosed.setVisibility(View.VISIBLE);
fastItemAdapter.clear();
endlessRecyclerOnScrollListener.resetPageCount();
tinyDb.putBoolean("resumeClosedIssues", false);
}
}
private void loadInitial(String instanceUrl, String token, String repoOwner, String repoName, String issueState, int resultLimit, String requestType) {
Call<List<Issues>> call = RetrofitClient.getInstance(instanceUrl, getContext()).getApiInterface().getClosedIssues(token, repoOwner, repoName, 1, issueState, resultLimit, requestType);
call.enqueue(new Callback<List<Issues>>() {
@Override
public void onResponse(@NonNull Call<List<Issues>> call, @NonNull Response<List<Issues>> response) {
if(response.isSuccessful()) {
assert response.body() != null;
if(response.body().size() > 0) {
if(response.body().size() == resultLimit) {
loadNextFlag = true;
}
for(int i = 0; i < response.body().size(); i++) {
items.add(new IssuesAdapter(getContext()).withNewItems(response.body().get(i).getTitle(), response.body().get(i).getNumber(), response.body().get(i).getUser().getAvatar_url(), response.body().get(i).getCreated_at(), response.body().get(i).getComments(), response.body().get(i).getUser().getFull_name(), response.body().get(i).getUser().getLogin()));
}
fastItemAdapter.add(items);
noDataIssuesClosed.setVisibility(View.GONE);
}
else {
noDataIssuesClosed.setVisibility(View.VISIBLE);
}
mProgressBarClosed.setVisibility(View.GONE);
}
else {
Log.i(TAG, String.valueOf(response.code()));
}
}
@Override
public void onFailure(@NonNull Call<List<Issues>> call, @NonNull Throwable t) {
Log.e(TAG, t.toString());
}
});
}
private void loadNext(String instanceUrl, String token, String repoOwner, String repoName, int resultLimit, String issueState, String requestType, final int currentPage) {
footerAdapter.clear();
//noinspection unchecked
footerAdapter.add(new ProgressItem().withEnabled(false));
Handler handler = new Handler();
handler.postDelayed(() -> {
Call<List<Issues>> call = RetrofitClient.getInstance(instanceUrl, getContext()).getApiInterface().getClosedIssues(token, repoOwner, repoName, currentPage + 1, issueState, resultLimit, requestType);
call.enqueue(new Callback<List<Issues>>() {
@Override
public void onResponse(@NonNull Call<List<Issues>> call, @NonNull Response<List<Issues>> response) {
if(response.isSuccessful()) {
assert response.body() != null;
if(response.body().size() > 0) {
loadNextFlag = response.body().size() == resultLimit;
for(int i = 0; i < response.body().size(); i++) {
fastItemAdapter.add(fastItemAdapter.getAdapterItemCount(), new IssuesAdapter(getContext()).withNewItems(response.body().get(i).getTitle(), response.body().get(i).getNumber(), response.body().get(i).getUser().getAvatar_url(), response.body().get(i).getCreated_at(), response.body().get(i).getComments(), response.body().get(i).getUser().getFull_name(), response.body().get(i).getUser().getLogin()));
}
footerAdapter.clear();
mProgressBarClosed.setVisibility(View.GONE);
}
else {
footerAdapter.clear();
}
mProgressBarClosed.setVisibility(View.GONE);
}
else {
Log.i(TAG, String.valueOf(response.code()));
}
}
@Override
public void onFailure(@NonNull Call<List<Issues>> call, @NonNull Throwable t) {
Log.i(TAG, t.toString());
}
});
}, 1000);
if(!loadNextFlag) {
footerAdapter.clear();
}
}
@Override
public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
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.setOnQueryTextListener(new androidx.appcompat.widget.SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
return false;
}
@Override
public boolean onQueryTextChange(String newText) {
fastItemAdapter.filter(newText);
return true;
}
});
endlessRecyclerOnScrollListener.enable();
}
@Override
public void itemsFiltered(@Nullable CharSequence constraint, @Nullable List<IssuesAdapter> results) {
endlessRecyclerOnScrollListener.disable();
}
@Override
public void onReset() {
endlessRecyclerOnScrollListener.enable();
}
}

View File

@ -0,0 +1,155 @@
package org.mian.gitnex.fragments;
import android.content.Context;
import android.graphics.Typeface;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentStatePagerAdapter;
import androidx.viewpager.widget.ViewPager;
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.widget.TextView;
import com.google.android.material.tabs.TabLayout;
import org.mian.gitnex.R;
import org.mian.gitnex.util.TinyDB;
import java.util.Objects;
/**
* Author M M Arif
*/
public class IssuesMainFragment extends Fragment {
private Context ctx;
public IssuesMainFragment() {
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_issues_main, container, false);
setHasOptionsMenu(true);
TinyDB tinyDb = new TinyDB(getContext());
SectionsPagerAdapter mSectionsPagerAdapter = new IssuesMainFragment.SectionsPagerAdapter(getChildFragmentManager());
ViewPager mViewPager = v.findViewById(R.id.issuesContainer);
mViewPager.setAdapter(mSectionsPagerAdapter);
Typeface myTypeface;
if(tinyDb.getInt("customFontId") == 0) {
myTypeface = Typeface.createFromAsset(Objects.requireNonNull(getContext()).getAssets(), "fonts/roboto.ttf");
}
else if (tinyDb.getInt("customFontId") == 1) {
myTypeface = Typeface.createFromAsset(Objects.requireNonNull(getContext()).getAssets(), "fonts/manroperegular.ttf");
}
else if (tinyDb.getInt("customFontId") == 2) {
myTypeface = Typeface.createFromAsset(Objects.requireNonNull(getContext()).getAssets(), "fonts/sourcecodeproregular.ttf");
}
else {
myTypeface = Typeface.createFromAsset(Objects.requireNonNull(getContext()).getAssets(), "fonts/roboto.ttf");
}
TabLayout tabLayout = v.findViewById(R.id.tabs);
ViewGroup vg = (ViewGroup) tabLayout.getChildAt(0);
int tabsCount = vg.getChildCount();
for (int j = 0; j < tabsCount; j++) {
ViewGroup vgTab = (ViewGroup) vg.getChildAt(j);
int tabChildCount = vgTab.getChildCount();
for (int i = 0; i < tabChildCount; i++) {
View tabViewChild = vgTab.getChildAt(i);
if (tabViewChild instanceof TextView) {
((TextView) tabViewChild).setTypeface(myTypeface);
}
}
}
mViewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
tabLayout.addOnTabSelectedListener(new TabLayout.ViewPagerOnTabSelectedListener(mViewPager));
return v;
}
public static class SectionsPagerAdapter extends FragmentStatePagerAdapter {
SectionsPagerAdapter(FragmentManager fm) {
super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
}
@NonNull
@Override
public Fragment getItem(int position) {
Fragment fragment = null;
switch (position) {
case 0: // open issues
fragment = new IssuesOpenFragment();
break;
case 1: // closed issues
fragment = new IssuesClosedFragment();
break;
}
assert fragment != null;
return fragment;
}
@Override
public int getCount() {
return 2;
}
}
@Override
public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
menu.clear();
Objects.requireNonNull(getActivity()).getMenuInflater().inflate(R.menu.repo_dotted_menu, menu);
super.onCreateOptionsMenu(menu, inflater);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
switch (id) {
case android.R.id.home:
return true;
case R.id.repoMenu:
BottomSheetRepoFragment bottomSheet = new BottomSheetRepoFragment();
bottomSheet.show(getChildFragmentManager(), "repoBottomSheet");
return true;
default:
return super.onOptionsItemSelected(item);
}
}
}

View File

@ -0,0 +1,308 @@
package org.mian.gitnex.fragments;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.DefaultItemAnimator;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import android.os.Handler;
import android.util.Log;
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.ProgressBar;
import android.widget.TextView;
import com.mikepenz.fastadapter.IItemAdapter;
import com.mikepenz.fastadapter.adapters.ItemAdapter;
import com.mikepenz.fastadapter.commons.adapters.FastItemAdapter;
import com.mikepenz.fastadapter.listeners.ItemFilterListener;
import com.mikepenz.fastadapter_extensions.items.ProgressItem;
import com.mikepenz.fastadapter_extensions.scroll.EndlessRecyclerOnScrollListener;
import org.mian.gitnex.R;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.helpers.StaticGlobalVariables;
import org.mian.gitnex.helpers.VersionCheck;
import org.mian.gitnex.adapters.IssuesAdapter;
import org.mian.gitnex.models.Issues;
import org.mian.gitnex.util.TinyDB;
import java.util.ArrayList;
import java.util.List;
import static com.mikepenz.fastadapter.adapters.ItemAdapter.items;
/**
* Author M M Arif
*/
public class IssuesOpenFragment extends Fragment implements ItemFilterListener<IssuesAdapter> {
private ProgressBar mProgressBar;
private boolean loadNextFlag = false;
private String TAG = StaticGlobalVariables.tagIssuesListOpen;
private TextView noDataIssues;
private int resultLimit = StaticGlobalVariables.resultLimitOldGiteaInstances;
private String requestType = StaticGlobalVariables.issuesRequestType;
private List<IssuesAdapter> items = new ArrayList<>();
private FastItemAdapter<IssuesAdapter> fastItemAdapter;
private ItemAdapter footerAdapter;
private EndlessRecyclerOnScrollListener endlessRecyclerOnScrollListener;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
final View v = inflater.inflate(R.layout.fragment_issues, 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");
String repoFullName = tinyDb.getString("repoFullName");
String[] parts = repoFullName.split("/");
final String repoOwner = parts[0];
final String repoName = parts[1];
if (VersionCheck.compareVersion("1.12.0", tinyDb.getString("giteaVersion")) < 1) {
resultLimit = StaticGlobalVariables.resultLimitNewGiteaInstances;
}
noDataIssues = v.findViewById(R.id.noDataIssues);
mProgressBar = v.findViewById(R.id.progress_bar);
final SwipeRefreshLayout swipeRefreshLayout = v.findViewById(R.id.pullToRefresh);
RecyclerView recyclerView = v.findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
recyclerView.setHasFixedSize(true);
fastItemAdapter = new FastItemAdapter<>();
fastItemAdapter.withSelectable(true);
footerAdapter = items();
//noinspection unchecked
fastItemAdapter.addAdapter(StaticGlobalVariables.issuesPageInit, footerAdapter);
fastItemAdapter.getItemFilter().withFilterPredicate((IItemAdapter.Predicate<IssuesAdapter>) (item, constraint) -> item.getIssueTitle().toLowerCase().contains(constraint.toString().toLowerCase()));
fastItemAdapter.getItemFilter().withItemFilterListener(this);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.setAdapter(fastItemAdapter);
endlessRecyclerOnScrollListener = new EndlessRecyclerOnScrollListener(footerAdapter) {
@Override
public void onLoadMore(final int currentPage) {
loadNext(instanceUrl, instanceToken, repoOwner, repoName, resultLimit, requestType, currentPage);
}
};
swipeRefreshLayout.setOnRefreshListener(() -> {
mProgressBar.setVisibility(View.VISIBLE);
fastItemAdapter.clear();
endlessRecyclerOnScrollListener.resetPageCount();
swipeRefreshLayout.setRefreshing(false);
});
recyclerView.addOnScrollListener(endlessRecyclerOnScrollListener);
loadInitial(instanceUrl, instanceToken, repoOwner, repoName, resultLimit, requestType);
fastItemAdapter.withEventHook(new IssuesAdapter.IssueTitleClickEvent());
assert savedInstanceState != null;
fastItemAdapter.withSavedInstanceState(savedInstanceState);
return v;
}
@Override
public void onResume() {
super.onResume();
TinyDB tinyDb = new TinyDB(getContext());
if(tinyDb.getBoolean("resumeIssues")) {
mProgressBar.setVisibility(View.VISIBLE);
fastItemAdapter.clear();
endlessRecyclerOnScrollListener.resetPageCount();
tinyDb.putBoolean("resumeIssues", false);
}
}
private void loadInitial(String instanceUrl, String token, String repoOwner, String repoName, int resultLimit, String requestType) {
Call<List<Issues>> call = RetrofitClient.getInstance(instanceUrl, getContext()).getApiInterface().getIssues(token, repoOwner, repoName, 1, resultLimit, requestType);
call.enqueue(new Callback<List<Issues>>() {
@Override
public void onResponse(@NonNull Call<List<Issues>> call, @NonNull Response<List<Issues>> response) {
if(response.isSuccessful()) {
assert response.body() != null;
if(response.body().size() > 0) {
if(response.body().size() == resultLimit) {
loadNextFlag = true;
}
for(int i = 0; i < response.body().size(); i++) {
items.add(new IssuesAdapter(getContext()).withNewItems(response.body().get(i).getTitle(), response.body().get(i).getNumber(), response.body().get(i).getUser().getAvatar_url(), response.body().get(i).getCreated_at(), response.body().get(i).getComments(), response.body().get(i).getUser().getFull_name(), response.body().get(i).getUser().getLogin()));
}
fastItemAdapter.add(items);
noDataIssues.setVisibility(View.GONE);
}
else {
noDataIssues.setVisibility(View.VISIBLE);
}
mProgressBar.setVisibility(View.GONE);
}
else {
Log.i(TAG, String.valueOf(response.code()));
}
}
@Override
public void onFailure(@NonNull Call<List<Issues>> call, @NonNull Throwable t) {
Log.e(TAG, t.toString());
}
});
}
private void loadNext(String instanceUrl, String token, String repoOwner, String repoName, int resultLimit, String requestType, final int currentPage) {
footerAdapter.clear();
//noinspection unchecked
footerAdapter.add(new ProgressItem().withEnabled(false));
Handler handler = new Handler();
handler.postDelayed(() -> {
Call<List<Issues>> call = RetrofitClient.getInstance(instanceUrl, getContext()).getApiInterface().getIssues(token, repoOwner, repoName, currentPage + 1, resultLimit, requestType);
call.enqueue(new Callback<List<Issues>>() {
@Override
public void onResponse(@NonNull Call<List<Issues>> call, @NonNull Response<List<Issues>> response) {
if(response.isSuccessful()) {
assert response.body() != null;
if(response.body().size() > 0) {
loadNextFlag = response.body().size() == resultLimit;
for(int i = 0; i < response.body().size(); i++) {
fastItemAdapter.add(fastItemAdapter.getAdapterItemCount(), new IssuesAdapter(getContext()).withNewItems(response.body().get(i).getTitle(), response.body().get(i).getNumber(), response.body().get(i).getUser().getAvatar_url(), response.body().get(i).getCreated_at(), response.body().get(i).getComments(), response.body().get(i).getUser().getFull_name(), response.body().get(i).getUser().getLogin()));
}
footerAdapter.clear();
noDataIssues.setVisibility(View.GONE);
}
else {
footerAdapter.clear();
}
mProgressBar.setVisibility(View.GONE);
}
else {
Log.i(TAG, String.valueOf(response.code()));
}
}
@Override
public void onFailure(@NonNull Call<List<Issues>> call, @NonNull Throwable t) {
Log.i(TAG, t.toString());
}
});
}, 1000);
if(!loadNextFlag) {
footerAdapter.clear();
}
}
@Override
public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
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.setOnQueryTextListener(new androidx.appcompat.widget.SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
return false;
}
@Override
public boolean onQueryTextChange(String newText) {
fastItemAdapter.filter(newText);
return true;
}
});
endlessRecyclerOnScrollListener.enable();
}
@Override
public void itemsFiltered(@Nullable CharSequence constraint, @Nullable List<IssuesAdapter> results) {
endlessRecyclerOnScrollListener.disable();
}
@Override
public void onReset() {
endlessRecyclerOnScrollListener.enable();
}
}

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