Compare commits

...

487 Commits

Author SHA1 Message Date
Shihaam Abdul Rahman
b2604c1650 added mine and athafans domains 2021-11-04 23:20:31 +05:00
M M Arif
a4dee6a179 Update readme (#1013)
Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/1013
Co-authored-by: M M Arif <mmarif@noreply.codeberg.org>
Co-committed-by: M M Arif <mmarif@noreply.codeberg.org>
2021-11-01 09:15:55 +01:00
M M Arif
8d69c7b9ce Update CI (#1012)
Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/1012
Co-authored-by: M M Arif <mmarif@noreply.codeberg.org>
Co-committed-by: M M Arif <mmarif@noreply.codeberg.org>
2021-11-01 09:11:10 +01:00
M M Arif
367380921f Update CI (#1011)
Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/1011
Co-authored-by: M M Arif <mmarif@noreply.codeberg.org>
Co-committed-by: M M Arif <mmarif@noreply.codeberg.org>
2021-11-01 08:00:52 +01:00
qwerty287
471889f744 Fix CI (#1010)
* replace docker image with newer version (tested locally, `curl` and `apksigner` are available)
* update the container before signing. This is necessary because `curl` is outdated, but can be updated via `apt` (tested locally, working **only** after update)

I hope this way is fine, I don't really anything about docker and just tried to fix it :)

Co-authored-by: qwerty287 <ndev@web.de>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/1010
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
Co-authored-by: qwerty287 <qwerty287@noreply.codeberg.org>
Co-committed-by: qwerty287 <qwerty287@noreply.codeberg.org>
2021-10-31 21:26:08 +01:00
qwerty287
84551ca8be Split issue templates (#999)
Split the issue templates into `Bug`, `Feature` and `Suggestion`.

Co-authored-by: qwerty287 <ndev@web.de>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/999
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
Co-authored-by: qwerty287 <qwerty287@noreply.codeberg.org>
Co-committed-by: qwerty287 <qwerty287@noreply.codeberg.org>
2021-10-24 14:55:48 +02:00
qwerty287
b4d08a6733 Improve behavior of Android's back button in file browser (#1006)
Co-authored-by: qwerty287 <ndev@web.de>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/1006
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
Co-authored-by: qwerty287 <qwerty287@noreply.codeberg.org>
Co-committed-by: qwerty287 <qwerty287@noreply.codeberg.org>
2021-10-24 12:17:54 +02:00
qwerty287
2cf702982a Fix crash on issue search (#1005)
Co-authored-by: qwerty287 <ndev@web.de>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/1005
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
Co-authored-by: qwerty287 <qwerty287@noreply.codeberg.org>
Co-committed-by: qwerty287 <qwerty287@noreply.codeberg.org>
2021-10-24 12:10:22 +02:00
qwerty287
65ca86847f Update README (#1004)
* fix typo
* remove link to archived website repo
* change `F-droid` to `F-Droid`

Co-authored-by: qwerty287 <ndev@web.de>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/1004
Reviewed-by: 6543 <6543@noreply.codeberg.org>
Co-authored-by: qwerty287 <qwerty287@noreply.codeberg.org>
Co-committed-by: qwerty287 <qwerty287@noreply.codeberg.org>
2021-10-20 18:12:05 +02:00
M M Arif
64b9b07a9e CI (#998)
Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/998
Co-authored-by: M M Arif <mmarif@noreply.codeberg.org>
Co-committed-by: M M Arif <mmarif@noreply.codeberg.org>
2021-10-14 21:20:27 +02:00
M M Arif
d5cf4295bd Check CI (#997)
As title

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/997
Co-authored-by: M M Arif <mmarif@noreply.codeberg.org>
Co-committed-by: M M Arif <mmarif@noreply.codeberg.org>
2021-10-14 20:40:51 +02:00
M M Arif
8b0e3ee53d Kick start 4.2.0 (#996)
As title

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/996
Co-authored-by: M M Arif <mmarif@noreply.codeberg.org>
Co-committed-by: M M Arif <mmarif@noreply.codeberg.org>
2021-10-14 17:08:17 +02:00
Epsilon_02
a2cf46a896 Fix newline glitch on issue description. (#995)
### Describe what your pull request does and which issue you’re targeting
A single newline did not work in the description. Only with two newlines they are shown but now as two newlines.
<br><br>

<!-- Make sure you are targeting the "main" branch, pull requests on release branches are only allowed for bug fixes. -->

- [x] I carefully read the [contribution guidelines](https://codeberg.org/GitNex/GitNex/src/branch/main/CONTRIBUTING.md).
- [x] I'm following the code standards as defined [here](https://codeberg.org/gitnex/GitNex/wiki/Code-Standards).
- [x] By submitting this pull request, I permit GitNex to license my work under the [GNU General Public License v3](https://codeberg.org/GitNex/GitNex/src/branch/main/LICENSE).

Co-authored-by: Epsilon_02 <epsilon_02+codeberg@mailbox.org>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/995
Reviewed-by: 6543 <6543@noreply.codeberg.org>
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
Co-authored-by: Epsilon_02 <epsilon_02@noreply.codeberg.org>
Co-committed-by: Epsilon_02 <epsilon_02@noreply.codeberg.org>
2021-10-14 17:04:08 +02:00
M M Arif
495c9b4179 Prepare release 4.1.0 (#994)
Closes #978

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/994
Co-authored-by: M M Arif <mmarif@noreply.codeberg.org>
Co-committed-by: M M Arif <mmarif@noreply.codeberg.org>
2021-10-12 18:39:45 +02:00
6543
122c5c068d Crowdin 2021-10-06 (#991)
as title

Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/991
Reviewed-by: qwerty287 <qwerty287@noreply.codeberg.org>
Co-authored-by: 6543 <6543@noreply.codeberg.org>
Co-committed-by: 6543 <6543@noreply.codeberg.org>
2021-10-06 17:13:50 +02:00
M M Arif
a08cf13382 Render md in org/repo info (#986)
Co-authored-by: M M Arif <mmarif@noreply.codeberg.org>
Co-committed-by: M M Arif <mmarif@noreply.codeberg.org>
2021-10-05 17:16:22 +02:00
qwerty287
ba930021e7 Allow nav from issue to repo when coming from explore/notifications (#988)
Adds the navigation to explore/notifications too
closes #747

Co-authored-by: qwerty287 <ndev@web.de>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/988
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
Co-authored-by: qwerty287 <qwerty287@noreply.codeberg.org>
Co-committed-by: qwerty287 <qwerty287@noreply.codeberg.org>
2021-10-04 21:08:34 +02:00
qwerty287
6d9a64596f Center icons (#987)
As discussed in Discord

Co-authored-by: qwerty287 <ndev@web.de>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/987
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
Co-authored-by: qwerty287 <qwerty287@noreply.codeberg.org>
Co-committed-by: qwerty287 <qwerty287@noreply.codeberg.org>
2021-10-04 21:07:57 +02:00
M M Arif
22cd23525e Explore users (#972)
Closes #960

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/972
Reviewed-by: qwerty287 <qwerty287@noreply.codeberg.org>
Co-authored-by: M M Arif <mmarif@noreply.codeberg.org>
Co-committed-by: M M Arif <mmarif@noreply.codeberg.org>
2021-10-04 15:35:34 +02:00
M M Arif
f4cd3c9a4d Refactors and clean up (#979)
Related #278

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/979
Co-authored-by: M M Arif <mmarif@noreply.codeberg.org>
Co-committed-by: M M Arif <mmarif@noreply.codeberg.org>
2021-09-29 11:29:39 +02:00
M M Arif
b493dfc567 Filter issues by milestone (#980)
Closes #693

Right now I like how the API(filters) is for issues, for PRs it is only accepting Ids. It should be more like issues which has optional titles and more forgiving.

Maybe in the future will implement for PRs when the API become updated.

Issues:
https://codeberg.org/api/swagger#/issue/issueListIssues

PR:
https://codeberg.org/api/swagger#/repository/repoListPullRequests

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/980
Reviewed-by: qwerty287 <qwerty287@noreply.codeberg.org>
Co-authored-by: M M Arif <mmarif@noreply.codeberg.org>
Co-committed-by: M M Arif <mmarif@noreply.codeberg.org>
2021-09-28 11:10:27 +02:00
qwerty287
95aea16a07 Add option to update PR (#973)
### Describe what your pull request does and which issue you’re targeting
<!-- Create a new issue, if it doesn't exist yet -->
Closes #967
<br><br>

<!-- Make sure you are targeting the "main" branch, pull requests on release branches are only allowed for bug fixes. -->

- [X] I carefully read the [contribution guidelines](https://codeberg.org/GitNex/GitNex/src/branch/main/CONTRIBUTING.md).
- [X] I'm following the code standards as defined [here](https://codeberg.org/gitnex/GitNex/wiki/Code-Standards).
- [X] By submitting this pull request, I permit GitNex to license my work under the [GNU General Public License v3](https://codeberg.org/GitNex/GitNex/src/branch/main/LICENSE).

Co-authored-by: qwerty287 <ndev@web.de>
Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/973
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
Co-authored-by: qwerty287 <qwerty287@noreply.codeberg.org>
Co-committed-by: qwerty287 <qwerty287@noreply.codeberg.org>
2021-09-14 16:18:28 +02:00
qwerty287
77d1d448ba Fix visibility of "Mark as read" button (#975)
### Describe what your pull request does and which issue you’re targeting
<!-- Create a new issue, if it doesn't exist yet -->
Closes #970
<br><br>

<!-- Make sure you are targeting the "main" branch, pull requests on release branches are only allowed for bug fixes. -->

- [X] I carefully read the [contribution guidelines](https://codeberg.org/GitNex/GitNex/src/branch/main/CONTRIBUTING.md).
- [X] I'm following the code standards as defined [here](https://codeberg.org/gitnex/GitNex/wiki/Code-Standards).
- [X] By submitting this pull request, I permit GitNex to license my work under the [GNU General Public License v3](https://codeberg.org/GitNex/GitNex/src/branch/main/LICENSE).

Co-authored-by: qwerty287 <ndev@web.de>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/975
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
Co-authored-by: qwerty287 <qwerty287@noreply.codeberg.org>
Co-committed-by: qwerty287 <qwerty287@noreply.codeberg.org>
2021-09-02 08:52:18 +02:00
qwerty287
2659d87bbe Re-enable single release handler (#974)
Was disabled in #958 due to crashes related to this. This re-enables it but fixes the crashes.
Also adresses #955

- [X] I carefully read the [contribution guidelines](https://codeberg.org/GitNex/GitNex/src/branch/main/CONTRIBUTING.md).
- [X] I'm following the code standards as defined [here](https://codeberg.org/gitnex/GitNex/wiki/Code-Standards).
- [X] By submitting this pull request, I permit GitNex to license my work under the [GNU General Public License v3](https://codeberg.org/GitNex/GitNex/src/branch/main/LICENSE).

Co-authored-by: qwerty287 <ndev@web.de>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/974
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
Co-authored-by: qwerty287 <qwerty287@noreply.codeberg.org>
Co-committed-by: qwerty287 <qwerty287@noreply.codeberg.org>
2021-09-02 08:07:11 +02:00
qwerty287
3a38e4d7d5 Add options to follow and unfollow users (#971)
### Describe what your pull request does and which issue you’re targeting
<!-- Create a new issue, if it doesn't exist yet -->
Adds options to follow and unfollow users. Closes #968
<br><br>

<!-- Make sure you are targeting the "main" branch, pull requests on release branches are only allowed for bug fixes. -->

- [X] I carefully read the [contribution guidelines](https://codeberg.org/GitNex/GitNex/src/branch/main/CONTRIBUTING.md).
- [X] I'm following the code standards as defined [here](https://codeberg.org/gitnex/GitNex/wiki/Code-Standards).
- [X] By submitting this pull request, I permit GitNex to license my work under the [GNU General Public License v3](https://codeberg.org/GitNex/GitNex/src/branch/main/LICENSE).

Co-authored-by: qwerty287 <ndev@web.de>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/971
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
Co-authored-by: qwerty287 <qwerty287@noreply.codeberg.org>
Co-committed-by: qwerty287 <qwerty287@noreply.codeberg.org>
2021-08-31 09:33:26 +02:00
M M Arif
244dc12fc3 Kick start 4.1.0 (#966)
As title

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/966
Co-authored-by: M M Arif <mmarif@noreply.codeberg.org>
Co-committed-by: M M Arif <mmarif@noreply.codeberg.org>
2021-08-24 21:29:34 +02:00
M M Arif
8ea7e470c5 Prepare release 4.0.0 (#963)
Closes #956

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/963
Co-authored-by: M M Arif <mmarif@noreply.codeberg.org>
Co-committed-by: M M Arif <mmarif@noreply.codeberg.org>
2021-08-16 09:04:43 +02:00
M M Arif
77edf450c6 Translation updates (#962)
As title

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/962
Co-authored-by: M M Arif <mmarif@noreply.codeberg.org>
Co-committed-by: M M Arif <mmarif@noreply.codeberg.org>
2021-08-16 08:37:23 +02:00
M M Arif
e0ff35d530 [BUG] Releases should come before release tag (#958)
As title

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/958
Co-authored-by: M M Arif <mmarif@noreply.codeberg.org>
Co-committed-by: M M Arif <mmarif@noreply.codeberg.org>
2021-08-15 19:36:12 +02:00
qwerty287
f88a2df749 Enable user link handler and fix click on users in admin section (#957)
addresses #955
This pr does the following:
1. enables the users link handler
2. it allows clicks on the full `itemView` in the admin users section (related to https://codeberg.org/gitnex/GitNex/pulls/931#issuecomment-211296)

- [X] I carefully read the [contribution guidelines](https://codeberg.org/GitNex/GitNex/src/branch/main/CONTRIBUTING.md).
- [X] I'm following the code standards as defined [here](https://codeberg.org/gitnex/GitNex/wiki/Code-Standards).
- [X] By submitting this pull request, I permit GitNex to license my work under the [GNU General Public License v3](https://codeberg.org/GitNex/GitNex/src/branch/main/LICENSE).

Co-authored-by: qwerty287 <ndev@web.de>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/957
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
Co-authored-by: qwerty287 <qwerty287@noreply.codeberg.org>
Co-committed-by: qwerty287 <qwerty287@noreply.codeberg.org>
2021-08-11 14:47:31 +02:00
M M Arif
bb392fb639 Fix biometric bug in recent apps (#940)
Closes #930

Co-authored-by: M M Arif <mmarif@swatian.com>
Co-authored-by: opyale <opyale@noreply.codeberg.org>
Co-authored-by: 6543 <6543@noreply.codeberg.org>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/940
Co-authored-by: M M Arif <mmarif@noreply.codeberg.org>
Co-committed-by: M M Arif <mmarif@noreply.codeberg.org>
2021-08-03 09:41:40 +02:00
M M Arif
1693acaa70 User profile view (#931)
Closes #881

Please suggest on current data shown as some may be related to personal(email etc), but at this moment we have not much to show either. So sticking to it is my view on this.

I will extend the taps on profile images once we agree what to show.

@gitnex/Code-Managers

- [x] Detail
- [x] Repositories
- [x] Starred Repos
- [x] Followers
- [x] Following
- [x] Tap on all profile images
- [x] Organizations

Co-authored-by: M M Arif <mmarif@swatian.com>
Co-authored-by: opyale <opyale@noreply.codeberg.org>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/931
Reviewed-by: 6543 <6543@noreply.codeberg.org>
Co-authored-by: M M Arif <mmarif@noreply.codeberg.org>
Co-committed-by: M M Arif <mmarif@noreply.codeberg.org>
2021-08-02 20:04:33 +02:00
qwerty287
1e8c8efd6b Fix md rendering after editing file (#954)
### Describe what your pull request does and which issue you’re targeting
fixes #951
and you can review/merge it

- [X] I carefully read the [contribution guidelines](https://codeberg.org/GitNex/GitNex/src/branch/main/CONTRIBUTING.md).
- [X] I'm following the code standards as defined [here](https://codeberg.org/gitnex/GitNex/wiki/Code-Standards).
- [X] By submitting this pull request, I permit GitNex to license my work under the [GNU General Public License v3](https://codeberg.org/GitNex/GitNex/src/branch/main/LICENSE).

Co-authored-by: qwerty287 <ndev@web.de>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/954
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
Co-authored-by: qwerty287 <qwerty287@noreply.codeberg.org>
Co-committed-by: qwerty287 <qwerty287@noreply.codeberg.org>
2021-08-02 19:22:49 +02:00
qwerty287
5544ae4248 Add option to change times that are used to switch to light/dark theme (#932)
### Describe what your pull request does and which issue you’re targeting
Closes #928

This allows to select the time to switch between themes. The mentioned color/contrast problem with the time selection isn't fixed. I also simplified the settings code (0fe854fd49). And with [this](a590f5bc4c) GitNex hides the two options to change the time if your theme isn't `Auto (Light/Dark)` or `Auto (Retro/Dark)`. I could apply this also to the notifications settings, that means that the advanced settings for notifications (polling delay, light...) are hidden if the notifications aren't enabled.

this is ready to review/merge
<br><br>

<!-- Make sure you are targeting the "main" branch, pull requests on release branches are only allowed for bug fixes. -->

- [X] I carefully read the [contribution guidelines](https://codeberg.org/GitNex/GitNex/src/branch/main/CONTRIBUTING.md).
- [X] I'm following the code standards as defined [here](https://codeberg.org/gitnex/GitNex/wiki/Code-Standards).
- [X] By submitting this pull request, I permit GitNex to license my work under the [GNU General Public License v3](https://codeberg.org/GitNex/GitNex/src/branch/main/LICENSE).

Co-authored-by: qwerty287 <ndev@web.de>
Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/932
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
Co-authored-by: qwerty287 <qwerty287@noreply.codeberg.org>
Co-committed-by: qwerty287 <qwerty287@noreply.codeberg.org>
2021-08-02 18:59:30 +02:00
qwerty287
36f20bb1aa Add more link handlers (#948)
I can't implement every handler correctly, if there are no views that display them (e.g. a single milestone or release)

- [X] Organization #915
- [X] Milestones
- [X] Milestone
- [X] New milestone
- [X] Files
- [ ] Lines *currently opens file viewer*
- [X] Folders/directory's
- [X] Branches list
- [X] Branches
- [X] Releases
- [X] Release
- [X] new Release
- [X] Labels
- [X] Explore (orgs/repos)
- [X] Commits list
- [X] New issue
- [ ] Issue comments *currently opens the issue details*
- [X] New PR
- [ ] PR comments *currently opens the PR details*
- [X] PR diff
- [X] Your user profile
- [ ] User profiles *blocked by #931*
- [X] Gitea administration
- [X] Notifications
- [X] repository settings (only for repo admins)
- [X] Login screen

Commits: not possible, Gitea's API doesn't provide enough information to view the correct branch in the list and/or to display the diff.

Closes #918
Closes #915

Co-authored-by: qwerty287 <ndev@web.de>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/948
Reviewed-by: 6543 <6543@noreply.codeberg.org>
Co-authored-by: qwerty287 <qwerty287@noreply.codeberg.org>
Co-committed-by: qwerty287 <qwerty287@noreply.codeberg.org>
2021-07-23 17:41:19 +02:00
qwerty287
0e696eb46f Allow navigating from issue to repo (#937)
Allow navigating from issue opend by link to go back to repo

Closes #747

Co-authored-by: qwerty287 <ndev@web.de>
Co-authored-by: M M Arif <mmarif@noreply.codeberg.org>
Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/937
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
Reviewed-by: 6543 <6543@noreply.codeberg.org>
Co-authored-by: qwerty287 <qwerty287@noreply.codeberg.org>
Co-committed-by: qwerty287 <qwerty287@noreply.codeberg.org>
2021-07-09 17:36:59 +02:00
qwerty287
2b3b0fbe0f Fix Gitea version check (#945)
Closes #941

Co-authored-by: qwerty287 <ndev@web.de>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/945
Reviewed-by: 6543 <6543@noreply.codeberg.org>
Co-authored-by: qwerty287 <qwerty287@noreply.codeberg.org>
Co-committed-by: qwerty287 <qwerty287@noreply.codeberg.org>
2021-06-20 17:26:13 +02:00
M M Arif
f96827488b Hide mark as read button when no notifications are available (#938)
Closes #847

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/938
Reviewed-by: opyale <opyale@noreply.codeberg.org>
Co-authored-by: M M Arif <mmarif@noreply.codeberg.org>
Co-committed-by: M M Arif <mmarif@noreply.codeberg.org>
2021-06-17 22:00:33 +02:00
opyale
8d0df59bfe Fixing CI (#936)
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/936
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
Co-authored-by: opyale <opyale@noreply.codeberg.org>
Co-committed-by: opyale <opyale@noreply.codeberg.org>
2021-06-13 19:38:28 +02:00
qwerty287
d567a012d8 Add option to delete branch after pr got merged (#929)
### Describe what your pull request does and which issue you’re targeting
<!-- Create a new issue, if it doesn't exist yet -->
Closes #860
<br><br>

<!-- Make sure you are targeting the "main" branch, pull requests on release branches are only allowed for bug fixes. -->

- [X] I carefully read the [contribution guidelines](https://codeberg.org/GitNex/GitNex/src/branch/main/CONTRIBUTING.md).
- [X] I'm following the code standards as defined [here](https://codeberg.org/gitnex/GitNex/wiki/Code-Standards).
- [X] By submitting this pull request, I permit GitNex to license my work under the [GNU General Public License v3](https://codeberg.org/GitNex/GitNex/src/branch/main/LICENSE).

Co-authored-by: qwerty287 <ndev@web.de>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/929
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
Co-authored-by: qwerty287 <qwerty287@noreply.codeberg.org>
Co-committed-by: qwerty287 <qwerty287@noreply.codeberg.org>
2021-06-10 18:03:52 +02:00
M M Arif
0fc845e058 Small improvements to About dialog (#927)
As title

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/927
Reviewed-by: opyale <opyale@noreply.codeberg.org>
Co-authored-by: M M Arif <mmarif@noreply.codeberg.org>
Co-committed-by: M M Arif <mmarif@noreply.codeberg.org>
2021-06-06 21:15:32 +02:00
qwerty287
b97fa45b18 Move settings arrays to resources (#924)
### Describe what your pull request does and which issue you’re targeting
<!-- Create a new issue, if it doesn't exist yet -->
Closes #920
<br><br>

<!-- Make sure you are targeting the "main" branch, pull requests on release branches are only allowed for bug fixes. -->

- [X] I carefully read the [contribution guidelines](https://codeberg.org/GitNex/GitNex/src/branch/main/CONTRIBUTING.md).
- [X] I'm following the code standards as defined [here](https://codeberg.org/gitnex/GitNex/wiki/Code-Standards).
- [X] By submitting this pull request, I permit GitNex to license my work under the [GNU General Public License v3](https://codeberg.org/GitNex/GitNex/src/branch/main/LICENSE).

Co-authored-by: qwerty287 <ndev@web.de>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/924
Reviewed-by: opyale <opyale@noreply.codeberg.org>
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
Co-authored-by: qwerty287 <qwerty287@noreply.codeberg.org>
Co-committed-by: qwerty287 <qwerty287@noreply.codeberg.org>
2021-06-05 16:07:05 +02:00
qwerty287
d458d60122 Add ScrollViews to DeepLink view (#923)
### Describe what your pull request does and which issue you’re targeting
<!-- Create a new issue, if it doesn't exist yet -->
Closes #921
<br><br>

<!-- Make sure you are targeting the "main" branch, pull requests on release branches are only allowed for bug fixes. -->

- [X] I carefully read the [contribution guidelines](https://codeberg.org/GitNex/GitNex/src/branch/main/CONTRIBUTING.md).
- [X] I'm following the code standards as defined [here](https://codeberg.org/gitnex/GitNex/wiki/Code-Standards).
- [X] By submitting this pull request, I permit GitNex to license my work under the [GNU General Public License v3](https://codeberg.org/GitNex/GitNex/src/branch/main/LICENSE).

Co-authored-by: qwerty287 <ndev@web.de>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/923
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
Reviewed-by: opyale <opyale@noreply.codeberg.org>
Co-authored-by: qwerty287 <qwerty287@noreply.codeberg.org>
Co-committed-by: qwerty287 <qwerty287@noreply.codeberg.org>
2021-05-30 20:57:02 +02:00
M M Arif
881aad5f2d New About App dialog, improvements and fixes (#922)
Possible fix for #917

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/922
Reviewed-by: opyale <opyale@noreply.codeberg.org>
Co-authored-by: M M Arif <mmarif@noreply.codeberg.org>
Co-committed-by: M M Arif <mmarif@noreply.codeberg.org>
2021-05-30 19:28:14 +02:00
qwerty287
547e7c705d Use language provided by system (#914)
Pr tries to implement support for usage of system language.

Currently work in progress.

- [x] add option to use system language
- [x] use this by default
- [x] fix other usages of db value "locale"
- [X] fix usages of `Locale.getDefault()` (except [here](https://codeberg.org/gitnex/GitNex/src/branch/main/app/src/main/java/org/mian/gitnex/helpers/ssl/MemorizingTrustManager.java#L429))
- [ ] get language list programmaticaly
- [X] localize language names (related to #101)
- [X] move languages list to ~~Hashmap~~ TreeMap (it seems that HashMaps sort everything in a random order)

I carefully read the [contribution guidelines](https://codeberg.org/GitNex/GitNex/src/branch/main/CONTRIBUTING.md).
I'm following the code standards as defined [here](https://codeberg.org/gitnex/GitNex/wiki/Code-Standards).
By submitting this pull request, I permit GitNex to license my work under the [GNU General Public License v3](https://codeberg.org/GitNex/GitNex/src/branch/main/LICENSE).
<br>
Fixes #899

Co-authored-by: qwerty287 <ndev@web.de>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/914
Reviewed-by: opyale <opyale@noreply.codeberg.org>
Co-authored-by: qwerty287 <qwerty287@noreply.codeberg.org>
Co-committed-by: qwerty287 <qwerty287@noreply.codeberg.org>
2021-05-29 18:21:48 +02:00
qwerty287
cc70fe9a68 Make markdown links clickable (#916)
Pr makes links in markdown clickable.

Closes #797
<br><br>

- [X] I carefully read the [contribution guidelines](https://codeberg.org/GitNex/GitNex/src/branch/main/CONTRIBUTING.md).
- [X] I'm following the code standards as defined [here](https://codeberg.org/gitnex/GitNex/wiki/Code-Standards).
- [X] By submitting this pull request, I permit GitNex to license my work under the [GNU General Public License v3](https://codeberg.org/GitNex/GitNex/src/branch/main/LICENSE).

Co-authored-by: qwerty287 <ndev@web.de>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/916
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
Co-authored-by: qwerty287 <qwerty287@noreply.codeberg.org>
Co-committed-by: qwerty287 <qwerty287@noreply.codeberg.org>
2021-05-28 21:23:07 +02:00
M M Arif
3b3b0ada2f Public organizations (#906)
Closes #903

Co-authored-by: M M Arif <mmarif@swatian.com>
Co-authored-by: opyale <opyale@noreply.codeberg.org>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/906
Reviewed-by: opyale <opyale@noreply.codeberg.org>
Co-authored-by: M M Arif <mmarif@noreply.codeberg.org>
Co-committed-by: M M Arif <mmarif@noreply.codeberg.org>
2021-05-25 22:39:06 +02:00
M M Arif
a9f1010add Improve reply comment title (#912)
Closes #910

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/912
Reviewed-by: opyale <opyale@noreply.codeberg.org>
Co-authored-by: M M Arif <mmarif@noreply.codeberg.org>
Co-committed-by: M M Arif <mmarif@noreply.codeberg.org>
2021-05-25 21:26:21 +02:00
qwerty287
c8872ade9f Fix typo (#911)
Fixes "Crodwin" typo

- [X] I carefully read the [contribution guidelines](https://codeberg.org/GitNex/GitNex/src/branch/main/CONTRIBUTING.md).
- [X] I'm following the code standards as defined [here](https://codeberg.org/gitnex/GitNex/wiki/Code-Standards).
- [X] By submitting this pull request, I permit GitNex to license my work under the [GNU General Public License v3](https://codeberg.org/GitNex/GitNex/src/branch/main/LICENSE).

Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/911
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
Co-authored-by: qwerty287 <qwerty287@noreply.codeberg.org>
Co-committed-by: qwerty287 <qwerty287@noreply.codeberg.org>
2021-05-25 14:35:30 +02:00
opyale
960eaa1cf9 Fix missing docker image. (#909)
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/909
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
Co-authored-by: opyale <opyale@noreply.codeberg.org>
Co-committed-by: opyale <opyale@noreply.codeberg.org>
2021-05-24 14:42:08 +02:00
qwerty287
224ead33bf Fix going back from about fragment (#908)
### Describe what your pull request does and which issue you’re targeting
This PR fixes the problem that you can't go back from the "About" section in the settings and it changes the action bar behaviour of the about fragment to keep the design consistent (see below).

The activity action bar is hidden [here](82ffeefdc4/app/src/main/java/org/mian/gitnex/fragments/AboutFragment.java (L35)), as the about fragment uses it's own (in my implementation) to keep the design consistent (currently, all sections of the settings are own activitys and their action bar has a close button, except the about section). If you don't like this, I can remove it, but currently, it doesn't look nice integrated.

Closes #905

- [X] I carefully read the [contribution guidelines](https://codeberg.org/GitNex/GitNex/src/branch/main/CONTRIBUTING.md).
- [X] I'm following the code standards as defined [here](https://codeberg.org/gitnex/GitNex/wiki/Code-Standards).
- [X] By submitting this pull request, I permit GitNex to license my work under the [GNU General Public License v3](https://codeberg.org/GitNex/GitNex/src/branch/main/LICENSE).

Co-authored-by: qwerty287 <ndev@web.de>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/908
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
Co-authored-by: qwerty287 <qwerty287@noreply.codeberg.org>
Co-committed-by: qwerty287 <qwerty287@noreply.codeberg.org>
2021-05-23 22:29:11 +02:00
opyale
1dd615fcae Moving to 'main' branch (#902)
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/902
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
Co-authored-by: opyale <opyale@noreply.codeberg.org>
Co-committed-by: opyale <opyale@noreply.codeberg.org>
2021-05-01 20:30:44 +02:00
M M Arif
8741074906 UI improvements and update translation file (#900)
Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/900
Reviewed-by: 6543 <6543@noreply.codeberg.org>
Co-authored-by: M M Arif <mmarif@noreply.codeberg.org>
Co-committed-by: M M Arif <mmarif@noreply.codeberg.org>
2021-05-01 00:01:22 +02:00
M M Arif
23b8301fbf Fix repo desc in recyclerview (#896)
fixes and clean up

Use Authorization.get()

minor  fixes

Fix repo desc in recyclerview

Co-authored-by: M M Arif <mmarif@swatian.com>
Co-authored-by: opyale <opyale@noreply.codeberg.org>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/896
Reviewed-by: opyale <opyale@noreply.codeberg.org>
Co-Authored-By: M M Arif <mmarif@noreply.codeberg.org>
Co-Committed-By: M M Arif <mmarif@noreply.codeberg.org>
2021-04-15 17:05:56 +02:00
opyale
d72f097012 Implement multi-session notification polling and additional improvements/refactors/cleanups/fixes (#875)
Merge branch 'master' of https://codeberg.org/gitnex/GitNex into notifications-performance-improvements

 Conflicts:
	app/src/main/java/org/mian/gitnex/adapters/DraftsAdapter.java
	app/src/main/java/org/mian/gitnex/adapters/NotificationsAdapter.java
	app/src/main/java/org/mian/gitnex/adapters/UserAccountsAdapter.java
	app/src/main/java/org/mian/gitnex/adapters/UserAccountsNavAdapter.java
	app/src/main/res/layout/bottom_sheet_repository_in_list.xml
	app/src/main/res/layout/list_files.xml

Merge branch 'master' into notifications-performance-improvements

Merge branch 'master' into notifications-performance-improvements

Merge branch 'master' of https://codeberg.org/gitnex/GitNex into notifications-performance-improvements

 Conflicts:
	app/src/main/res/values-it/strings.xml

Add ripple effect to buttons.

Run syntax highlighting on separate thread. (#859)

Initial commit.

Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/875
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
Co-Authored-By: opyale <opyale@noreply.codeberg.org>
Co-Committed-By: opyale <opyale@noreply.codeberg.org>
2021-04-13 20:56:50 +02:00
M M Arif
9d3cd49d23 New UI for multiple screens (#894)
clean up

Another round of ui improvements and some refactors

Minor improvements.

Hide user accounts frame while list is loading

Remove unnecessary attribute

Minor improvements.

Define avatar size in lists globally.

Improvemnts to some ui elements

Improve layout of organizations and repositories.

Update the UI across most of the screens

Refactor org UI

clean up repo layout

Add archived msg instead of label

Redesign repos UI

Move archived to repo detail screen

Co-authored-by: M M Arif <mmarif@swatian.com>
Co-authored-by: opyale <opyale@noreply.codeberg.org>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/894
Reviewed-by: opyale <opyale@noreply.codeberg.org>
Co-Authored-By: M M Arif <mmarif@noreply.codeberg.org>
Co-Committed-By: M M Arif <mmarif@noreply.codeberg.org>
2021-04-13 16:19:42 +02:00
opyale
27a4bab73c Remove "Android PdfViewer" library (#893)
Remove "Android PdfViewer" library

Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/893
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
Co-Authored-By: opyale <opyale@noreply.codeberg.org>
Co-Committed-By: opyale <opyale@noreply.codeberg.org>
2021-04-10 21:16:07 +02:00
M M Arif
69a5f00771 Add private icon in repo detail toolbar, switch to if by gradle lint (#892)
Hide repoTypeToolbar by default.

Merge branch 'master' into add-repo-status-icon

Add private icon in repo detail toolbar, switch to if by gradle lint

Co-authored-by: opyale <opyale@noreply.codeberg.org>
Co-authored-by: 6543 <6543@noreply.codeberg.org>
Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/892
Reviewed-by: opyale <opyale@noreply.codeberg.org>
Co-Authored-By: M M Arif <mmarif@noreply.codeberg.org>
Co-Committed-By: M M Arif <mmarif@noreply.codeberg.org>
2021-04-10 20:29:21 +02:00
opyale
8104889bf6 Improve markdown rendering performance (#890)
Use object pooling with up to 45 threads for improved parallelization in markdown rendering.

Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/890
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
Co-Authored-By: opyale <opyale@noreply.codeberg.org>
Co-Committed-By: opyale <opyale@noreply.codeberg.org>
2021-04-10 19:54:05 +02:00
M M Arif
bd3e6ff20a [Frontport] Tr updates (#871)
Tr updates

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/871
Reviewed-by: 6543 <6543@noreply.codeberg.org>
Co-Authored-By: M M Arif <mmarif@noreply.codeberg.org>
Co-Committed-By: M M Arif <mmarif@noreply.codeberg.org>
2021-04-01 12:02:35 +02:00
opyale
a384128c8f Launch Toasts on UI thread. (#868)
Launch Toasts on UI thread.

Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/868
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
Co-Authored-By: opyale <opyale@noreply.codeberg.org>
Co-Committed-By: opyale <opyale@noreply.codeberg.org>
2021-03-31 19:36:11 +02:00
opyale
4b140f3195 Fixing crash on ProfileFragment (#865)
Fixing crash on ProfileFragment

Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/865
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
Co-Authored-By: opyale <opyale@noreply.codeberg.org>
Co-Committed-By: opyale <opyale@noreply.codeberg.org>
2021-03-31 18:36:47 +02:00
M M Arif
4ccc66b04e Fix lock icon for repos (#864)
Fix lock icon for repos

Fix layout

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/864
Reviewed-by: opyale <opyale@noreply.codeberg.org>
Co-Authored-By: M M Arif <mmarif@noreply.codeberg.org>
Co-Committed-By: M M Arif <mmarif@noreply.codeberg.org>
2021-03-31 18:28:18 +02:00
M M Arif
7c6247782b [Frontport] Fix Acra and workmanager, update gradle (#856)
Move acra to application

[Frontport] Fix Acra and workmanager errors, update gradle

Fix ACRA and workmanager errors

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/856
Reviewed-by: opyale <opyale@noreply.codeberg.org>
Co-Authored-By: M M Arif <mmarif@noreply.codeberg.org>
Co-Committed-By: M M Arif <mmarif@noreply.codeberg.org>
2021-03-30 16:31:39 +02:00
opyale
3e5fca4f52 Fall back to plain text if syntax highlighting fails. (#854)
[HotFix] Fall back to plain text if syntax highlighting fails.

upstream issue: https://github.com/noties/Prism4j/issues/8

Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/854
Reviewed-by: 6543 <6543@noreply.codeberg.org>
Co-Authored-By: opyale <opyale@noreply.codeberg.org>
Co-Committed-By: opyale <opyale@noreply.codeberg.org>
2021-03-30 00:31:26 +02:00
M M Arif
a848cabcda Release 3.5.0 (#850)
Release 3.5.0

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/850
Co-Authored-By: M M Arif <mmarif@noreply.codeberg.org>
Co-Committed-By: M M Arif <mmarif@noreply.codeberg.org>
2021-03-21 20:40:41 +01:00
6543
0b8d8618ed Update French (#849)
Update French

Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/849
Reviewed-by: opyale <opyale@noreply.codeberg.org>
Co-Authored-By: 6543 <6543@noreply.codeberg.org>
Co-Committed-By: 6543 <6543@noreply.codeberg.org>
2021-03-21 20:14:01 +01:00
6543
62ce30db23 Crowdin 2020-03-21 (#848)
Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/848
Reviewed-by: opyale <opyale@noreply.codeberg.org>
Co-Authored-By: 6543 <6543@noreply.codeberg.org>
Co-Committed-By: 6543 <6543@noreply.codeberg.org>
2021-03-21 19:57:34 +01:00
opyale
dc29a31e63 Replacing highlightJS with custom view due to performance issues and high file sizes. (#837)
Fixing crash and minor improvements.

Add ".properties" and ".ini" formats.

Increase surface area of files list item.

Fixing issue where some source code is not visible.

Replacing highlightJS with custom view due to performance issues and high file sizes.

Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/837
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
Reviewed-by: 6543 <6543@noreply.codeberg.org>
Co-Authored-By: opyale <opyale@noreply.codeberg.org>
Co-Committed-By: opyale <opyale@noreply.codeberg.org>
2021-03-21 19:26:28 +01:00
opyale
98cf1a1976 Improve file type handling. (#841)
Removing file size selection dialog in favor of hardcoded value.

Adding warning to file size picker and minor improvements.

Bump dependencies and gradle

Merge branch 'master' of https://codeberg.org/gitnex/GitNex into improve-filetype-recognition

Improving credits, adding symlink and submodule icons to FilesAdapter and removing unused libraries.

Minor improvements and bug fixes.

Add true progress indication routine for copying streams.

Merge branch 'master' of https://codeberg.org/gitnex/GitNex into improve-filetype-recognition

Performance and memory usage improvements

Notification improvements

Renaming StaticGlobalVariables to Constants

Overall improvements and fixes.

Merge branch 'master' of https://codeberg.org/gitnex/GitNex into improve-filetype-recognition

Add additional image formats.

Adding audio and video categories.

Merge branch 'master' of https://codeberg.org/gitnex/GitNex into improve-filetype-recognition

Improve file type handling.

Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/841
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
Co-Authored-By: opyale <opyale@noreply.codeberg.org>
Co-Committed-By: opyale <opyale@noreply.codeberg.org>
2021-03-21 16:56:54 +01:00
6543
ef3108db14 Crowdin 2021-03-18 (#845)
Crowdin 2021-03-18

Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/845
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
Co-Authored-By: 6543 <6543@noreply.codeberg.org>
Co-Committed-By: 6543 <6543@noreply.codeberg.org>
2021-03-18 11:48:54 +01:00
M M Arif
f1c88921bc Update readme (#844)
add line for used trademarks

update readme

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/844
Reviewed-by: opyale <opyale@noreply.codeberg.org>
Co-Authored-By: M M Arif <mmarif@noreply.codeberg.org>
Co-Committed-By: M M Arif <mmarif@noreply.codeberg.org>
2021-03-10 13:05:07 +01:00
M M Arif
fb0bd0299c Disable cancel repo settings dialogs (#843)
Merge branch 'master' into disable-dialog-close-repo-settings

Disable cancel repo settings dialogs

Co-authored-by: opyale <opyale@noreply.codeberg.org>
Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/843
Reviewed-by: opyale <opyale@noreply.codeberg.org>
Co-Authored-By: M M Arif <mmarif@noreply.codeberg.org>
Co-Committed-By: M M Arif <mmarif@noreply.codeberg.org>
2021-03-09 22:21:42 +01:00
M M Arif
c353275ab8 Biometric support (#820)
Minor improvements.

Merge branch 'master' into biometric-support

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

Merge branch 'master' into biometric-support

Merge branch 'master' into biometric-support

UI transition improvements

check for older version(android 6+), support for android 10 and below

Fix material lib builds with new version

Merge branch 'biometric-support' of codeberg.org:gitnex/GitNex into biometric-support

Merge branch 'master' into biometric-support

# Conflicts:
#	app/src/main/java/org/mian/gitnex/activities/BaseActivity.java
#	app/src/main/res/values/strings.xml

Merge branch 'master' into biometric-support

Merge branch 'master' into biometric-support

Merge branch 'master' into biometric-support

set status to false

Merge branch 'master' into biometric-support

check for bimetric status on device

Merge branch 'master' of https://codeberg.org/gitnex/GitNex into biometric-support

close app if back button or cancel is clicked

Enable/disable and show biometric auth dialog

Layout

Co-authored-by: opyale <opyale@noreply.codeberg.org>
Co-authored-by: M M Arif <mmarif@swatian.com>
Co-authored-by: 6543 <6543@noreply.codeberg.org>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/820
Reviewed-by: opyale <opyale@noreply.codeberg.org>
Co-Authored-By: M M Arif <mmarif@noreply.codeberg.org>
Co-Committed-By: M M Arif <mmarif@noreply.codeberg.org>
2021-03-09 22:15:42 +01:00
M M Arif
328dbaa01c Copy user id to clipboard (#840)
Co-Authored-By: M M Arif <mmarif@noreply.codeberg.org>
Co-Committed-By: M M Arif <mmarif@noreply.codeberg.org>
2021-03-05 06:24:48 +01:00
opyale
ff915f1813 Make singletons threadsafe. (#838)
Merge branch 'master' into threadsafe-singletons

Make singletons threadsafe.

Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/838
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
Co-Authored-By: opyale <opyale@noreply.codeberg.org>
Co-Committed-By: opyale <opyale@noreply.codeberg.org>
2021-03-03 15:10:23 +01:00
6543
77e39952c1 Crowdin 2021-03-03 (#839)
Crowdin 2021-03-03

Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/839
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
Co-Authored-By: 6543 <6543@noreply.codeberg.org>
Co-Committed-By: 6543 <6543@noreply.codeberg.org>
2021-03-03 10:27:49 +01:00
M M Arif
afffb7c15a Switch to proper account for popular instances and other ui improvements (#836)
* improve navigation via keyboard

* switch to proper account for popular instances

* ui improvements

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/836
Reviewed-by: 6543 <6543@noreply.codeberg.org>
Co-Authored-By: M M Arif <mmarif@noreply.codeberg.org>
Co-Committed-By: M M Arif <mmarif@noreply.codeberg.org>
2021-02-25 00:22:11 +01:00
M M Arif
47d6c68410 Improve files ui and bug fix encoding in names (#834)
Minor UI and performance improvements.

use one image and remove relativelayout

Fix html codes in name, fix org fragment tab count to load Members

Improve files ui

Co-authored-by: opyale <opyale@noreply.codeberg.org>
Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/834
Reviewed-by: opyale <opyale@noreply.codeberg.org>
Co-Authored-By: M M Arif <mmarif@noreply.codeberg.org>
Co-Committed-By: M M Arif <mmarif@noreply.codeberg.org>
2021-02-21 23:15:46 +01:00
opyale
57ce453661 Fixing bug where path separators would be URL encoded. (#832)
Merge branch 'master' of https://codeberg.org/gitnex/GitNex into fix-path-encoding-issues

Fixing bug where path separators would be URL encoded.

Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/832
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
Co-Authored-By: opyale <opyale@noreply.codeberg.org>
Co-Committed-By: opyale <opyale@noreply.codeberg.org>
2021-02-17 14:51:20 +01:00
opyale
d8a14105c9 Fixing and improving scaling of images, improving performance by doing work that has to be done once only once and using different terminology. (#831)
remove unknown case for editing

Improve var names and code formatting

Minor improvements.

Restoring ACRA functionality.

Fixing and improving scaling of images, improving performance by doing work that has to be done once only once and using different terminology.

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/831
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
Co-Authored-By: opyale <opyale@noreply.codeberg.org>
Co-Committed-By: opyale <opyale@noreply.codeberg.org>
2021-02-13 20:31:38 +01:00
M M Arif
711711274e Fix canvas too large crash (#830)
fix crash by scaling the image resolution

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/830
Reviewed-by: 6543 <6543@noreply.codeberg.org>
Co-Authored-By: M M Arif <mmarif@noreply.codeberg.org>
Co-Committed-By: M M Arif <mmarif@noreply.codeberg.org>
2021-02-12 23:16:29 +01:00
6543
44b8ad8d1c Add crowdin-cli config template (#827)
Add example crowdin Config

„crowdin.yml“ ändern

now able to upload new strings.xml file

add crowdin config (without API key)

Co-authored-by: 6543 <6543@obermui.de>
Co-authored-by: 6543 <6543@noreply@gitea.io>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/827
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
Co-Authored-By: 6543 <6543@noreply.codeberg.org>
Co-Committed-By: 6543 <6543@noreply.codeberg.org>
2021-02-12 10:30:02 +01:00
6543
fc49e29703 Crowdin 2021-02-11 (#828)
Crowdin 2021-02-11

Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/828
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
Co-Authored-By: 6543 <6543@noreply.codeberg.org>
Co-Committed-By: 6543 <6543@noreply.codeberg.org>
2021-02-12 10:29:04 +01:00
opyale
7f8595defc Fixing theme issues in RepoStargazersActivity. (#825)
Merge branch 'master' into fixing-theme-on-stargazers

Fixing theme issues in RepoStargazersActivity.

Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/825
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
Co-Authored-By: opyale <opyale@noreply.codeberg.org>
Co-Committed-By: opyale <opyale@noreply.codeberg.org>
2021-02-11 14:40:06 +01:00
opyale
eb858f3535 Moving ApiInterface, WebInterface and models to different repository. (#824)
Gradle v6.8.2

Use release instead of commit hash.

Moving ApiInterface, WebInterface and models to different repository.

Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/824
Reviewed-by: 6543 <6543@noreply.codeberg.org>
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
Co-Authored-By: opyale <opyale@noreply.codeberg.org>
Co-Committed-By: opyale <opyale@noreply.codeberg.org>
2021-02-11 11:23:35 +01:00
opyale
29653cade2 Calling overloaded method first. (#823)
Calling overloaded method first.

Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/823
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
Co-Authored-By: opyale <opyale@noreply.codeberg.org>
Co-Committed-By: opyale <opyale@noreply.codeberg.org>
2021-02-09 13:51:13 +01:00
M M Arif
d72cd57cd7 Cron tasks (#817)
* Run task

* Add info popup dialog for details

* List cron tasks

* Add cron to admin screen

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/817
Reviewed-by: 6543 <6543@noreply.codeberg.org>
Co-Authored-By: M M Arif <mmarif@noreply.codeberg.org>
Co-Committed-By: M M Arif <mmarif@noreply.codeberg.org>
2021-02-04 04:47:00 +01:00
M M Arif
cb241d80f3 Fix crash on creating new file (#819)
Allow multi line text in desc inputs

Minor improvements.

Improving the selection of branches.

Default to first branch in spinner.

Minor improvements.

fix crash on creating new file

Co-authored-by: M M Arif <mmarif@swatian.com>
Co-authored-by: opyale <opyale@noreply.codeberg.org>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/819
Reviewed-by: opyale <opyale@noreply.codeberg.org>
Co-Authored-By: M M Arif <mmarif@noreply.codeberg.org>
Co-Committed-By: M M Arif <mmarif@noreply.codeberg.org>
2021-02-01 19:13:48 +01:00
opyale
3c381f372e Add execution permissions for script. (#815)
Add execution permissions for script.

Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/815
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
Co-Authored-By: opyale <opyale@noreply.codeberg.org>
Co-Committed-By: opyale <opyale@noreply.codeberg.org>
2021-01-27 10:00:18 +01:00
opyale
2398995928 Update nextcloud image. (#814)
Update nextcloud image.

Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/814
Reviewed-by: 6543 <6543@noreply.codeberg.org>
Co-Authored-By: opyale <opyale@noreply.codeberg.org>
Co-Committed-By: opyale <opyale@noreply.codeberg.org>
2021-01-27 05:01:56 +01:00
opyale
7faf800d02 Changing docker image. (#813)
Changing docker image.

Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/813
Reviewed-by: 6543 <6543@noreply.codeberg.org>
Co-Authored-By: opyale <opyale@noreply.codeberg.org>
Co-Committed-By: opyale <opyale@noreply.codeberg.org>
2021-01-27 00:24:50 +01:00
opyale
d0c06a65f4 Add tool to set commit status. (#812)
Add tool to set commit status.

Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/812
Reviewed-by: 6543 <6543@noreply.codeberg.org>
Co-Authored-By: opyale <opyale@noreply.codeberg.org>
Co-Committed-By: opyale <opyale@noreply.codeberg.org>
2021-01-26 23:21:47 +01:00
M M Arif
20b203c4ad Render emoji in issue/pr titles, commit msg and markdown files (#805)
Merge branch 'master' into render-emoji-in-titles

Merge branch 'master' into render-emoji-in-titles

Merge branch 'master' into render-emoji-in-titles

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

Render emoji in issue/pr titles, commit msg and markdown files

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/805
Reviewed-by: opyale <opyale@noreply.codeberg.org>
Co-Authored-By: M M Arif <mmarif@noreply.codeberg.org>
Co-Committed-By: M M Arif <mmarif@noreply.codeberg.org>
2021-01-26 18:53:59 +01:00
M M Arif
b02c87b143 Support hx and ts files (#811)
Support hx and ts files

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/811
Reviewed-by: opyale <opyale@noreply.codeberg.org>
Co-Authored-By: M M Arif <mmarif@noreply.codeberg.org>
Co-Committed-By: M M Arif <mmarif@noreply.codeberg.org>
2021-01-26 18:48:24 +01:00
opyale
093204df43 Fixing layout issues and crashes. (#810)
Fixing layout issues and crashes.

Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/810
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
Co-Authored-By: opyale <opyale@noreply.codeberg.org>
Co-Committed-By: opyale <opyale@noreply.codeberg.org>
2021-01-26 18:43:25 +01:00
opyale
a26737e510 Rewriting deprecated code and adding view bindings to all fragments and activities. (#809)
Remove jetbrain import

Merge branch 'master' into deprecations

View bindings #3

View bindings #2

View bindings #1

Rewriting deprecated code.

Co-authored-by: M M Arif <mmarif@swatian.com>
Co-authored-by: M M Arif <mmarif@noreply.codeberg.org>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/809
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
Co-Authored-By: opyale <opyale@noreply.codeberg.org>
Co-Committed-By: opyale <opyale@noreply.codeberg.org>
2021-01-26 16:10:31 +01:00
opyale
371649b8ca Adding ProGuard rules to improve performance on low-spec devices. (#808)
Fixing failing build.

Bumping dependencies.

Adding ProGuard rules to improve performance on low-spec devices.

Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/808
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
Co-Authored-By: opyale <opyale@noreply.codeberg.org>
Co-Committed-By: opyale <opyale@noreply.codeberg.org>
2021-01-26 15:08:55 +01:00
M M Arif
8c62ecadbc Fix crash for offline mode org labels (#804)
Merge branch 'master' into fix-offline-org-labels

Fix crash for offline mode org labels

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/804
Reviewed-by: opyale <opyale@noreply.codeberg.org>
Co-Authored-By: M M Arif <mmarif@noreply.codeberg.org>
Co-Committed-By: M M Arif <mmarif@noreply.codeberg.org>
2021-01-14 18:42:35 +01:00
opyale
b75bf84d43 Rewriting deprecated code and improving offline mode. (#800)
Moving UI-related code to message queue of main thread.

Removing NetworkObserver in favor of NetworkStatusObserver

Some fixes.

Removing deprecated PreferenceManager.

Fixing crash.

Merge branch 'master' of https://codeberg.org/gitnex/GitNex into fix-performance-regression

 Conflicts:
	app/src/main/java/org/mian/gitnex/clients/RetrofitClient.java

Rewriting deprecated code.

Improving degraded performance due to unnecessary object allocation.

Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/800
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
Co-Authored-By: opyale <opyale@noreply.codeberg.org>
Co-Committed-By: opyale <opyale@noreply.codeberg.org>
2021-01-14 17:33:50 +01:00
opyale
5d2bb02b2d Improving degraded performance due to unnecessary object allocation. (#799)
Improving degraded performance due to unnecessary object allocation.

Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/799
Reviewed-by: 6543 <6543@noreply.codeberg.org>
Co-Authored-By: opyale <opyale@noreply.codeberg.org>
Co-Committed-By: opyale <opyale@noreply.codeberg.org>
2021-01-01 18:30:30 +01:00
M M Arif
fef1597522 dev-3.5.0 (#798)
fix typo

start dev of 3.5.0

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/798
Co-Authored-By: M M Arif <mmarif@noreply.codeberg.org>
Co-Committed-By: M M Arif <mmarif@noreply.codeberg.org>
2021-01-01 12:57:16 +01:00
6543
1f9a3eb85d Crowdin 2020-12-31 (#795)
CI.restart()

Crowdin 2020-12-31

Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/795
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
Co-Authored-By: 6543 <6543@noreply.codeberg.org>
Co-Committed-By: 6543 <6543@noreply.codeberg.org>
2020-12-31 16:55:13 +01:00
M M Arif
a51ba4f2a8 Fix offline mode (#794)
Closes #790

update libs

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/794
Reviewed-by: 6543 <6543@noreply.codeberg.org>
Co-Authored-By: M M Arif <mmarif@noreply.codeberg.org>
Co-Committed-By: M M Arif <mmarif@noreply.codeberg.org>
2020-12-31 15:38:18 +01:00
6543
4c4a7376cb Uppdate Supported Gitea Version Range (#793)
Uppdate Supported Gitea Versins

Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/793
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
Co-Authored-By: 6543 <6543@noreply.codeberg.org>
Co-Committed-By: 6543 <6543@noreply.codeberg.org>
2020-12-15 08:57:47 +01:00
M M Arif
bbbcb56b98 Organization labels (#771)
List, Create, Edit & Delete OrgLabels

Co-authored-by: M M Arif <mmarif@swatian.com>
Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/771
Reviewed-by: 6543 <6543@noreply.codeberg.org>
2020-11-30 23:20:14 +01:00
opyale
b871a1fb22 Removing left-over space in case no reactions are available (#782)
update gradle

Removing left-over space in case no reactions are available.

Co-authored-by: 6543 <6543@obermui.de>
Co-authored-by: 6543 <6543@noreply.codeberg.org>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/782
Reviewed-by: 6543 <6543@noreply.codeberg.org>
2020-11-30 00:26:01 +01:00
M M Arif
f2bc81210c Cap sentence start letters where necessary in input fields (#786)
Cap sentence start letters where necessary in input fields

Co-authored-by: 6543 <6543@noreply.codeberg.org>
Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/786
Reviewed-by: 6543 <6543@noreply.codeberg.org>
2020-11-29 23:41:44 +01:00
M M Arif
a6e97a1b36 Add new theme - Pitch Black (#787)
update drawables

Add new theme - Pitch Black

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/787
Reviewed-by: 6543 <6543@noreply.codeberg.org>
2020-11-29 22:51:35 +01:00
M M Arif
2ebcdf9186 Kick start dev of 3.4.0 (#781)
Kick start development of 3.4.0

Release 3.3.0

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/781
2020-11-18 08:25:34 +01:00
M M Arif
272fc78df9 [Frontport] Fix add new account (#779)
Fix add new account

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/779
Reviewed-by: 6543 <6543@noreply.codeberg.org>
2020-11-17 19:56:16 +01:00
M M Arif
3aa819f3ef [Frontport] Fix date and minor ui improvements (#774)
Fix date and minor ui improvements

Co-authored-by: 6543 <6543@noreply.codeberg.org>
Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/774
Reviewed-by: 6543 <6543@noreply.codeberg.org>
2020-11-17 05:40:58 +01:00
6543
e9fa2984a1 Update Translations 2020-11-16 (#775)
Update Translations 2020-11-16

Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/775
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
2020-11-16 14:13:43 +01:00
M M Arif
240cdf5701 Fix pr pagination (#770)
links improvement

Fix button alignment in polling delay popup

Fix pr pagination

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/770
2020-11-13 16:04:43 +01:00
M M Arif
a170c10e43 Improve deeplinks (#769)
Change to mainIntent

Add commit to deep links

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/769
2020-11-13 16:04:14 +01:00
opyale
d11da92fc4 Fixing missing emotes. (#768)
switch to tagged version (v5.1.2)

Using JitPack for artifact instead.

Fixing missing emotes.

Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/768
Reviewed-by: 6543 <6543@noreply.codeberg.org>
2020-11-08 23:57:33 +01:00
M M Arif
3b53111981 3.3.0 rc3 release (#766)
3.3.0 rc3 release

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/766
2020-11-08 20:09:29 +01:00
opyale
ade7b797f1 Add Issue/Comment Reactions (#557)
Minor performance improvements.

Merge branch 'master' of https://codeberg.org/gitnex/GitNex into issue-reactions

Improving color of selected elements.

First, fully working implementation of reactions.

Merge branch 'master' of https://codeberg.org/gitnex/GitNex into issue-reactions

 Conflicts:
	app/src/main/res/layout/bottom_sheet_issue_comments.xml
	app/src/main/res/layout/list_issue_comments.xml

(Hopefully) fixing merge issues.

Merge branch 'master' of https://codeberg.org/gitnex/GitNex into issue-reactions

 Conflicts:
	app/src/main/java/org/mian/gitnex/interfaces/ApiInterface.java
	app/src/main/res/layout/activity_issue_detail.xml
	app/src/main/res/layout/bottom_sheet_issue_comments.xml
	app/src/main/res/layout/bottom_sheet_single_issue.xml
	app/src/main/res/values/colors.xml

Moving reactions below time frame on comments.

Merge branch 'master' into layout-reactions

Add IssueReactions

Merge remote-tracking branch 'origin/layout-reactions' into layout-reactions

Merge branch 'master' of https://gitea.com/gitnex/GitNex into layout-reactions

Merge branch 'master' into layout-reactions

Applying to pulls and issues.

Merge branch 'master' of https://gitea.com/gitnex/GitNex into layout-reactions

Providing external layouts.

Some improvements.

Adding comment emote indications.

Adding circle around emotes.

Adding some padding.

First tests.

Co-authored-by: opyale <opyale@noreply.gitea.io>
Co-authored-by: 6543 <6543@obermui.de>
Co-authored-by: 6543 <6543@noreply.gitea.io>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/557
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
2020-11-08 19:58:47 +01:00
M M Arif
f97f668363 Improve nav drawer lag (#765)
Improve drawer nav lagginess

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/765
Reviewed-by: opyale <opyale@noreply.codeberg.org>
2020-11-06 02:09:34 +01:00
M M Arif
639cf51027 Org level labels in issue labels (#763)
Adding null checks.

Minor cleanups.

Merge branch 'master' into org-labels-in-issue

Fix repo size

Add new instances

Merge branch 'master' into org-labels-in-issue

Add org level labels to issue labels

Co-authored-by: opyale <opyale@noreply.codeberg.org>
Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/763
Reviewed-by: opyale <opyale@noreply.codeberg.org>
2020-11-05 13:10:17 +01:00
M M Arif
a92da6a6d4 Improve notifications (#764)
Moving translation.

Adding option to enable/disable notifications.

Fix typos

Improve notifications

Co-authored-by: opyale <opyale@noreply.codeberg.org>
Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/764
Reviewed-by: opyale <opyale@noreply.codeberg.org>
2020-11-03 20:14:24 +01:00
M M Arif
87379ae0b2 Refactor deeplinks (#762)
Minor improvements.

refactor deeplinks

Add popular instances taken from #758

Co-authored-by: opyale <opyale@noreply.codeberg.org>
Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/762
Reviewed-by: 6543 <6543@noreply.codeberg.org>
Reviewed-by: opyale <opyale@noreply.codeberg.org>
2020-11-02 18:01:06 +01:00
opyale
43166237ee Adding link to CI. (#761)
Adding link to CI.

Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/761
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
2020-11-02 16:25:45 +01:00
opyale
a3bd5c2af2 Increasing performance, fixing bugs and adding syntax highlighting. (#755)
Merge branch 'performance-highlight-refactor' of https://codeberg.org/opyale/GitNex into performance-highlight-refactor

Fixing theme recognition.

Merge branch 'master' into performance-highlight-refactor

Merge commit 'refs/pull/755/head' of codeberg.org:gitnex/GitNex into performance-highlight-refactor

Add new field issueType to db

Improving theme recognition.

Fixing alignment of menu button.

Fixing cut off text.

Merge commit 'refs/pull/755/head' of codeberg.org:gitnex/GitNex into performance-highlight-refactor

Fixing crash.

Refactoring activities.

Improving drafts.

Calculating density for avatars.

Improving drafts.

Calculating density for avatars.

Increasing size of avatar.

Decreasing size of avatar.

Restoring DeepLinksActivity

Merge branch 'master' of https://codeberg.org/gitnex/GitNex into performance-highlight-refactor

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

Initial commit.

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/755
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
2020-11-02 16:17:00 +01:00
6543
0f5858f292 Compress PNG (#759)
Compress PNG

Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/759
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
2020-11-02 16:01:59 +01:00
M M Arif
dcec158076 Remove liberapay (#754)
remove about screen

remove liberapay

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/754
2020-10-30 16:12:13 +01:00
M M Arif
63d3c95501 Release 3.3.0 rc2 (#753)
Release 3.3.0 rc2

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/753
2020-10-30 08:07:23 +01:00
M M Arif
f111f7f2df Fix scrolling issue for textareas (#752)
Add info msg for merge 405

Fix scrolling issue for textareas

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/752
2020-10-30 08:00:52 +01:00
opyale
5807d11e8c Fixing scrolling. (#751)
Fixing scrolling.

Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/751
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
2020-10-29 18:37:06 +01:00
opyale
4a9bde8731 Improving templates. (#746)
Additional improvements.

Merge branch 'master' into improving-templates

Improving templates.

Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/746
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
2020-10-29 17:24:19 +01:00
M M Arif
f64e23dcc1 Enhance settings screen and make it translation ready (#735)
Merge branch 'master' into enhance-settings-screen

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

Cleanup and refactor of activities

Fix bottomsheet

enhance code blocks and refactors

Move home screen to general, make it ready for translation

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/735
2020-10-29 14:13:19 +01:00
M M Arif
6a9144435e Layout and UI improvements (#738)
Layout and UI improvements

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/738
2020-10-29 13:53:03 +01:00
M M Arif
3c7b505b5b Fix view recycling issue (#742)
Fix view issue

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/742
2020-10-29 13:52:40 +01:00
M M Arif
2064c40c7d Remove deprecated startActivity for file download (#737)
Remove deprecated startActivity for file download

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/737
2020-10-29 13:51:52 +01:00
M M Arif
65c0ecaad1 Fix deep links (#743)
Fix opening links

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/743
Reviewed-by: 6543 <6543@noreply.codeberg.org>
2020-10-29 00:21:47 +01:00
M M Arif
99925621f1 Fix apk download image (#740)
Fix apk download image

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/740
2020-10-28 13:36:07 +01:00
M M Arif
d3fe4d6d41 3.3.0 rc release (#734)
Prepare 3.3.0 rc release

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/734
2020-10-25 12:46:25 +01:00
M M Arif
8e86fa668d Handle popular links (#730)
Fix settings layout

Merge branch 'master' into deeplinks

Support for all links, check gitea instance, add progress indicator

Enhance account checks, improve the experience of coming from links

Merge branch 'master' into deeplinks

Update libs

Minor layout fixes

gradle update

Fix show/hide views

Handle pr, repos. Handle settings for no action.

open issue from link

Add new settings section translation ready - General for generic settings

wip on handle popular links

Co-authored-by: M M Arif <mmarif@swatian.com>
Co-authored-by: 6543 <6543@obermui.de>
Co-authored-by: 6543 <6543@noreply.codeberg.org>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/730
2020-10-23 20:13:13 +02:00
M M Arif
044f6191bf New input design (#725)
Update missing buttons

update libs

login screen

Merge pr screen

create new file screen

This will be replaced later by custom built mentions, so removing the dependency.

create repo screen

comment screen

edit issue/pr screen and minor ui fixes

collaborator screen

release screen

label and milestone screens

move org, new team, new team member to new design

Add new user input transition

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/725
Reviewed-by: opyale <opyale@noreply.codeberg.org>
2020-10-20 20:09:07 +02:00
M M Arif
9e19945ad4 Add source of installation (#732)
Add source of installation

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/732
2020-10-17 07:36:44 +02:00
opyale
cafb29f8b7 Implementing BottomSheetFragment for commenting on issues and pull requests. (#555)
change to server error on onFailure

Fix keyboard move issue

Fix statusbar color, remove social, enhance other things

Merge branch 'master' into bottomsheet-issue-comments

Merge branch 'master' of https://codeberg.org/gitnex/GitNex into bottomsheet-issue-comments

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

Making it work.

Merge branch 'master' of https://codeberg.org/gitnex/GitNex into bottomsheet-issue-comments

Merge branch 'master' of https://codeberg.org/gitnex/GitNex into bottomsheet-issue-comments

Merge branch 'master' of https://codeberg.org/gitnex/GitNex into bottomsheet-issue-comments

First major changes.

Merge branch 'master' of https://codeberg.org/gitnex/GitNex into bottomsheet-issue-comments

Cleanup.

Simplifying title.

Adding BottomSheetFragment layout for future changes.

Co-authored-by: M M Arif <mmarif@swatian.com>
Co-authored-by: M M Arif <mmarif@noreply.codeberg.org>
Co-authored-by: opyale <opyale@noreply.gitea.io>
Co-authored-by: opyale <example@example.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/555
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
2020-10-12 20:11:23 +02:00
M M Arif
d346d68b4f Fix screen orientation reloads (#728)
Fix screen orientation reloads

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/728
Reviewed-by: 6543 <6543@noreply.codeberg.org>
2020-10-11 21:49:30 +02:00
M M Arif
57f0d23ef0 New popup for labels/assignees (#723)
Preventing lists to store duplicate collaborators (#726)

Using login instead of id.

Merge branch 'new-popup-labels-assigness' of https://codeberg.org/gitnex/GitNex into new-popup-labels-assigness

To prevent lists storing duplicate Collaborators

Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/726

Add current logged user to list

Change to collection

Fix depricated handler calls

Change to List and better naming

Move to actions

Merge branch 'master' into new-popup-labels-assigness

Add assignees popup and remove multi select

update to view binding

add/remove labels in edit issue

remove org call

Add org members to assignees list

Add assignees adapter

Add color to labels

Refactor and add new labels popup

Clean up build libs

Co-authored-by: opyale <opyale@noreply.codeberg.org>
Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/723
Reviewed-by: opyale <opyale@noreply.codeberg.org>
2020-10-09 17:47:52 +02:00
M M Arif
1e30c37d7c Improve repo files (#719)
Merge branch 'master' into improve-files

Improve repo files

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/719
2020-10-08 20:44:38 +02:00
M M Arif
1bf023357b Development of 3.3.0 (#722)
Development of 3.3.0

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/722
2020-10-05 18:29:19 +02:00
M M Arif
3235caf07d Add graphics for f-droid (#721)
Add graphics for f-droid

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/721
2020-10-05 17:36:54 +02:00
M M Arif
0f014c2822 Update readme (#718)
Update readme

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/718
2020-09-30 21:15:11 +02:00
M M Arif
996983d7a3 Release 3.2.0 (#717)
Prepare release 3.2.0

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/717
2020-09-30 21:08:48 +02:00
6543
00cfcbc9cf Crowdin 2020-09-30 (#716)
Crowdin 2020-09-30

Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/716
2020-09-30 20:45:50 +02:00
M M Arif
74669a9dcb Enhance explore repos (#715)
Enhance explore repos

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/715
2020-09-30 16:53:31 +02:00
M M Arif
d52d7a188e Search issues (#713)
Implement pagination

Use tabs for explore

add fragment, layout, adapter and implementation of api calls

Merge branch 'master' into 14-search-issues-pulls

Merge branch 'master' into 14-search-issues-pulls

Merge branch 'master' into 14-search-issues-pulls

Add menu item

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/713
2020-09-30 13:09:24 +02:00
M M Arif
d20a773d1d Extend explore repositories search (#703)
Merge branch 'master' into improve-explore-screen

improve email address input ui

Add filter query actions

Add radio buttons

improve nav accounts list images

Merge branch 'master' into improve-explore-screen

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

Implement dialog and use new input layout

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/703
2020-09-27 09:55:59 +02:00
M M Arif
bf19e52799 Move about and rate to settings screen (#714)
Move about and rate to settings screen

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/714
2020-09-27 09:36:57 +02:00
opyale
8612258174 Including releases in latest builds (#712)
Including releases in latest builds.

Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/712
Reviewed-by: 6543 <6543@noreply.codeberg.org>
2020-09-27 00:23:06 +02:00
M M Arif
a31abf0974 3.2.0 rc1 release (#709)
prepare 3.2.0 rc1 release

RC1 release of 3.2.0

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/709
2020-09-26 20:51:12 +02:00
6543
6d466e2542 Crowdin 2020-09-26 (#711)
Crowdin Update

Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/711
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
2020-09-26 20:50:15 +02:00
opyale
01bd61ad8e Fixing CI (#710)
Fixing CI.

Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/710
Reviewed-by: 6543 <6543@noreply.codeberg.org>
2020-09-26 20:21:29 +02:00
M M Arif
4031c32fc8 Introduce Pro version for play store (#708)
Introduce Pro version for play store

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/708
2020-09-26 17:05:51 +02:00
M M Arif
d51d2d5164 Android 11 support (#707)
update libs

Android 11 support

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/707
2020-09-26 15:55:30 +02:00
M M Arif
7b8bc21a83 Adjust logo with new colors (#706)
Adjust logo with new colors

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/706
2020-09-26 09:18:41 +02:00
M M Arif
1c1f73eafc Redo About screen UI and some refactors (#705)
Redo About screen UI and some refactors

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/705
2020-09-26 07:54:31 +02:00
M M Arif
02672aef3d Refactor: remove instanceUrlWithProtocol (#698)
Refactor: remove instanceUrlWithProtocol

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/698
2020-09-24 18:53:28 +02:00
M M Arif
23fb1ce71f Create PR (#689)
Merge branch 'master' into create-pr

consistent button height

implement create pr

Merge branch 'master' into create-pr

Remove save button for labels

minor improvements

new line

Implement interfaces for labels data

UI updates to labels dialog

Merge branch 'master' into create-pr

Merge branch 'master' of codeberg.org:gitnex/GitNex into master

Add labels list

Add ui elements, api calls for branches and milestone

Add activity, layout, click trigger and checks

Merge branch 'master' into create-pr

Merge branch 'master' of codeberg.org:gitnex/GitNex into master

Merge branch 'master' of codeberg.org:gitnex/GitNex into master

Add bs item

Merge branch 'master' of codeberg.org:gitnex/GitNex into master

Merge branch 'master' of codeberg.org:gitnex/GitNex into master

endline

Co-authored-by: 6543 <6543@noreply.codeberg.org>
Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/689
2020-09-24 18:51:20 +02:00
M M Arif
1f5eeb5632 Notification badge in navigation menu (#702)
Merge branch 'master' into 700-notifications-counter

Notification badge in navigation menu

Co-authored-by: 6543 <6543@noreply.codeberg.org>
Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/702
2020-09-18 06:51:41 +02:00
M M Arif
78782d159a UI improvements (#699)
UI improvements

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/699
2020-09-16 20:03:52 +02:00
M M Arif
a75ffe0381 Transfer repository ownership (#696)
simplify comments

Transfer repository ownership

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/696
2020-09-16 08:53:13 +02:00
M M Arif
c4279dcd77 Improve crash report notification string (#697)
Improve crash report notification string

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/697
2020-09-16 08:52:32 +02:00
6543
14b1256ce1 Crowdin 2020-09-13 (#694)
Add Czech

Update 2020-09-13

Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/694
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
2020-09-13 13:11:55 +02:00
M M Arif
7b72815bcb Add account new UI (#692)
Merge branch 'new-account-ui' of codeberg.org:gitnex/GitNex into new-account-ui

Merge branch 'master' into new-account-ui

Merge branch 'master' of codeberg.org:gitnex/GitNex into master

Merge branch 'master' into new-account-ui

Transition of adding account to new UI

Merge branch 'master' of codeberg.org:gitnex/GitNex into master

Merge branch 'master' of codeberg.org:gitnex/GitNex into master

endline

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/692
2020-09-13 06:57:04 +02:00
M M Arif
5e6c600e71 Repo settings (delete-edit) (#683)
better var names

remove migration

Merge branch 'repo-settings-delete-migrate-edit' of codeberg.org:gitnex/GitNex into repo-settings-delete-migrate-edit

delete repository

Merge branch 'master' into repo-settings-delete-migrate-edit

Can edit repo properties now

Add progress indicator, call for save

Pull repo info into dialog

Repo properties in custom dialog

settings activity with labels

Merge branch 'master' into repo-settings-delete-migrate-edit

Merge branch 'master' of codeberg.org:gitnex/GitNex into master

add bottom sheet entry

endline

Co-authored-by: M M Arif <mmarif@swatian.com>
Co-authored-by: 6543 <6543@noreply.codeberg.org>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/683
2020-09-13 06:54:05 +02:00
M M Arif
dbf5be25a5 Add stat indicator pr/issues (#686)
Merge branch 'master' into add-stat-indicator

Merge branch 'master' of codeberg.org:gitnex/GitNex into master

Show PR/Issue stat

Merge branch 'master' of codeberg.org:gitnex/GitNex into master

Merge branch 'master' of codeberg.org:gitnex/GitNex into master

endline

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/686
2020-09-13 06:52:30 +02:00
M M Arif
2bfe0b8d1a Fix create issue crash on label added and removed (#685)
Merge branch 'master' into fix-create-issue-crash

Merge branch 'master' of codeberg.org:gitnex/GitNex into master

Fix crash when label added and removed

Merge branch 'master' of codeberg.org:gitnex/GitNex into master

Merge branch 'master' of codeberg.org:gitnex/GitNex into master

endline

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/685
2020-09-13 06:50:06 +02:00
M M Arif
0c92eb3fa2 Fix active account selector (#687)
Merge branch 'master' into fix-active-account-selector

Merge branch 'master' of codeberg.org:gitnex/GitNex into master

Fix active account selector

Merge branch 'master' of codeberg.org:gitnex/GitNex into master

Merge branch 'master' of codeberg.org:gitnex/GitNex into master

endline

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/687
2020-09-13 06:48:30 +02:00
M M Arif
32f3080283 Fix fragments when view forks from repo info (#688)
Temp fix fragments forks

Merge branch 'master' of codeberg.org:gitnex/GitNex into master

Merge branch 'master' of codeberg.org:gitnex/GitNex into master

endline

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/688
2020-09-13 06:37:10 +02:00
opyale
7342668a1b Fixing gitlab ci releases (#690)
Fixing gitlab ci releases.

Co-authored-by: opyale <opyale@noreply.gitea.io>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/690
Reviewed-by: 6543 <6543@noreply.codeberg.org>
2020-09-08 20:44:12 +02:00
opyale
6f9bbe4c58 Optimizing user accounts list. (#684)
Optimizing user accounts list.

Co-authored-by: opyale <opyale@noreply.gitea.io>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/684
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
2020-09-07 16:29:04 +02:00
M M Arif
b2b42887f7 Move branch commits to files popup (#682)
Move commits to file sub menu

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/682
Reviewed-by: 6543 <6543@noreply.codeberg.org>
2020-09-05 15:43:29 +02:00
M M Arif
37f622b952 Update libs (#681)
Update libs

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/681
2020-09-04 16:33:59 +02:00
6543
d677c90b01 helper Version: add valid() function (#670)
Merge branch 'master' into VersionValid

format code

introduce Version.valid()

Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/670
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
2020-09-04 16:33:37 +02:00
M M Arif
23d3ba7f42 Fix crash on token logins with Require signin view enabled (#678)
Fix crash on token logins with Require signin view enabled

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/678
2020-09-03 19:26:24 +02:00
M M Arif
a42d888eb7 Share only stack trace (#675)
Share only stack trace

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/675
2020-09-03 18:12:53 +02:00
6543
bbcffd67d6 Crowdin 2020-08-28 (#668)
Crowdin 2020-08-28

Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/668
Reviewed-by: opyale <opyale@noreply.codeberg.org>
2020-09-02 21:08:23 +02:00
M M Arif
00eb9c9135 Fix edit comment draft (#661)
Fix edit comment draft

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/661
2020-08-24 12:03:16 +02:00
M M Arif
28a23d30f8 Fix crash on login (#662)
Fix crash on login

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/662
2020-08-24 12:02:45 +02:00
M M Arif
82f874dc37 Official start of 3.2 development (#660)
Official start of 3.2 development

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/660
2020-08-21 20:19:44 +02:00
M M Arif
b60a0e7a92 3.1.0 release (#659)
3.1.0 release

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/659
2020-08-21 18:32:56 +02:00
6543
185bdb863d Crowdin 2020-08-21 (#658)
Crowdin 2020-08-21

Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/658
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
2020-08-21 18:20:28 +02:00
M M Arif
da338fcc83 Fix styling radio buttons (#657)
Fix styling radio buttons

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/657
2020-08-21 16:59:54 +02:00
M M Arif
6d8a87358d Copy comment url to clipboard (#655)
Copy comment url to clipboard

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/655
2020-08-21 16:17:48 +02:00
M M Arif
5fc6cdde63 New Retro theme (#654)
New Retro theme

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/654
2020-08-20 18:21:55 +02:00
M M Arif
dc6b1bb5b6 Release 3.1.0 RC2 (#653)
Release 3.1.0 RC2

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/653
2020-08-19 09:07:12 +02:00
M M Arif
8768c87b8a Update missing progress bars (#652)
update missing progress bars

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/652
2020-08-18 19:55:34 +02:00
M M Arif
7caff70946 Edit and delete a file (#626)
update if file is modified on resume

implementation of edit file

Merge branch 'master' into 44-delete-file

Merge branch '44-delete-file' of codeberg.org:gitnex/GitNex into 44-delete-file

Merge branch 'master' into 44-delete-file

# Conflicts:
#	app/src/main/java/org/mian/gitnex/activities/CreateFileActivity.java
#	app/src/main/java/org/mian/gitnex/activities/FileViewActivity.java
#	app/src/main/java/org/mian/gitnex/activities/RepoDetailActivity.java
#	app/src/main/java/org/mian/gitnex/fragments/BottomSheetFileViewerFragment.java

Merge branch 'master' into 44-delete-file

implement delete file

add links to bottomsheet

Co-authored-by: M M Arif <mmarif@swatian.com>
Co-authored-by: 6543 <6543@noreply.codeberg.org>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/626
2020-08-18 16:37:10 +02:00
M M Arif
76137c56bc Improve drafts ui, add edited comments, create new ones on each call (#628)
Merge branch 'master' into 627-save-edit-draft

# Conflicts:
#	app/src/main/java/org/mian/gitnex/actions/IssueActions.java

Merge branch 'master' into 627-save-edit-draft

Improve drafts, add edited comments, create new ones on each call.

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/628
2020-08-18 16:11:31 +02:00
M M Arif
dcacf1f141 Design Accounts from Nav menu (#648)
Merge branch 'master' into new-account-design

Merge branch 'master' into new-account-design

enhance the dialog UI

Merge branch 'master' into new-account-design

New account design in nav with dialog popup list

New design for accounts accessing

Co-authored-by: 6543 <6543@noreply.codeberg.org>
Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/648
2020-08-18 16:10:46 +02:00
M M Arif
7585eb4834 Update bug icon (#651)
update bug icon

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/651
2020-08-17 19:08:29 +02:00
M M Arif
7dd231ee95 Set notifications as home srceen (#644) 2020-08-12 09:31:39 +02:00
M M Arif
d5fd6d8cc4 Fix share issue url (#643) 2020-08-12 09:31:06 +02:00
opyale
28963bb079 Using language instead of country. (#647)
Using language instead of country.

Co-authored-by: opyale <opyale@noreply.gitea.io>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/647
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
2020-08-11 18:32:30 +02:00
M M Arif
87649ebae8 Introduce new progress indicators (#638)
Add indicator to the rest of fragments/activities

Merge branch 'master' into profress-indicators

# Conflicts:
#	app/src/main/res/layout/activity_credits.xml
#	app/src/main/res/layout/activity_sponsors.xml

wip to remove old indicator

Make dark green as primary color, clean up app files

Introduce new progress indicators

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/638
2020-08-09 10:23:51 +02:00
M M Arif
a92969a47f Fix jumps in drawer when open for all items(icons, user data) (#639)
Fix drawer jumps when open for all items

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/639
2020-08-09 10:23:19 +02:00
M M Arif
d9cd04facf Layout improvements (#637)
Layout improvements

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/637
2020-08-08 17:43:14 +02:00
M M Arif
3eacfe91fe 3.1.0 RC1 release (#636)
3.1.0 RC1 release

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/636
2020-08-07 17:28:39 +02:00
M M Arif
e38d141d38 Quick labels, assignes dialog ui fixes (#635)
labels, assignes dialog ui fixes

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/635
2020-08-07 17:23:04 +02:00
M M Arif
7c40c049d4 Fix email login loop (can login with email again) (#629)
Merge branch 'master' into fix-email-logins

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

cleanup

Fix emails logins loop

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/629
2020-08-06 17:31:31 +02:00
M M Arif
b4b7981722 Open respective content when tap on repo info prs, watchers, forks, stargazers (#632)
Merge branch 'master' into open-repo-info-item

Open respective content when tap on repo info items, prs, watchers, forks, stargazers

Co-authored-by: 6543 <6543@noreply.codeberg.org>
Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/632
2020-08-06 17:19:37 +02:00
M M Arif
96fad2d73e Copy urls (#631)
fix url open in browser

Copy org and repo url

Copy urls

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/631
2020-08-06 17:18:02 +02:00
M M Arif
24064192e4 Enhance dialog buttons (#633)
switch to outline buttons

Enhance and fix color scheme for dialogs

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/633
2020-08-06 17:17:27 +02:00
M M Arif
12a7b6040b App wide UI changes and refactors (#630)
Enhance and update the buttons across the app, colorful animation on tap

update toasty in view models

update toasty in fragments

update toasty in actions, activities, adapters

Alert dialogs buttons arrangements

strings fixes

switch to fab buttons

remove snackbar

Enhance whole app UI, bring consistency among the elements

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/630
2020-08-06 17:16:51 +02:00
M M Arif
30921ea330 Multiple accounts support (#624)
Title update

Color clean up

switch to another account and update the token at login

Add new account

Add fab button for new account and activity

update libs

Remove account from Manage accounts list

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/624
Reviewed-by: 6543 <6543@noreply.codeberg.org>
2020-08-04 22:50:04 +02:00
M M Arif
ea36a3f6d6 Repository forks (#606)
Repository forks

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/606
Reviewed-by: 6543 <6543@noreply.codeberg.org>
2020-07-29 21:46:58 +02:00
M M Arif
f1ecc42876 Md support in file viewer (#607)
format

implement support for md on tap on icon

show icon for md files only

Add md to top bar

Co-authored-by: 6543 <6543@obermui.de>
Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/607
Reviewed-by: 6543 <6543@noreply.codeberg.org>
2020-07-29 20:45:05 +02:00
6543
73e7acfbdf Drop support for login with email (#622)
Drop support for login with email

Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/622
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
2020-07-29 20:28:24 +02:00
M M Arif
a9ad91d954 Fix drafts from notifications view (#618)
Fix drafts when coming from notifications

Fix star/watchers layout

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/618
Reviewed-by: 6543 <6543@noreply.codeberg.org>
2020-07-29 20:04:40 +02:00
6543
ff537b79ff BasicAuth Login: Handle existing token (#611)
fix code comment

bugfix

code format

Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/611
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
2020-07-29 16:27:47 +02:00
M M Arif
7efc8650fa Remove unlock for public repos (#605)
Remove unlock for public repos

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/605
Reviewed-by: 6543 <6543@noreply.codeberg.org>
2020-07-26 12:01:15 +02:00
M M Arif
a171abc0b8 Official start of 3.1.0 development (#603)
Official start of 3.1.0 development

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/603
2020-07-23 20:17:38 +02:00
M M Arif
0928e936d7 Prepare release (#599)
update  feature list in readme

Merge branch 'master' into 480-update-screenshots

update desc for f-droid

update screenshots, add changelogs

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/599
Reviewed-by: 6543 <6543@noreply.codeberg.org>
2020-07-23 19:35:46 +02:00
6543
a29011c6a2 Crowdin 2020-07-23 (#602)
Crowdin Update

Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/602
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
2020-07-23 18:38:18 +02:00
6543
c09fc4988a Support Samsung DeX (#601)
Support Samsung DeX

Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/601
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
2020-07-23 18:37:32 +02:00
opyale
39ac49b258 Notifications (#554)
Cleanup

Extending and improving notifications

Using new icons instead

Lowering polling delay to one minute and other improvements

Fixing minor issues

Simplifying progress layout

Fixing bugs and other improvements

Adding translations

Notifications

Co-authored-by: opyale <opyale@noreply.gitea.io>
Co-authored-by: 6543 <6543@noreply.codeberg.org>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/554
Reviewed-by: 6543 <6543@noreply.codeberg.org>
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
2020-07-22 21:32:42 +02:00
6543
cd55f946f0 Crowdin 2020-07-22 (#597)
Crowdin Update

Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/597
Reviewed-by: opyale <opyale@noreply.codeberg.org>
2020-07-22 14:48:12 +02:00
M M Arif
b529f81115 Fix some bugs (#596)
remove redundant casting

Fix edittext layout when typing(reduce size), fix refresh drafts. Minor improvements

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/596
Reviewed-by: 6543 <6543@noreply.codeberg.org>
2020-07-19 15:44:08 +02:00
M M Arif
e6109ef36d Search drafts (#574)
Merge branch 'master' into search-drafts

Merge branch 'master' into search-drafts

Merge branch 'master' into search-drafts

Merge branch 'master' into search-drafts

Merge branch 'master' into search-drafts

Merge branch 'master' into search-drafts

Merge branch 'master' into search-drafts

Merge branch 'master' into search-drafts

Merge branch 'master' into search-drafts

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

search drafts

Co-authored-by: 6543 <6543@noreply.codeberg.org>
Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/574
Reviewed-by: 6543 <6543@noreply.codeberg.org>
2020-07-19 12:33:58 +02:00
M M Arif
e00fcd846a Add missed icons and improve the ratio of all icons across the app (#592)
Merge branch 'master' into new-missing-icons

Merge branch 'master' into new-missing-icons

Fix background and icon

Fix search bar icons and layout to match the themes

new lines?

Merge branch 'master' into new-missing-icons

Add missed icons, and improve the ratio of all icons across the app

Co-authored-by: 6543 <6543@noreply.codeberg.org>
Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/592
2020-07-19 12:24:47 +02:00
M M Arif
060c86c090 Add server avatar to user accounts (#594)
Add server avatar to user accounts

Co-authored-by: 6543 <6543@noreply.codeberg.org>
Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/594
Reviewed-by: 6543 <6543@noreply.codeberg.org>
2020-07-19 12:13:37 +02:00
M M Arif
26f54280a1 Add explore and drafts to set as home screen options (#588)
Fix icon cut off sizes

Add explore and drafts to set as home screen options

Co-authored-by: 6543 <6543@noreply.codeberg.org>
Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/588
Reviewed-by: 6543 <6543@noreply.codeberg.org>
2020-07-19 12:05:08 +02:00
6543
8a7923cba7 Fix VersionCheck (#591)
code dedub

Bugfix & Test Correction

Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/591
Reviewed-by: opyale <opyale@noreply.codeberg.org>
2020-07-14 18:20:00 +02:00
6543
673b9f564c Crowdin 2020-07-14 (#590)
crowdin_2020-07-14

Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/590
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
2020-07-14 17:14:06 +02:00
M M Arif
d1be03956c Transition of old icons to new ones (#589)
last set of updates and changes to the icons

Add more icons

WIP : transition of more icons

Switch of icons to new icons for the whole app - WIP

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/589
Reviewed-by: 6543 <6543@noreply.codeberg.org>
2020-07-12 19:18:50 +02:00
M M Arif
caa437d5e3 Switch branches (#571)
Fix default branch

Merge branch 'master' into switch-branches

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

update icon

Merge branch 'master' into switch-branches

Merge branch 'master' into switch-branches

update the missing parts

Minor updates

Merge branch 'master' into switch-branches

Merge branch 'master' into switch-branches

# Conflicts:
#	app/src/main/java/org/mian/gitnex/activities/CreateIssueActivity.java
#	app/src/main/java/org/mian/gitnex/activities/RepoDetailActivity.java
#	app/src/main/java/org/mian/gitnex/fragments/BottomSheetRepoFragment.java
#	app/src/main/java/org/mian/gitnex/fragments/FilesFragment.java

Add branch to breadcrumb and dir structure fix

Make change branch work

clean up

Merge branch 'master' into switch-branches

add icon in top bar, add interface listener

Merge branch 'master' into switch-branches

Merge remote-tracking branch 'remotes/main/master' into switch-branches

# Conflicts:
#	app/src/main/java/org/mian/gitnex/activities/LoginActivity.java
#	app/src/main/java/org/mian/gitnex/fragments/ProfileFragment.java
#	app/src/main/java/org/mian/gitnex/helpers/PathsHelper.java

Switching between branches.

Minor fixes

Merge remote-tracking branch 'remotes/main/master' into login-fix

URL parsing, label and other improvements.

Co-authored-by: M M Arif <mmarif@swatian.com>
Co-authored-by: 6543 <6543@noreply.codeberg.org>
Co-authored-by: opyale <opyale@noreply.gitea.io>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/571
Reviewed-by: 6543 <6543@noreply.codeberg.org>
2020-07-12 17:14:50 +02:00
6543
25036ce5d2 Remove Unused Locales (#585)
Remove Unused Locales

Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/585
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
2020-07-11 12:49:35 +02:00
M M Arif
a8a34ccc7a New icons (#587)
repo info icons update

Update icons across the app

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/587
Reviewed-by: 6543 <6543@noreply.codeberg.org>
2020-07-10 22:54:09 +02:00
6543
f87e8020d8 Remove Unused Resources (#586)
Remove Unused Resources

Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/586
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
2020-07-10 12:43:51 +02:00
M M Arif
4d67e63db4 Fix license (#584)
Fix license

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/584
Reviewed-by: opyale <opyale@noreply.codeberg.org>
2020-07-09 17:42:13 +02:00
opyale
3561dde19f Badges and drone fix. (#583)
Removing link

Badges and drone fix.

Co-authored-by: opyale <opyale@noreply.gitea.io>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/583
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
2020-07-09 15:18:21 +02:00
M M Arif
9c48dec54d Delete drafts [settings] (#576)
Merge branch '450-drafts-settings' of codeberg.org:gitnex/GitNex into 450-drafts-settings

Fix package move

Merge branch 'master' into 450-drafts-settings

Merge branch 'master' into 450-drafts-settings

fix default value save

Delete drafts settings

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/576
Reviewed-by: opyale <opyale@noreply.codeberg.org>
2020-07-09 13:55:09 +02:00
opyale
3d72d68e14 Fixing CI (#582)
Fixing CI

Co-authored-by: opyale <opyale@noreply.gitea.io>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/582
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
2020-07-09 13:37:44 +02:00
opyale
47b24470e6 Improving CI. (#581)
Improving CI.

Co-authored-by: opyale <opyale@noreply.gitea.io>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/581
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
2020-07-09 13:29:36 +02:00
opyale
1db6a3294b Using GitLab CI. (#580)
Using smaller image and publishing releases.

Fixing things.

Merge branch 'gitlab-ci' of https://codeberg.org/opyale/GitNex into gitlab-ci

Removing eclint.

Merge branch 'master' into gitlab-ci

Only run jobs when master changed.

Using GitLab CI.

Co-authored-by: opyale <opyale@noreply.gitea.io>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/580
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
2020-07-09 08:55:05 +02:00
opyale
500dc019c1 Moving TinyDB and AppUtil to helpers. (#579)
Moving TinyDB and AppUtil to helpers.

Co-authored-by: opyale <opyale@noreply.gitea.io>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/579
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
2020-07-07 19:15:01 +02:00
M M Arif
e2aff890d7 Accounts overview screen (#577)
optimize url string

Overview of accounts in the app

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/577
Reviewed-by: opyale <opyale@noreply.codeberg.org>
2020-07-07 16:20:43 +02:00
M M Arif
cdfc2cfb9e Implement drafts, introduce Room persistence library for db (#139)
Fix no draft message

translation updates

format improvements

typo update

some renaming refactors

Use better naming convention

remove duplicate source

arrange draft titles

enhance click listener area

Launch drafts from reply screen and clean up

Add message draft saved

update repositories tasks

Update user accounts repository with thread, remove async tasks

remove async task in drafts

update layout, change async to thread in drafts

Merge branch 'master' into pull_139

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

Merge branch 'master' into pull_139

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

Merge branch 'pull_139' of codeberg.org:gitnex/GitNex into pull_139

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

Merge branch 'master' into pull_139

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

Merge branch 'master' into pull_139

Merge branch 'master' into pull_139

Merge branch 'master' into pull_139 and fix conflicts

# Conflicts:
#	app/build.gradle
#	app/src/main/java/org/mian/gitnex/activities/LoginActivity.java
#	app/src/main/java/org/mian/gitnex/activities/MainActivity.java
#	app/src/main/java/org/mian/gitnex/activities/ReplyToIssueActivity.java
#	app/src/main/java/org/mian/gitnex/adapters/MyReposListAdapter.java
#	app/src/main/java/org/mian/gitnex/helpers/StaticGlobalVariables.java
#	app/src/main/res/values/strings.xml

Code Format

Merge branch 'master' into 15-comments-draft

Merge branch 'master' into 15-comments-draft

Merge branch 'master' into 15-comments-draft

# Conflicts:
#	app/src/main/java/org/mian/gitnex/activities/MainActivity.java
#	app/src/main/res/values/strings.xml

Go to draft, save on type and other fixes

delete all drafts, added messages where needed

delete draft

Force logout

Merge branch 'master' into 15-comments-draft

Merge branch 'master' into 15-comments-draft

# Conflicts:
#	app/src/main/java/org/mian/gitnex/activities/MainActivity.java
#	app/src/main/java/org/mian/gitnex/helpers/StaticGlobalVariables.java

check if account data is null, we need to log the user out for the 1st time.

Merge branch 'master' into 15-comments-draft

fix repo owner, name sequence

Add comments for test, show drafts list

Add repos to db

Add account to db and other refactors to the code

Merge branch 'master' into 15-comments-draft

Merge branch 'master' into 15-comments-draft

Merge branch 'master' into 15-comments-draft

Merge branch 'master' into 15-comments-draft

# Conflicts:
#	app/build.gradle
#	app/src/main/AndroidManifest.xml

Merge branch 'master' into 15-comments-draft

merge

more queries, added dao repositories, layout update

Added queries in dao

some refactor. added models, dao, entities (accounts, repositories, drafts)

WIP on implementing drafts, introduced Room persistence library for db.

Co-authored-by: M M Arif <mmarif@swatian.com>
Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/139
Reviewed-by: opyale <opyale@noreply.codeberg.org>
2020-07-04 22:51:55 +02:00
M M Arif
f135508745 Release 3.0.0 rc3 (#570)
Release 3.0.0 rc3

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/570
2020-06-30 21:08:10 +02:00
M M Arif
3e5e94790e Update libs, remove depricated libs (#566)
proper decleration

Merge branch 'update-libs-fix-deps' of codeberg.org:gitnex/GitNex into update-libs-fix-deps

import searchview and other improvements

Merge branch 'master' into update-libs-fix-deps

Update libs, remove depricated libs

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/566
Reviewed-by: opyale <opyale@noreply.codeberg.org>
2020-06-30 20:59:11 +02:00
opyale
62aace4b91 Fix old URLs which do not have a slash at the end. (#568)
Merge branch 'master' into fix-older-urls

Fix old URLs which do not have a slash at the end.

Co-authored-by: opyale <opyale@noreply.gitea.io>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/568
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
2020-06-30 20:36:24 +02:00
opyale
2412245a9f Fixing path issues. (#567)
Fixing path issues.

Co-authored-by: opyale <opyale@noreply.gitea.io>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/567
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
2020-06-30 20:19:55 +02:00
opyale
e872069093 Proper URL parsing, label redesign and other improvements. (#564)
Final improvements.

Fixing reply mention.

Do NOT use "instanceUrlRaw" as of now.

Minor fixes

Merge remote-tracking branch 'remotes/main/master' into login-fix

URL parsing, label and other improvements.

Co-authored-by: opyale <opyale@noreply.gitea.io>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/564
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
2020-06-30 16:43:27 +02:00
opyale
5672208fd0 Adding ability to quote and to copy issue comments. (#562)
Minor fix.

Merge branch 'master' into reply-tools

Merge remote-tracking branch 'opyale/reply-tools' into reply-tools

Changing names.

Merge branch 'master' into reply-tools

Adding ability to cite and to copy issue comments.

Co-authored-by: opyale <opyale@noreply.gitea.io>
Co-authored-by: 6543 <6543@noreply.codeberg.org>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/562
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
2020-06-28 19:26:59 +02:00
opyale
7379e9945d Fixing bugs of previous pull (#563)
Fixing bugs of previous pull.

Co-authored-by: opyale <opyale@noreply.gitea.io>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/563
Reviewed-by: 6543 <6543@noreply.codeberg.org>
2020-06-28 18:48:33 +02:00
opyale
815417bf11 Refactoring LoginActivity and other improvements. (#561)
Adding error message for login().

Final touch.

Refactoring LoginActivity and other improvements.

Co-authored-by: opyale <opyale@noreply.gitea.io>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/561
Reviewed-by: 6543 <6543@noreply.codeberg.org>
2020-06-28 17:11:59 +02:00
M M Arif
95fc5e1e9a Fix bug #549, add more file ext to file viewer (#560)
Fix empty release notes bug

Add new sponsor

Fix bug #549, add more file ext to file viewer

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/560
Reviewed-by: opyale <opyale@noreply.codeberg.org>
Reviewed-by: 6543 <6543@noreply.codeberg.org>
2020-06-28 16:45:39 +02:00
6543
f285d47a0b Fix Crash on closed PRs with deleted Fork (#559)
Fix edge-case DeletedFork of a Pull-Branch

Co-authored-by: 6543 <6543@obermui.de>
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
2020-06-26 17:09:18 +02:00
opyale
2483968f11 Inverting color of divider too (#553)
Inverting color of divider too

Co-authored-by: opyale <opyale@noreply.gitea.io>
Reviewed-by: 6543 <6543@noreply.codeberg.org>
2020-06-25 01:27:13 +02:00
opyale
d0fde4e791 Adjusting icon color to fit background. (#551)
Adjusting icon color to fit background.

Co-authored-by: opyale <opyale@noreply.gitea.io>
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
2020-06-24 23:02:22 +02:00
M M Arif
c7c2ac2a11 Enhance bottomsheets ui (#550)
Fix name collision in themes

Add space between org and repo name

standard use of dimens

more ui improvements

wip to enhance all bottom sheets

Fix radius and improve the ui

enhance bottom sheet

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-by: opyale <opyale@noreply.codeberg.org>
2020-06-24 22:29:58 +02:00
6543
4f79ea0156 Fix Crash when searching issues/pr (#547)
fix in pr and ms fragments

Fix Crash when searching issues/pr

Co-authored-by: M M Arif <mmarif@swatian.com>
Co-authored-by: 6543 <6543@obermui.de>
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
2020-06-24 17:05:02 +02:00
M M Arif
22943ca9cd Fix user team search crash (#545)
Fix team user search crash

Refactor userName

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-by: 6543 <6543@noreply.codeberg.org>
2020-06-23 20:59:23 +02:00
opyale
5a10127c1c Calculate ImageContrastColor more precise & some doc nits (#544)
Fixing color bug, updating license headers and CONTRIBUTORS

Co-authored-by: opyale <opyale@noreply.gitea.io>
Reviewed-by: 6543 <6543@noreply.codeberg.org>
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
2020-06-23 16:54:27 +02:00
opyale
7de29687eb Fixing collaborators bug and some improvements in RepoDetailActivity (#543)
* Minor improvements.

* Fixing collaborators bug and many (performance) improvements in RepoDetailActivity.

Co-authored-by: opyale <opyale@noreply.gitea.io>
Reviewed-by: 6543 <6543@noreply.codeberg.org>
2020-06-22 18:28:08 +02:00
6543
1a95475140 Gitea >= v1.12.0 only need read rights for Colaborators Tab (#542)
show "Add Collaborator" option only if you have the right to do so

gitea >= v1.12.0 only need read rights for Colaborators Tab

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

Co-authored-by: 6543 <6543@obermui.de>
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
2020-06-22 17:59:36 +02:00
M M Arif
d2265aecae Fix profile title (#541)
Fix profile
2020-06-22 09:57:21 +02:00
M M Arif
626746be8b Release 3.0.0 rc2 (#539)
release 3.0.0 rc2

Co-authored-by: M M Arif <mmarif@swatian.com>
2020-06-11 15:47:28 +02:00
6543
f21f23c1f0 Refactor FileDiffActivety (#537)
use androidx @NonNull instead of jetbrains @NotNull

Merge branch 'master' into refactor_FileDiffActivity

code format corrections

Merge branch 'master' into refactor_FileDiffActivity

add Unit TESTs for ParseDiff.getFileDiffViewArray

add get methods

make rm/add similar to gitea stats

calc diff stat based on diff itself

rename getFileContents -> toString

fix empty content bug & add comments

format AppUtil.java

rm unused

working version

skip binary files for now ... [DONT CRASH]

better regex

format FileDiffView.java

rename toolbar_title -> toolbarTitle

Co-authored-by: 6543 <6543@obermui.de>
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
2020-06-11 15:31:11 +02:00
opyale
5005fcc5b5 Redesign releases screen (#526)
Add download assets

implement release layout in adapter

update the layout

Fixing gravity.

Adding layouts for new release items.

Co-authored-by: M M Arif <mmarif@swatian.com>
Co-authored-by: opyale <opyale@noreply.gitea.io>
Reviewed-by: 6543 <6543@noreply.codeberg.org>
2020-06-11 01:45:11 +02:00
6543
008e446b93 GitNex drop 1.10 support and add 1.13 (#538)
GitNex drop 1.10 support and add 1.13

rm unused

Co-authored-by: 6543 <6543@obermui.de>
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
2020-06-10 17:22:49 +02:00
6543
50e0142f6c Pull Diff View: Use new API if gitea >= 1.13.0 (#536)
right arg order & right instanceUrl

use new API if gitea >= 1.13.0

correct name

format code

Co-authored-by: 6543 <6543@obermui.de>
Reviewed-by: opyale <opyale@noreply.codeberg.org>
2020-06-09 15:36:08 +02:00
opyale
42640f2d1c Updating gradle. (#535)
Updating gradle.

Co-authored-by: opyale <opyale@noreply.gitea.io>
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
2020-06-08 18:43:57 +02:00
opyale
4a8ee2ea96 Improving design of organisation detail page. (#534)
Design changes and updating dependencies.

Small fix.

Adding missing library.

Cleanup.

Improving design of organisation detail page.

Co-authored-by: opyale <opyale@noreply.gitea.io>
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
2020-06-08 08:34:53 +02:00
opyale
acc55e3433 Using blurred avatar as background. (#532)
Fixing NullPointerException when image isn't loaded yet.

Display country instead of raw language code.

Minor improvements and contrasting color.

First changes.

Co-authored-by: opyale <opyale@noreply.gitea.io>
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
2020-06-06 22:04:07 +02:00
M M Arif
e267aa5100 Show archived repo message (#530)
Implement archived repo in all adapters

Merge branch 'archive-repo2' into archive-repo

Fix typos

Fixing gravity.

Restoring old names.

Design changes.

Adjusting sizing.

Improving design of archived message.

Show archived repo message and other fixes

Co-authored-by: M M Arif <mmarif@swatian.com>
Co-authored-by: opyale <opyale@noreply.gitea.io>
Reviewed-by: opyale <opyale@noreply.codeberg.org>
2020-06-06 21:41:19 +02:00
6543
5e41469452 Move to CodeBerg (#528)
the rest

move to CodeBerg

Co-authored-by: 6543 <6543@obermui.de>
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
2020-06-04 17:37:51 +02:00
opyale
55473701b8 Improving design of "Show more information" (#527)
Adding comments to editorconfig.

Formatting.

Adding link color attribute.

Minor improvements.

Use dedicated layout for additional information.

Co-authored-by: opyale <opyale@noreply.gitea.io>
Reviewed-by: 6543 <6543@noreply.codeberg.org>
2020-06-04 16:21:23 +02:00
opyale
546346ff48 Improving milestones. (#525)
Removing unused strings.

Adding a little bit more space between title and progress bar.

Swapping icons.

Merge remote-tracking branch 'remotes/main/master' into improve-milestones

# Conflicts:
#	app/src/main/res/layout/list_milestones.xml

Minor improvements.

Merge branch 'improve-layouts' of https://gitea.com/opyale/GitNex into improve-milestones

Merge branch 'improve-layouts' of https://gitea.com/gitnex/GitNex into improve-milestones

Moving items.

Merge branch 'master' into improve-layouts

Merge branch 'master' into improve-layouts

Translation and additional formatting.

Enhancing editorconfig

Formatting and removing unused imports.

Removing milestone state.

Improving milestones.

branches and milestones layout update. Fix milestone infinite pagination loop for lower versions

layout updates for issues, pr. Fix pr nullable objects for lower versions

improve files layout

improve org info and list orgs

improve teams list layout by org

Fix repo layouts

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/525
Reviewed-by: M M Arif <mmarif@swatian.com>
2020-06-01 16:43:58 +00:00
M M Arif
4f0091f151 Improve layouts (#524)
make release checkboxes unchecked

admin users layout update

update commits and releases layout

profile fragments layout updates

improve labels

Merge branch 'master' into improve-layouts

branches and milestones layout update. Fix milestone infinite pagination loop for lower versions

layout updates for issues, pr. Fix pr nullable objects for lower versions

improve files layout

improve org info and list orgs

improve teams list layout by org

Fix repo layouts

Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/524
Reviewed-by: opyale <opyale@noreply.gitea.io>
2020-06-01 15:53:56 +00:00
M M Arif
37367e142f Fixes for rc1 (#523)
Fix commits query limit

Fix text colors for auto theme

Fix text color in grid views

fix file size for dir

Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/523
Reviewed-by: opyale <opyale@noreply.gitea.io>
2020-06-01 14:19:34 +00:00
M M Arif
8b1c79c0c3 Merge pull request 'Prepare release 3.0.0 rc1' (#520) from prepare-release into master
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/520
2020-05-31 13:39:25 +00:00
M M Arif
bf26a44376 Prepare release 3.0.0 rc1 2020-05-31 18:36:42 +05:00
M M Arif
6721b09de9 Improve single issue UI (#518)
Merge branch 'master' into single-issue-ui

Add progressbar, match the ui to other ui for views(lines etc). And other refactors.

Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/518
Reviewed-by: opyale <opyale@noreply.gitea.io>
2020-05-30 16:59:52 +00:00
opyale
0f9e130cf4 Using more recent docker image for eclint. (#516)
Using more recent docker image for eclint.

Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/516
Reviewed-by: 6543 <6543@noreply.gitea.io>
2020-05-29 21:31:55 +00:00
M M Arif
014b06cc46 Fix org repos layout bug, cleanup layouts and adapters (#514)
Merge branch 'extra-space' into fix-extra-space

# Conflicts:
#	app/src/main/res/layout/list_repositories.xml

fix margins and clean up

Adjusting margin to be consistent.

remove association

Fix org repos layout bug, cleanup layouts and adapters

Co-authored-by: opyale <opyale@noreply.gitea.io>
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/514
Reviewed-by: opyale <opyale@noreply.gitea.io>
2020-05-29 19:30:04 +00:00
opyale
6654b6fb48 [CI] Use enviroment variables again (#511)
[CI] Hopefully fixing upload now.

Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/511
Reviewed-by: 6543 <6543@noreply.gitea.io>
2020-05-28 10:19:14 +00:00
opyale
f1eb632d9b CI: Adding basic formatting tests (#509)
better names

Using dedicated eclint image

Reconfiguring editorconfig

Removing intellij-specific configuration and making adjustments.

Final improvements

Minor improvements.

end_of_line = lf

Adding basic formatting tests.

Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/509
Reviewed-by: 6543 <6543@noreply.gitea.io>
2020-05-27 18:09:55 +00:00
M M Arif
34f8f82b63 Fix infined load on Issues/Pulls if they dont exist (#507)
404 fix for issues

add 404 for pr

Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/507
Reviewed-by: 6543 <6543@noreply.gitea.io>
2020-05-23 18:30:33 +00:00
M M Arif
b30e2da387 Milestones filter(open/close) + refactor (#506)
remove strings

translation: generic but with contecxt

Merge branch 'milestones-filter' of gitea.com:gitnex/GitNex into milestones-filter

Clean up strings

Merge branch 'master' into milestones-filter

clean up and add missing parts

enhance and refactor milestone, added filter for closed and open ms

change to viewbinding

Co-authored-by: 6543 <6543@obermui.de>
Co-authored-by: 6543 <6543@noreply.gitea.io>
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/506
Reviewed-by: 6543 <6543@noreply.gitea.io>
2020-05-23 17:54:16 +00:00
opyale
6b3ac84113 Decreasing upload time to 3 minutes, increasing attempts and removing proxy. (#504)
CI: Decreasing upload time to 3 minutes, increasing attempts and removing proxy.

Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/504
Reviewed-by: 6543 <6543@noreply.gitea.io>
2020-05-23 08:38:09 +00:00
M M Arif
9541ef7dbc Merge pull request 'Enhance profile screen' (#505) from enhance-profile into master
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/505
Reviewed-by: opyale <opyale@noreply.gitea.io>
2020-05-22 15:46:48 +00:00
M M Arif
6a6bbef63d Enhance profile screen 2020-05-22 17:02:16 +05:00
6543
dc168a732b Update Crowdin 2020-05-21 (#503)
Update Crowdin 2020-05-21

Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/503
Reviewed-by: opyale <opyale@noreply.gitea.io>
2020-05-21 23:08:40 +00:00
M M Arif
d06f5353c6 Delete branch after merge (#496)
delete branch API call

Add fork repo info for branch

Check if pr is mergeable, show message if not.

Use checkbox instead of button

make ripple effects work for buttons with enable/disable

introduce viewbinding

Co-authored-by: 6543 <6543@noreply.gitea.io>
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/496
Reviewed-by: 6543 <6543@noreply.gitea.io>
2020-05-21 22:49:09 +00:00
M M Arif
1b213783bc New file saving (#502)
New file saving

Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/502
Reviewed-by: 6543 <6543@noreply.gitea.io>
2020-05-21 20:16:31 +00:00
6543
e83b9eb736 Check Issue Subscription and display button based on that (#445)
update string names

Update strings

Merge branch 'master' into imprufe-issue-subscription-checking

switch icon as per @mmarif

Migrate to new Version Check & disable IssueSubscription function for gitea < 1.12.0

Merge branch 'master' into imprufe-issue-subscription-checking

Merge branch 'master' into imprufe-issue-subscription-checking

Merge branch 'master' into imprufe-issue-subscription-checking

refactor  & use dismiss()

realy check If issue is subscribed

add 200 http Status check and handle it

Rename WatchRepository to WatchInfo & add checkIssueWatchStatus

Co-authored-by: M M Arif <mmarif@swatian.com>
Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/445
Reviewed-by: M M Arif <mmarif@swatian.com>
2020-05-21 18:58:00 +00:00
6543
ad7c3696d5 [BugFix] Version Compare (#500)
BugFix of Version

add new TestCase

Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/500
Reviewed-by: M M Arif <mmarif@swatian.com>
2020-05-21 14:13:14 +00:00
M M Arif
7bfdfa3223 Add/Remove new member to team (#483)
Search as user type, fix datalist.

Code Format

Fix users search theme

add and remove user from team

Add interface and user search and check for being team member or not

bottom sheet menu and few refactors

Co-authored-by: 6543 <6543@noreply.gitea.io>
Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/483
Reviewed-by: 6543 <6543@noreply.gitea.io>
2020-05-20 18:21:09 +00:00
opyale
0f38d81cd0 Minor improvements concerning CI. (#498)
Minor improvements concerning CI

Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/498
Reviewed-by: 6543 <6543@noreply.gitea.io>
2020-05-19 17:56:38 +00:00
6543
dd92ef9732 Merge pull request 'Adding additional functionality to build upload.' (#497) from opyale/GitNex:ci-upload-reloaded into master
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/497
Reviewed-by: 6543 <6543@noreply.gitea.io>
2020-05-18 23:20:47 +00:00
opyale
408fd9627b Adding additional functionality. 2020-05-19 01:09:56 +02:00
6543
3de4dd9463 Refactor Version Checks (#472)
Merge branch 'master' into refactor-versionCheck

Merge branch 'master' into refactor-versionCheck

Revert "test CI"

This reverts commit b56eff092020eedf20a4abaf7a0a9a3f3c5ffe9b.

test CI

Reformat LoginActivity.java

cleanup

migrate

Working + Tests

add first UnitTest

wip ...

enum2class

Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/472
Reviewed-by: M M Arif <mmarif@swatian.com>
2020-05-17 16:14:06 +00:00
M M Arif
7f0689524f Merge pull request 'Add corners to popup dialogs' (#495) from ui-enhancements into master
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/495
Reviewed-by: opyale <opyale@noreply.gitea.io>
2020-05-15 22:08:29 +00:00
M M Arif
a4afa5fbc2 Add corners to popup dialogs 2020-05-16 02:09:49 +05:00
M M Arif
29756511f3 Merge pull request 'Small layout adjustments and correcting typos.' (#493) from opyale/GitNex:settings-design-typo-adj into master
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/493
Reviewed-by: M M Arif <mmarif@swatian.com>
2020-05-14 15:09:48 +00:00
opyale
56d8cd0fac Small layout adjustments and correcting typos. 2020-05-14 12:46:49 +02:00
opyale
4e6057171b Adding deprecation dialog. (#492)
Additional improvements.

Final improvements.

Adding deprecation dialog.

Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/492
Reviewed-by: M M Arif <mmarif@swatian.com>
2020-05-09 19:07:55 +00:00
M M Arif
ab8a5ed505 Clear cache, configure cache size (#482)
decrease the compression to have better results

Move cache size outside of maxsize method. fix progress bar alignment for files

Add cache size to picasso

Use getAbsolutePath

Merge branch 'app-cache' of gitea.com:gitnex/GitNex into app-cache

Few imprvoements

Merge branch 'master' into app-cache

small improvement

Implement configure cache size and clear it

Co-authored-by: 6543 <6543@noreply.gitea.io>
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/482
Reviewed-by: opyale <opyale@noreply.gitea.io>
2020-05-09 14:50:45 +00:00
M M Arif
a6b424f5ff Fix files layout bug (#485)
Fix files layout bug

Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/485
Reviewed-by: 6543 <6543@noreply.gitea.io>
2020-05-04 17:16:36 +00:00
M M Arif
e5d6fd3b41 [New] Delete own comment (#478)
Code Reformat

Use return from 6543 commit

Fix typo

Move delete method to adapter to update the recyclerview

make it work

add to bottomsheet entry

Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/478
Reviewed-by: 6543 <6543@noreply.gitea.io>
2020-04-30 10:42:22 +00:00
opyale
5d1efe0f3f Moving HighlightJS into app. (#477)
Final fixes and improvements.

Fixing crash of app in Android 5.0

Removing unused theme.

Moving HighlightJS to app.

Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/477
Reviewed-by: M M Arif <mmarif@swatian.com>
2020-04-30 06:28:27 +00:00
6543
c41ab845fd Refactor Context (#469)
Merge branch 'master' into fix-refactor-context

reorder + space

fix

R E F A C T O R

set ctx and appCtx in LoginActivity

Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/469
Reviewed-by: M M Arif <mmarif@swatian.com>
Reviewed-by: opyale <opyale@noreply.gitea.io>
2020-04-28 13:47:25 +00:00
opyale
e45dc4b311 Increasing usability and design of files diff. (#413)
Applying sizes.

Additional changes.

First changes.

Merge branch 'master' into diff-cleaner

Fixing formatting.

Merge branch 'master' into diff-cleaner

Final changes for working with custom themes.

Merge remote-tracking branch 'remotes/main/master' into diff-cleaner

First changes for working with custom themes.

Merge branch 'master' into diff-cleaner

Merge branch 'master' into diff-cleaner

Merge branch 'master' into diff-cleaner

Merge branch 'master' into diff-cleaner

Merge branch 'master' into diff-cleaner

Adding custom COLOR_FONT.

Even smaller cleanups.

Merge remote-tracking branch 'remotes/main/master' into diff-cleaner

Small cleanups.

Fixing bug and adding maximum line limit.

Adding option to set cursor to end and small cleanup.

First aid.

Merge branch 'master' into diff-cleaner

Merge branch 'master' into diff-cleaner

Merge branch 'master' into diff-cleaner

Few improvements.

Performance improvements and cleanups.

Minor improvements (code in order) and many bug fixes

Bug fix.

Combining cited code.

Adding code commenting option.

Renaming list_files_diffs_new to list_files_diffs

Moving ProcessBar into center

Increasing performance.

Applying size to all icons globally.

Removing another unused file.

Merge remote-tracking branch 'remotes/main/master' into diff-cleaner

Removing unused files.

Changing size of 'close'-button.

Major changes concerning design and bug fixes.

Temporary save point.

2

1

Co-authored-by: opyale <example@example.com>
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/413
Reviewed-by: 6543 <6543@noreply.gitea.io>
Reviewed-by: M M Arif <mmarif@swatian.com>
2020-04-28 12:39:41 +00:00
M M Arif
7c53de363d Fix the context bug (#470)
Fix the context bug. done in activities

Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/470
Reviewed-by: 6543 <6543@noreply.gitea.io>
2020-04-28 10:36:07 +00:00
M M Arif
f352f175dd Merge pull request 'Add phone os version and model' (#468) from add-phone-os-section into master
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/468
2020-04-28 06:34:43 +00:00
M M Arif
d1a5c9c897 Add phone os version and model 2020-04-28 06:33:39 +00:00
M M Arif
51a7bca889 Merge pull request 'Small refactor and cleanup' (#467) from refactor-cleanup into master
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/467
2020-04-28 06:20:35 +00:00
M M Arif
03528f653a small refactor and cleanup 2020-04-28 11:18:58 +05:00
M M Arif
9d182821d2 Hide new branch when current is selected (#451)
Hide is best approach here

Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/451
Reviewed-by: opyale <opyale@noreply.gitea.io>
Reviewed-by: 6543 <6543@noreply.gitea.io>
2020-04-28 02:08:12 +00:00
M M Arif
195bfc8fe2 Refactor commits (#452)
code reformat

check for same gitea version

change link to button `view in browser`

add search by commit hash

Fix crash for custom attr caused by context and clean up

Refactor commits, remove fastadapter

Co-authored-by: 6543 <6543@noreply.gitea.io>
Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/452
Reviewed-by: 6543 <6543@noreply.gitea.io>
2020-04-26 22:59:09 +00:00
M M Arif
2e89fb0054 Fix load more after using filter (#463)
Fix load more after using filter

Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/463
Reviewed-by: opyale <opyale@noreply.gitea.io>
2020-04-26 21:21:15 +00:00
M M Arif
48abe71645 Split settings screen into different sections (#457)
add reports section

Add translation, fix change lang bug not taking affect

Add security section

Add file viewer section

Change settings screen into different sections

Co-authored-by: 6543 <6543@noreply.gitea.io>
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/457
Reviewed-by: 6543 <6543@noreply.gitea.io>
2020-04-26 13:36:33 +00:00
M M Arif
eca46b7913 Notification icons (#458)
New notification icon with transparent background

Co-authored-by: 6543 <6543@noreply.gitea.io>
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/458
Reviewed-by: opyale <opyale@noreply.gitea.io>
Reviewed-by: 6543 <6543@noreply.gitea.io>
2020-04-26 11:13:56 +00:00
M M Arif
6736fa2f5d Fix repo url (#455)
Fix repo url

Co-authored-by: 6543 <6543@noreply.gitea.io>
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/455
Reviewed-by: opyale <opyale@noreply.gitea.io>
Reviewed-by: 6543 <6543@noreply.gitea.io>
2020-04-26 11:02:03 +00:00
M M Arif
bbf41988d5 Merge pull request 'Enhance statusbar color for light theme' (#453) from enhance-statusbar-color-in-light-theme into master
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/453
Reviewed-by: opyale <opyale@noreply.gitea.io>
2020-04-26 09:54:30 +00:00
M M Arif
aa3288e889 Enhance statusbar color for light theme 2020-04-25 20:41:17 +05:00
M M Arif
92a0d06b75 Merge pull request 'Fix newlines in Readme' (#447) from fix-readme-newlines into master
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/447
Reviewed-by: M M Arif <mmarif@swatian.com>
2020-04-24 04:59:21 +00:00
6543
4e7fd6295e Fix newlines in Readme
because of new Render rouls - linebreaks have to be fixed
2020-04-24 00:28:44 +00:00
M M Arif
0ee5b43996 Optimize fragments, add filters, fix search and clean up (#439)
Code Reformat

hide not found message

Refactor issues, remove fastadapter.

fix swipe back filter icon issue, fix crash on issues with faster swiping

Change filter icon based on selection, empty the list for progress bar, check for gitea version to pass limit and other improvements

Separate menu and interface for pr

Add filter bottom sheet to PRs, issues

Fix search/filter pull requests

Co-authored-by: 6543 <6543@obermui.de>
Co-authored-by: 6543 <6543@noreply.gitea.io>
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/439
Reviewed-by: opyale <opyale@noreply.gitea.io>
2020-04-23 20:40:13 +00:00
M M Arif
625e60f2e2 Merge pull request 'Create new screen for administration' (#442) from 438-admin-nav into master
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/442
Reviewed-by: 6543 <6543@noreply.gitea.io>
2020-04-23 16:11:06 +00:00
6543
3fb063b0b1
Display Admin Menue Only If you are Admin 2020-04-23 18:04:32 +02:00
M M Arif
d7ef368f0b Create new screen for administration 2020-04-23 17:05:50 +05:00
M M Arif
dd1fce892a Replace textview with button for view commits in branches (#437)
Replace textview with button for view commits in branches

Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/437
Reviewed-by: 6543 <6543@noreply.gitea.io>
2020-04-22 10:12:56 +00:00
M M Arif
f39357f596 update master (#436)
update changelog

update master

Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/436
2020-04-22 05:05:35 +00:00
M M Arif
3bfc6b94a4 Merge pull request 'Crowdin [2020-04-21]' (#431) from 6543/GitNex:update-crowdin into master
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/431
Reviewed-by: M M Arif <mmarif@swatian.com>
2020-04-21 13:52:51 +00:00
6543
996d5d5fea
Update from Crowdin 2020-04-21 10:40:54 +02:00
M M Arif
af6cbfdb66 [FrontPort #429] Dismiss bottom sheet on subscribe/unsubscribe to issue & Fix (#428)
Merge branch 'master' into 427-dismiss-bottom-sheet

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.

Co-authored-by: 6543 <6543@noreply.gitea.io>
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/428
Reviewed-by: 6543 <6543@noreply.gitea.io>
2020-04-18 14:29:42 +00:00
6543
01e451556e README: Add download for CI build apk (#424)
Merge branch 'master' into update-readme-add-ci-build

apply suggestions

Change "Download APK" option to gitnex.com download page

add download for CI build apk

Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/424
Reviewed-by: M M Arif <mmarif@swatian.com>
2020-04-18 13:58:38 +00:00
M M Arif
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
M M Arif
57ecf3b7d2 Rc release 2020-04-18 10:19:43 +05:00
opyale
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
6543
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
M M Arif
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
M M Arif
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
M M Arif
b7abe65508 Fix crash caused by res shrinking and minification 2020-04-17 15:10:32 +05:00
6543
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
6543
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
opyale
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
M M Arif
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
M M Arif
e7554819fd Prepare 2.5.0 rc release 2020-04-15 02:27:58 +05:00
M M Arif
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
6543
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
M M Arif
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
opyale
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
M M Arif
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
opyale
4cb0253b38 Adjusting size of text views in organizations list. 2020-04-13 17:31:39 +02:00
M M Arif
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
M M Arif
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
6543
9a5a774d8c Merge branch 'master' into 400-milestone-bug 2020-04-13 10:20:18 +00:00
6543
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
M M Arif
3b84ec46d1 Fix of views being gone randomly 2020-04-13 12:48:23 +05:00
opyale
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
M M Arif
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
M M Arif
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
M M Arif
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
opyale
a7213add30 Adding more reliable calculation of label width. 2020-04-12 20:33:41 +02:00
opyale
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
6543
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
M M Arif
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
M M Arif
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
6543
1acbd7dc9f Merge branch 'master' into 329-close-open-milestone 2020-04-11 06:44:30 +00:00
M M Arif
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
M M Arif
0caaa63b06 Close/reopen milestone 2020-04-08 23:31:27 +05:00
M M Arif
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
M M Arif
8b7c5e2873 Minor improvement and fix for repo info tab 2020-04-08 02:21:47 +05:00
opyale
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
opyale
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
6543
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
opyale
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
M M Arif
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
M M Arif
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
6543
ce51b9264a
fix
Signed-off-by: 6543 <6543@obermui.de>
2020-04-07 15:18:14 +02:00
M M Arif
831e9d36ec Fix repos loading on switching accounts 2020-04-07 11:05:42 +05:00
6543
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
opyale
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
6543
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
6543
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
6543
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
6543
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
M M Arif
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
M M Arif
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
6543
fe0654b9eb
On Repo Lists: change comment-icon to issue-icon 2020-04-04 03:40:08 +02:00
anonTree1417
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
M M Arif
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
M M Arif
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
M M Arif
b9ca041c5b update libs and clean up 2020-04-03 11:28:24 +05:00
M M Arif
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
anonTree1417
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
M M Arif
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
6543
120c83a943 Merge branch 'master' into fix-341 2020-04-02 18:11:23 +00:00
anonTree1417
59e8f6f94a Fixing popup bug. 2020-04-02 19:11:23 +02:00
M M Arif
fc532989e5 Fix repos load on initial login and clean ups 2020-04-02 22:04:54 +05:00
anonTree1417
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
6543
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
M M Arif
70581cd330 Updates to settings screen 2020-04-02 20:49:26 +05:00
6543
20ce31fed8
add eng mesage 2020-04-02 17:17:53 +02:00
6543
f53f122a15
add saveUserName step on login 2020-04-02 17:17:00 +02:00
anonTree1417
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
M M Arif
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
M M Arif
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
anonTree1417
b9eee16294 Adding resources. 2020-04-02 03:12:44 +02:00
anonTree1417
abdfe8d9d1 Adding option to delete certificates. 2020-04-02 02:59:00 +02:00
6543
f4c4b837de
remove pointless if statements 2020-04-02 01:16:07 +02:00
anonTree1417
ee0392e208 Very small improvements 2020-04-01 21:58:42 +02:00
anonTree1417
b2f34f819c Removing library and commenting out logger. 2020-04-01 18:58:52 +02:00
anonTree1417
faaa4db88b Removing option "ONCE" 2020-04-01 18:39:39 +02:00
M M Arif
4217db3e31 Add author to readme 2020-04-01 21:16:59 +05:00
M M Arif
d2f77cfcd0 Fix minor formattings, other improvements 2020-04-01 20:28:14 +05:00
anonTree1417
9f6d8239f6 Adding author 2020-04-01 14:38:34 +02:00
anonTree1417
0dda996444 Adding Picasso support for self-signed certificates. 2020-04-01 13:26:32 +02:00
anonTree1417
c02d7f2df7 Merge branch 'master' of https://gitea.com/gitnex/GitNex into self-signed 2020-04-01 12:00:25 +02:00
M M Arif
9988649714 cleanup 2020-04-01 14:51:37 +05:00
M M Arif
1e52649b76 Added to labels, issue comment 2020-04-01 14:44:38 +05:00
M M Arif
ca37ad661d Changed repos list menus to bottom sheets 2020-04-01 11:38:14 +05:00
M M Arif
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
6543
786ac3999a Merge branch 'master' into improve-images-loading 2020-03-31 20:40:08 +00:00
anonTree1417
e5a656ce57 Many improvements and bug fixes. 2020-03-31 22:09:42 +02:00
anonTree1417
5fdbc98d6e Text to resource. 2020-03-31 21:21:49 +02:00
anonTree1417
b4996c0e6d Even more reformatting. 2020-03-31 21:14:49 +02:00
anonTree1417
28d97f2d67 Merge branch 'master' of https://gitea.com/gitnex/GitNex into self-signed 2020-03-31 21:10:47 +02:00
anonTree1417
a53a5d55bf Reformatting applied. 2020-03-31 21:04:53 +02:00
anonTree1417
2125d38a66 Adding information at error and resetting button. 2020-03-31 21:04:08 +02:00
anonTree1417
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
anonTree1417
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
M M Arif
0e365a6d49 Add placeholders for images 2020-03-31 23:46:42 +05:00
anonTree1417
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
anonTree1417
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
anonTree1417
d87bd3a8f7 Merge remote-tracking branch 'remotes/main/master' into add-styling 2020-03-31 20:09:06 +02:00
anonTree1417
22010d953a Adjusting sizes in LabelsAdapter 2020-03-31 18:43:52 +02:00
anonTree1417
f12219ace7 Restoring branches_list.xml 2020-03-31 16:52:39 +02:00
anonTree1417
d2190ad189 Moving classes to helpers/ 2020-03-31 16:44:11 +02:00
anonTree1417
e1ccb4e404 Fixed formatting. 2020-03-31 16:41:50 +02:00
M M Arif
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
M M Arif
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
anonTree1417
60781ac4c3 Small design changes. 2020-03-31 05:14:24 +02:00
anonTree1417
6b2be06eda Adjusting proportions of issue labels. 2020-03-31 04:04:11 +02:00
6543
c2505d66b5 Merge branch 'master' into 13-repo-commits 2020-03-30 23:12:07 +00:00
6543
9f30299cfa
add Discord badge 2020-03-31 00:12:50 +02:00
anonTree1417
2b6d22ed94 Modifying license headers. 2020-03-30 23:25:49 +02:00
anonTree1417
aa697d11ad Adding, customizing and modifying MemorizingTrustManager. 2020-03-30 23:01:54 +02:00
6543
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
M M Arif
0820dc3480 Merge branch 'master' into 13-repo-commits
# Conflicts:
#	app/src/main/res/values/strings.xml
2020-03-29 19:27:56 +05:00
M M Arif
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
M M Arif
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
M M Arif
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
6543
25c6a9558f simplify code 2020-03-29 16:04:04 +02:00
6543
667d98329c Merge branch 'master' into 262-changelog-popup 2020-03-29 13:45:39 +00:00
M M Arif
3955b64efb Add to readme 2020-03-29 16:18:16 +05:00
M M Arif
6e7e3ef690 Code style as whichever is availability in idea 2020-03-29 11:09:51 +05:00
M M Arif
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
M M Arif
2bda0dbe7e fix http protocol for open repo url 2020-03-28 21:08:11 +05:00
M M Arif
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
M M Arif
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
M M Arif
21aae88e62 Refactor naming convention for better findings 2020-03-28 15:52:09 +05:00
M M Arif
ea9025296a final implementation and ui completion of commits list 2020-03-27 23:59:24 +05:00
M M Arif
e963d3483b Merge branch 'master' into 262-changelog-popup 2020-03-25 19:48:49 +05:00
M M Arif
c8164c56d0 Initial work on commits list using paging library 2020-03-25 19:43:40 +05:00
M M Arif
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
M M Arif
fec0945be9 Fix encoding on login 2020-03-24 13:33:35 +05:00
M M Arif
c3c0749a7a show when update/install app 2020-03-21 23:52:52 +05:00
M M Arif
a9b8e15812 use StandardCharsets instead 2020-03-19 18:54:20 +05:00
M M Arif
c57d39e3f4 Merge branch 'master' into 262-changelog-popup 2020-03-19 18:52:57 +05:00
M M Arif
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
Florian
0e7df87a60 hotfix for #297 2020-03-18 18:30:18 +01:00
M M Arif
e40eb5e6a1 changelog popup initial working draft 2020-03-17 20:56:37 +05:00
M M Arif
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
M M Arif
2b976f58ba Check if data really exists 2020-03-17 15:36:26 +05:00
M M Arif
7e8d2c6ec2 Create repository from organization menu, refactors too 2020-03-17 15:32:03 +05:00
M M Arif
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
M M Arif
614e053796 Show only issues 2020-03-17 12:19:59 +05:00
M M Arif
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
M M Arif
6cb06d918d Fix divider color in themes 2020-03-17 01:07:23 +05:00
M M Arif
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
M M Arif
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
M M Arif
79bd96f6a2 Share feature and some refactor to easily manage source code files 2020-03-17 00:28:03 +05:00
M M Arif
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
M M Arif
8921543ef5 Fix breadcrumb navigation 2020-03-16 19:30:41 +05:00
M M Arif
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
M M Arif
375c12b192 update libs, fix required bugs after update libs, bump app ver 2020-03-16 14:25:15 +05:00
M M Arif
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
6543
d16b1580dd crowdin update 2020-03-15 19:36:59 +01:00
762 changed files with 50920 additions and 26186 deletions

View File

@ -1,31 +1,104 @@
---
kind: pipeline
name: gitnex-ci-test
type: docker
name: tests
steps:
- name: test
- name: unit-tests
image: nextcloudci/android:android-49
depends_on: [ clone ]
commands:
- ./gradlew test
- name: check-formatting
image: zosiab/eclint:latest
depends_on: [ clone ]
commands:
- git pull origin main
- eclint check $(git diff --name-only origin/main)
# This may be used in the future, because it makes of intellij's native code inspection/formatting capabilities.
# Additional information: https://www.jetbrains.com/help/idea/command-line-formatter.html
#
# - name: do-or-check-formatting
# image: dlsniper/docker-intellij
# depends_on: [ clone ]
# commands:
# - /opt/intellij/bin/idea.sh inspect/format ...
#
# - name: do-or-check-formatting
# image: dlsniper/docker-intellij
# depends_on: [ clone ]
# commands:
# - /opt/intellij/bin/idea.sh format -s .idea/codeStyles/Project.xml -m *.java app/src/main/java
trigger:
event:
- pull_request
---
kind: pipeline
name: gitnex-ci-build
type: docker
name: code-analysis
steps:
- name: check-global-formatting
image: zosiab/eclint:latest
depends_on: [ clone ]
commands:
- eclint check $(git ls-files)
trigger:
event:
- push
branch:
- main
---
kind: pipeline
type: docker
name: build
steps:
- name: build
image: nextcloudci/android:android-49
commands:
- ./gradlew build
- ./gradlew assembleFreeRelease
- name: sign
image: nextcloudci/android:android-49
environment:
BOT_TOKEN:
from_secret: BOT_TOKEN
KS_PASS:
from_secret: KS_PASS
KEY_PASS:
from_secret: KEY_PASS
OUTPUT: signed.apk
INSTANCE: https://codeberg.org
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_TIMEOUT: 180
PLUGIN_ATTEMPTS: 5
PLUGIN_DESTINATION: 'https://cloud.swatian.com/remote.php/dav/files/GitNexBot/gitnex/builds/latest.apk'
PLUGIN_CUSTOM_ARGUMENTS: '--progress-bar'
trigger:
event:
- push
branch:
- master
- main

25
.editorconfig Normal file
View File

@ -0,0 +1,25 @@
[*]
charset = utf-8
end_of_line = lf
indent_size = 4
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
max_line_length = 150
[*.java]
indent_style = tab
line_comment = //
block_comment_start = /*
block_comment = *
block_comment_end = */
[*.json]
indent_size = 2
[{*.yml,*.yaml}]
indent_size = 2
[*.md]
trim_trailing_whitespace = false
insert_final_newline = false

View File

@ -0,0 +1,37 @@
---
name: "Bug"
about: "Something isn't working"
labels:
- Bug
---
## # Describe your matter briefly
<br><br>
##### What did you expect?
---
<br><br>
##### Some additional details
---
* The version of **Gitea** you are using:
* The version of **GitNex** you are using:
* Source of installation (Play Store, F-Droid, APK):
* Current android version and phone model/manufacturer:
* The type of certificate your instance is using (self-signed, signed):
* How you used to log in (via password or token):
<br>
##### We would appreciate some screenshots or stacktrace's, but this is also not required.
---
<!-- Screenshots and stacktrace's can go here. -->
<br><br>
- [ ] I carefully read the [contribution guidelines](https://codeberg.org/GitNex/GitNex/src/branch/main/CONTRIBUTING.md).
<br>
<!-- Thank you for your time. -->

View File

@ -0,0 +1,17 @@
---
name: "Feature"
about: "A new feature or an enhancement to an existing feature"
labels:
- Feature
---
## # Describe your matter briefly
<br><br>
- [ ] I carefully read the [contribution guidelines](https://codeberg.org/GitNex/GitNex/src/branch/main/CONTRIBUTING.md).
<br>
<!-- Thank you for your time. -->

View File

@ -0,0 +1,37 @@
---
name: "Suggestion"
about: "A general suggestion"
labels:
- Suggestion
---
## # Describe your matter briefly
<br><br>
##### What did you expect?
---
<br><br>
##### Some additional details
---
* The version of **Gitea** you are using:
* The version of **GitNex** you are using:
* Source of installation (Play Store, F-Droid, APK):
* Current android version and phone model/manufacturer:
* The type of certificate your instance is using (self-signed, signed):
* How you used to log in (via password or token):
<br>
##### We would appreciate some screenshots or stacktrace's, but this is also not required.
---
<!-- Screenshots and stacktrace's can go here. -->
<br><br>
- [ ] I carefully read the [contribution guidelines](https://codeberg.org/GitNex/GitNex/src/branch/main/CONTRIBUTING.md).
<br>
<!-- Thank you for your time. -->

View File

@ -0,0 +1,9 @@
### Describe what your pull request does and which issue youre targeting
<!-- Create a new issue, if it doesn't exist yet -->
<br><br>
<!-- Make sure you are targeting the "main" branch, pull requests on release branches are only allowed for bug fixes. -->
- [ ] I carefully read the [contribution guidelines](https://codeberg.org/GitNex/GitNex/src/branch/main/CONTRIBUTING.md).
- [ ] I'm following the code standards as defined [here](https://codeberg.org/gitnex/GitNex/wiki/Code-Standards).
- [ ] By submitting this pull request, I permit GitNex to license my work under the [GNU General Public License v3](https://codeberg.org/GitNex/GitNex/src/branch/main/LICENSE).

10
.gitignore vendored
View File

@ -8,6 +8,12 @@
*.ap_
*.aab
# Release dir
app/release/*
# Pro dir
app/pro/*
# Files for the ART/Dalvik VM
*.dex
@ -48,6 +54,7 @@ captures/
.idea/dictionaries
.idea/libraries
.idea/caches
!.idea/codeStyles
# Keystore files
# Uncomment the following lines if you do not want to check your keystore files in.
@ -188,3 +195,6 @@ crowdin.yml
!/gradle/wrapper/gradle-wrapper.jar
# End of https://www.gitignore.io/api/android,androidstudio
# Crowdin Config
crowdin.yml

100
.gitlab-ci.yml Normal file
View File

@ -0,0 +1,100 @@
stages:
- build
- sign
- publish
on_setup:
image: curlimages/curl:7.77.0
stage: .pre
only:
- main
- tags
variables:
INSTANCE: "https://codeberg.org"
MAIN_REPO: gitnex/GitNex
STATE: pending
script:
- ./scripts/add-commit-status.sh
build:
image: nextcloudci/android8:android-61
stage: build
only:
- main
- tags
script:
- ./gradlew assembleFreeRelease
artifacts:
paths:
- app/build/outputs/
expire_in: 15 minutes
sign:
image: nextcloudci/android8:android-61
stage: sign
only:
- main
- tags
variables:
OUTPUT: "signed.apk"
INSTANCE: "https://codeberg.org"
KS_FILE: "ci_keystore.jks"
script:
- ./scripts/sign-build.sh
artifacts:
paths:
- signed.apk
expire_in: 15 minutes
latest:
image: curlimages/curl:7.77.0
stage: publish
only:
- main
- tags
variables:
WEBDAV_USERNAME: "GitNexBot"
PLUGIN_FILE: "signed.apk"
PLUGIN_DESTINATION: "https://cloud.swatian.com/remote.php/dav/files/GitNexBot/gitnex/builds/latest.apk"
script:
- curl -T "$PLUGIN_FILE" -u "$WEBDAV_USERNAME":"$WEBDAV_PASSWORD" "$PLUGIN_DESTINATION"
release:
image: curlimages/curl:7.77.0
stage: publish
only:
- tags
variables:
WEBDAV_USERNAME: "GitNexBot"
PLUGIN_FILE: "signed.apk"
script:
- "[[ $CI_COMMIT_REF_NAME == *'-rc'* ]] && echo 'Upload blocked. Build seems to be a release candidate.' && exit 0"
- curl -T "$PLUGIN_FILE" -u "$WEBDAV_USERNAME":"$WEBDAV_PASSWORD" 'https://cloud.swatian.com/remote.php/dav/files/GitNexBot/gitnex/releases/'"$CI_COMMIT_REF_NAME"'.apk'
on_success:
image: curlimages/curl:7.77.0
stage: .post
only:
- main
- tags
variables:
INSTANCE: "https://codeberg.org"
MAIN_REPO: gitnex/GitNex
STATE: success
script:
- ./scripts/add-commit-status.sh
when: on_success
on_failure:
image: curlimages/curl:7.77.0
stage: .post
only:
- main
- tags
variables:
INSTANCE: "https://codeberg.org"
MAIN_REPO: gitnex/GitNex
STATE: failure
script:
- ./scripts/add-commit-status.sh
when: on_failure

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

@ -0,0 +1,183 @@
<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>
<JetCodeStyleSettings>
<option name="PACKAGES_TO_USE_STAR_IMPORTS">
<value>
<package name="java.util" alias="false" withSubpackages="false" />
<package name="kotlinx.android.synthetic" alias="false" withSubpackages="true" />
<package name="io.ktor" alias="false" withSubpackages="true" />
</value>
</option>
<option name="PACKAGES_IMPORT_LAYOUT">
<value>
<package name="" alias="false" withSubpackages="true" />
<package name="java" alias="false" withSubpackages="true" />
<package name="javax" alias="false" withSubpackages="true" />
<package name="kotlin" alias="false" withSubpackages="true" />
<package name="" alias="true" withSubpackages="true" />
</value>
</option>
</JetCodeStyleSettings>
<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="ALIGN_MULTILINE_PARAMETERS" value="false" />
<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="CALL_PARAMETERS_WRAP" value="1" />
<option name="METHOD_PARAMETERS_WRAP" value="1" />
<option name="THROWS_LIST_WRAP" value="1" />
<option name="METHOD_CALL_CHAIN_WRAP" value="1" />
<option name="TERNARY_OPERATION_WRAP" value="1" />
<option name="ARRAY_INITIALIZER_WRAP" value="1" />
<option name="IF_BRACE_FORCE" value="3" />
<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

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

View File

@ -2,21 +2,35 @@
Please take a few minutes to read this document to make the process of contribution more easy and healthy for all involved.
## Pull Requests
Patches, enhancements, features are always welcome. The PR should focus on the scope of work and avoid many unnecessary commits. Please provide as much detail and context as possible to explain the work submitted.
Please ask if you are not sure about the scope of work to be submitted to avoid waste of time spent on the work.
**How to submit a PR**
Fork this repository. Pull the forked repository from your namespace to your local machine. Create new branch and work on the bug/feature/enhancement you would like to submit. Push it to your forked version. From there create Pull Request(PR) against **master** branch.
**IMPORTANT:** By submitting PR, you agree to allow GitNex to license your work under the same license as that used by GitNex.
## Issues and Reports
*1st of please be polite and gentle while commenting or creating new issue to maintain a healthy environment.*
### General
> **Be polite and gentle while commenting or creating new issues to maintain a healthy environment in which __everyone__ is able to feel comfortable.**
<br>
### Issues and Reports
Before creating an issue please take a moment and search the repository issues(open/closed) to avoid duplicate issues either it's a bug or feature.
In case you want to submit a bug report, please provide as much details as possible to better debug the problem. The important part is how to reproduce the bug and steps to reproduce are appreciated.<br><br>
**Note:** Please contact the project directly via [email](mailto:gitnex@swatian.com) if have to share sensitive and security related details.
<br>
In case you want to submit a bug report, please provide as much details as possible to better debug the problem. The important part is how to reproduce the bug and steps to reproduce are appreciated.
### Pull Requests
Patches, enhancements and features are always welcome.
The PR should focus on the scope of work and avoid many unnecessary commits.
Please provide as much detail and context as possible to explain the work submitted.
**Note:** Please contact the project directly via email(gitnex@swatian.com) if have to share sensitive and security related details.
**Please ask if you are not sure about the scope of work to be submitted to avoid waste of time spent on the work.** (Submit an issue, __before__ submitting a PR)
**Code Standards**<br><br>
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://codeberg.org/gitnex/GitNex/wiki/Code-Standards)
**How to submit a PR (Pull Request)**
1. Fork this repository.
2. Clone the forked repository from your namespace to your local machine.
3. Create a new branch and work on your feature, enhancement or patch.
4. Push your commits to your forked version.
5. You can now create a PR using the web interface against **main** branch.
For more information, click [here](http://makeapullrequest.com/).
**IMPORTANT:** By submitting PR, you agree to allow GitNex to license your work under the same license as that used by GitNex.

View File

@ -3,6 +3,7 @@ This part lists all PUBLIC individuals having contributed content to the code.
* M M Arif (mmarif)
* 6543
* opyale
* Unpublished
# Translators

63
LICENSE
View File

@ -1,7 +1,7 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
@ -620,55 +620,18 @@ copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
GitNex is an Android client/application for Gitea.
Copyright (C) 2019 The GitNex Authors
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
Mastalab is a Mastodon client for Android devices
Copyright (C) 2017 Thomas Schneider
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
Mastalab Copyright (C) 2017 Thomas Schneider
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.

101
README.md
View File

@ -1,94 +1,97 @@
[![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
[![Release](https://img.shields.io/badge/dynamic/json.svg?label=release&url=https://gitea.com/api/v1/repos/gitnex/GitNex/releases&query=$[0].tag_name)](https://gitea.com/gitnex/GitNex/releases)
[![Build Status](https://drone.gitea.com/api/badges/gitnex/GitNex/status.svg)](https://drone.gitea.com/gitnex/GitNex)
[![Crowdin](https://badges.crowdin.net/gitnex/localized.svg)](https://crowdin.com/project/gitnex)
[![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0) [![Pipeline status](https://img.shields.io/gitlab/pipeline/mmarif4u/gitnex-ci/main)](https://gitlab.com/mmarif4u/gitnex-ci/-/pipelines) [![Release](https://img.shields.io/badge/dynamic/json.svg?label=release&url=https://codeberg.org/api/v1/repos/gitnex/GitNex/releases&query=$[0].tag_name)](https://codeberg.org/gitnex/GitNex/releases) [![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="Donate using Liberapay" src="https://liberapay.com/assets/widgets/donate.svg" height="40"/>](https://liberapay.com/mmarif/donate)
[<img alt="Become a Patreon" src="https://c5.patreon.com/external/logo/become_a_patron_button@2x.png" height="40"/>](https://www.patreon.com/mmarif)
# GitNex - Android client for Gitea
GitNex is a free, open-source Android client for Git repository management tool Gitea. Gitea is a community managed fork of Gogs, lightweight code hosting solution written in Go.
GitNex is a free/paid, open-source Android client for Git repository management tool Gitea. Gitea is a community managed fork of Gogs, lightweight code hosting solution written in Go.
GitNex is licensed under GPLv3 License. See the LICENSE file for the full license text.
No trackers are used and source code is available here for anyone to audit.
GitNex is licensed under GPLv3 License. See the LICENSE file for the full license text. **No trackers are used** and source code is available here for anyone to audit.
## Downloads
[<img alt='Get it on F-droid' src='https://gitlab.com/fdroid/artwork/raw/master/badge/get-it-on.png' height="80"/>](https://f-droid.org/en/packages/org.mian.gitnex/)
[<img alt='Get it on Google Play' src='https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png' height="80"/>](https://play.google.com/store/apps/details?id=org.mian.gitnex)
[<img alt='Download APK' src='https://gitnex.com/img/download-apk.png' height="80"/>](https://gitea.com/gitnex/GitNex/releases)
[<img alt='Get it on F-Droid' src='https://gitlab.com/fdroid/artwork/raw/master/badge/get-it-on.png' height="80"/>](https://f-droid.org/en/packages/org.mian.gitnex/)
[<img alt='Get it on Google Play' src='https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png' height="80"/>](https://play.google.com/store/apps/details?id=org.mian.gitnex.pro)
[<img alt='Download builds and releases' src='https://codeberg.org/gitnex/GitNex/raw/branch/main/assets/apk-badge.png' height="82"/>](https://cloud.swatian.com/s/DN7E5xxtaw4fRbE)
## Note about Gitea version
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://codeberg.org/gitnex/GitNex/wiki/Compatibility) which lists all the supported versions with compatibility ratio.
## Build from source
Option 1 - Download the source code, open it in Android Studio and build it there.
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 assembleFree`.
## Features
- Multiple accounts support
- File and directory browser
- File viewer
- Create files
- Explore repositories
- Issues list
- Pull requests
- Merge pull request
- [MANY MORE](https://gitea.com/gitnex/GitNex/wiki/Features)
- Files diff for PRs
- Notifications
- Drafts
- Repositories / issues / org list
- [MANY MORE](https://codeberg.org/gitnex/GitNex/wiki/Features)
## Contributing
[CONTRIBUTING](https://gitea.com/gitnex/GitNex/src/branch/master/CONTRIBUTING.md)
[CONTRIBUTING](https://codeberg.org/gitnex/GitNex/src/branch/main/CONTRIBUTING.md)
## Translation
Help us translate GitNex to your native language.
We use [Crowdin](https://crowdin.com/project/gitnex) for translation.
If your language is not listed, please request [here](https://gitea.com/gitnex/GitNex/issues) to add it to the project.
We use [Crowdin](https://crowdin.com/project/gitnex) for translation. If your language is not listed, please request [here](https://codeberg.org/gitnex/GitNex/issues) to add it to the project.
**Link: https://crowdin.com/project/GitNex**
## Screenshots:
<img src="https://gitea.com/gitnex/GitNex/raw/branch/master/fastlane/metadata/android/en-US/images/phoneScreenshots/001.png" alt="001.png" width="200"/> | <img src="https://gitea.com/gitnex/GitNex/raw/branch/master/fastlane/metadata/android/en-US/images/phoneScreenshots/002.png" alt="002.png" width="200"/> | <img src="https://gitea.com/gitnex/GitNex/raw/branch/master/fastlane/metadata/android/en-US/images/phoneScreenshots/003.png" alt="003.png" width="200"/> | <img src="https://gitea.com/gitnex/GitNex/raw/branch/master/fastlane/metadata/android/en-US/images/phoneScreenshots/004.png" alt="004.png" width="200"/>
<img src="https://codeberg.org/gitnex/GitNex/raw/branch/main/fastlane/metadata/android/en-US/images/phoneScreenshots/001.png" alt="001.png" width="200"/> | <img src="https://codeberg.org/gitnex/GitNex/raw/branch/main/fastlane/metadata/android/en-US/images/phoneScreenshots/002.png" alt="002.png" width="200"/> | <img src="https://codeberg.org/gitnex/GitNex/raw/branch/main/fastlane/metadata/android/en-US/images/phoneScreenshots/003.png" alt="003.png" width="200"/> | <img src="https://codeberg.org/gitnex/GitNex/raw/branch/main/fastlane/metadata/android/en-US/images/phoneScreenshots/004.png" alt="004.png" width="200"/>
---|---|---|---
<img src="https://gitea.com/gitnex/GitNex/raw/branch/master/fastlane/metadata/android/en-US/images/phoneScreenshots/005.png" alt="005.png" width="200"/> | <img src="https://gitea.com/gitnex/GitNex/raw/branch/master/fastlane/metadata/android/en-US/images/phoneScreenshots/006.png" alt="006.png" width="200"/> | <img src="https://gitea.com/gitnex/GitNex/raw/branch/master/fastlane/metadata/android/en-US/images/phoneScreenshots/007.png" alt="007.png" width="200"/> | <img src="https://gitea.com/gitnex/GitNex/raw/branch/master/fastlane/metadata/android/en-US/images/phoneScreenshots/008.png" alt="008.png" width="200"/>
## FAQ
[Faq](https://gitea.com/gitnex/GitNex/wiki/FAQ)
<img src="https://codeberg.org/gitnex/GitNex/raw/branch/main/fastlane/metadata/android/en-US/images/phoneScreenshots/005.png" alt="005.png" width="200"/> | <img src="https://codeberg.org/gitnex/GitNex/raw/branch/main/fastlane/metadata/android/en-US/images/phoneScreenshots/006.png" alt="006.png" width="200"/> | <img src="https://codeberg.org/gitnex/GitNex/raw/branch/main/fastlane/metadata/android/en-US/images/phoneScreenshots/007.png" alt="007.png" width="200"/> | <img src="https://codeberg.org/gitnex/GitNex/raw/branch/main/fastlane/metadata/android/en-US/images/phoneScreenshots/008.png" alt="008.png" width="200"/>
## Links
[Website](https://gitnex.com)
[Wiki](https://gitea.com/gitnex/GitNex/wiki/Home)
[Wiki](https://codeberg.org/gitnex/GitNex/wiki/Home)
[Website Repository](https://gitlab.com/mmarif4u/gitnex-website)
[Troubleshoot Guide](https://codeberg.org/gitnex/GitNex/wiki/Troubleshoot-Guide)
[Troubleshoot Guide](https://gitea.com/gitnex/GitNex/wiki/Troubleshoot-Guide)
[Faq](https://codeberg.org/gitnex/GitNex/wiki/FAQ)
[Release Blog](https://gitnex.codeberg.page)
## Thanks
Thanks to all the open source libraries, contributors and donators.
Open source libraries
- Retrofit
- Gson
- Okhttp
- ViHtarb/tooltip
- Picasso
- Markwon
- Prettytime
- Amulyakhare/textdrawable
- Vdurmont/emoji-java
- Abumoallim/android-multi-select-dialog
- Pes/materialcolorpicker
- Hendraanggrian/socialview
- HamidrezaAmz/BreadcrumbsView
- Chrisbanes/PhotoView
- Pddstudio/highlightjs-android
- Apache/commons-io
- Caverock/androidsvg
- Droidsonroids.gif/android-gif-drawable
- Barteksc/AndroidPdfViewer
#### Open source libraries
- [square/retrofit](https://github.com/square/retrofit)
- [google/gson](https://github.com/google/gson)
- [square/okhttp](https://github.com/square/okhttp)
- [square/picasso](https://github.com/square/picasso)
- [wasabeef/picasso-transformations](https://github.com/wasabeef/picasso-transformations)
- [cats-oss/android-gpuimage](https://github.com/cats-oss/android-gpuimage)
- [noties/Markwon](https://github.com/noties/Markwon)
- [noties/Prism4j](https://github.com/noties/Prism4j)
- [ocpsoft/prettytime](https://github.com/ocpsoft/prettytime)
- [amulyakhare/TextDrawable](https://github.com/amulyakhare/TextDrawable)
- [vdurmont/emoji-java](https://github.com/vdurmont/emoji-java)
- [Pes8/android-material-color-picker-dialog](https://github.com/Pes8/android-material-color-picker-dialog)
- [HamidrezaAmz/BreadcrumbsView](https://github.com/HamidrezaAmz/BreadcrumbsView)
- [Baseflow/PhotoView](https://github.com/Baseflow/PhotoView)
- [apache/commons](https://github.com/apache/commons-io)
- [ge0rg/MemorizingTrustManager](https://github.com/ge0rg/MemorizingTrustManager)
- [mikaelhg/urlbuilder](https://github.com/mikaelhg/urlbuilder)
- [ACRA/acra](https://github.com/ACRA/acra)
- [chrisvest/stormpot](https://github.com/chrisvest/stormpot)
#### Icon sets
- [feathericons/feather](https://github.com/feathericons/feather)
- [primer/octicons](https://github.com/primer/octicons)
- [google/material-design-icons](https://github.com/google/material-design-icons)
[Follow me on Fediverse - mastodon.social/@mmarif](https://mastodon.social/@mmarif)
*All trademarks and logos are the properties of their respective owners.*

View File

@ -1,50 +1,85 @@
apply plugin: 'com.android.application'
android {
compileSdkVersion 29
compileSdkVersion 30
defaultConfig {
applicationId "org.mian.gitnex"
minSdkVersion 21
targetSdkVersion 29
versionCode 90
versionName "2.4.0"
targetSdkVersion 30
versionCode 415
versionName "4.2.0"
multiDexEnabled true
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
dexOptions {
javaMaxHeapSize "4g"
}
flavorDimensions "default"
productFlavors {
free {
applicationId "org.mian.gitnex"
}
pro {
applicationId "org.mian.gitnex.pro"
}
}
buildFeatures {
viewBinding true
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
shrinkResources false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
lintOptions {
//checkReleaseBuilds false
abortOnError false
}
compileOptions {
coreLibraryDesugaringEnabled true
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
defaultConfig{
vectorDrawables.useSupportLibrary = true
}
}
configurations {
cleanedAnnotations
compile.exclude group: 'org.jetbrains', module: 'annotations'
}
dependencies {
def lifecycle_version = "2.2.0"
final def markwon_version = "4.1.1"
def lifecycle_version = '2.3.1'
def markwon_version = '4.6.2'
def work_version = "2.7.0-alpha05"
def acra = "5.7.0"
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation "androidx.appcompat:appcompat:1.1.0"
implementation "com.google.android.material:material:1.2.0-alpha05"
implementation "androidx.constraintlayout:constraintlayout:1.1.3"
implementation 'androidx.appcompat:appcompat:1.4.0-alpha03'
implementation 'com.google.android.material:material:1.4.0'
implementation 'androidx.viewpager2:viewpager2:1.1.0-beta01'
implementation 'androidx.constraintlayout:constraintlayout:2.1.1'
implementation "androidx.legacy:legacy-support-v4:1.0.0"
testImplementation "junit:junit:4.12"
androidTestImplementation "androidx.test:runner:1.2.0"
androidTestImplementation "androidx.test.espresso:espresso-core:3.2.0"
implementation "com.github.vihtarb:tooltip:0.2.0"
implementation "com.squareup.okhttp3:okhttp:3.12.1"
implementation "com.google.code.gson:gson:2.8.5"
implementation "androidx.lifecycle:lifecycle-viewmodel:$lifecycle_version"
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test:runner:1.4.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
implementation 'com.squareup.okhttp3:okhttp:5.0.0-alpha.2'
implementation "com.google.code.gson:gson:2.8.6"
implementation "com.squareup.picasso:picasso:2.71828"
implementation 'jp.wasabeef:picasso-transformations:2.4.0'
implementation 'jp.co.cyberagent.android:gpuimage:2.1.0'
implementation "com.amulyakhare:com.amulyakhare.textdrawable:1.0.1"
implementation "com.squareup.retrofit2:retrofit:2.5.0"
implementation "com.squareup.retrofit2:converter-gson:2.5.0"
implementation "com.squareup.retrofit2:converter-scalars:2.5.0"
implementation "com.squareup.okhttp3:logging-interceptor:3.12.1"
implementation "org.ocpsoft.prettytime:prettytime:4.0.1.Final"
implementation "com.vdurmont:emoji-java:4.0.0"
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation 'com.squareup.retrofit2:converter-scalars:2.9.0'
implementation 'com.squareup.okhttp3:logging-interceptor:5.0.0-alpha.2'
implementation 'org.ocpsoft.prettytime:prettytime:5.0.0.Final'
implementation "com.pes.materialcolorpicker:library:1.2.5"
implementation "io.noties.markwon:core:$markwon_version"
implementation "io.noties.markwon:ext-latex:$markwon_version"
@ -59,15 +94,24 @@ dependencies {
implementation "io.noties.markwon:recycler-table:$markwon_version"
implementation "io.noties.markwon:simple-ext:$markwon_version"
implementation "io.noties.markwon:syntax-highlight:$markwon_version"
implementation "com.caverock:androidsvg:1.4"
implementation "pl.droidsonroids.gif:android-gif-drawable:1.2.19"
implementation "com.hendraanggrian.appcompat:socialview:0.2"
implementation "com.hendraanggrian.appcompat:socialview-commons:0.2"
implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-viewmodel:$lifecycle_version"
implementation "io.noties.markwon:image-picasso:$markwon_version"
implementation "io.noties:prism4j:2.0.0"
annotationProcessor "io.noties:prism4j-bundler:2.0.0"
implementation "com.github.HamidrezaAmz:BreadcrumbsView:0.2.9"
implementation "commons-io:commons-io:2.6"
implementation "commons-io:commons-io:20030203.000550"
implementation 'org.apache.commons:commons-lang3:3.12.0'
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"
implementation "ch.acra:acra-mail:$acra"
implementation "ch.acra:acra-limiter:$acra"
implementation "ch.acra:acra-notification:$acra"
implementation 'androidx.room:room-runtime:2.3.0'
annotationProcessor 'androidx.room:room-compiler:2.3.0'
implementation "androidx.work:work-runtime:$work_version"
implementation "io.mikael:urlbuilder:2.0.9"
implementation "org.codeberg.gitnex-garage:emoji-java:v5.1.2"
implementation "org.codeberg.gitnex:tea4j:1.0.24"
coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:1.1.5"
implementation 'androidx.biometric:biometric:1.1.0'
implementation 'com.github.chrisvest:stormpot:2.4.2'
}

View File

@ -19,3 +19,5 @@
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
-optimizationpasses 30
-allowaccessmodification

View File

@ -4,62 +4,92 @@
package="org.mian.gitnex">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<application
android:name=".core.MainApplication"
android:allowBackup="true"
android:icon="@mipmap/app_logo"
android:label="@string/app_name"
android:label="@string/appName"
android:networkSecurityConfig="@xml/network_security_config"
android:resizeableActivity="true"
android:roundIcon="@mipmap/app_logo_round"
android:supportsRtl="true"
tools:targetApi="n">
<activity android:name=".activities.MergePullRequestActivity" />
<activity
android:name=".activities.MergePullRequestActivity"
android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|uiMode|keyboard|keyboardHidden|navigation" />
<activity
android:name=".activities.FileViewActivity"
android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|uiMode|keyboard|keyboardHidden|navigation"
android:theme="@style/AppTheme.NoActionBar" />
<activity
android:name=".activities.NewFileActivity"
android:name=".activities.CreateFileActivity"
android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|uiMode|keyboard|keyboardHidden|navigation"
android:theme="@style/AppTheme.NoActionBar" />
<activity
android:name=".activities.RepoWatchersActivity"
android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|uiMode|keyboard|keyboardHidden|navigation"
android:theme="@style/AppTheme.NoActionBar" />
<activity
android:name=".activities.RepoStargazersActivity"
android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|uiMode|keyboard|keyboardHidden|navigation"
android:theme="@style/AppTheme.NoActionBar" />
<activity android:name=".activities.AdminGetUsersActivity" />
<activity
android:name=".activities.AddRemoveAssigneesActivity"
android:theme="@style/Theme.AppCompat.Light.Dialog" />
<activity android:name=".activities.CreateReleaseActivity" />
<activity android:name=".activities.EditIssueActivity" />
<activity android:name=".activities.CreateNewUserActivity" />
android:name=".activities.AdminGetUsersActivity"
android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|uiMode|keyboard|keyboardHidden|navigation" />
<activity
android:name=".activities.AddRemoveLabelsActivity"
android:theme="@style/Theme.AppCompat.Light.Dialog" />
<activity android:name=".activities.ProfileEmailActivity" />
<activity android:name=".activities.AddCollaboratorToRepositoryActivity" />
<activity android:name=".activities.CreateTeamByOrgActivity" />
<activity android:name=".activities.OrgTeamMembersActivity" />
android:name=".activities.CreateReleaseActivity"
android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|uiMode|keyboard|keyboardHidden|navigation" />
<activity
android:name=".activities.OrgDetailActivity"
android:label="@string/title_activity_org_detail"
android:name=".activities.EditIssueActivity"
android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|uiMode|keyboard|keyboardHidden|navigation" />
<activity
android:name=".activities.CreateNewUserActivity"
android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|uiMode|keyboard|keyboardHidden|navigation" />
<activity
android:name=".activities.MyProfileEmailActivity"
android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|uiMode|keyboard|keyboardHidden|navigation" />
<activity
android:name=".activities.AddCollaboratorToRepositoryActivity"
android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|uiMode|keyboard|keyboardHidden|navigation" />
<activity
android:name=".activities.CreateTeamByOrgActivity"
android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|uiMode|keyboard|keyboardHidden|navigation" />
<activity
android:name=".activities.OrganizationTeamMembersActivity"
android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|uiMode|keyboard|keyboardHidden|navigation" />
<activity
android:name=".activities.OrganizationDetailActivity"
android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|uiMode|keyboard|keyboardHidden|navigation"
android:label="@string/titleActivityOrgDetail"
android:theme="@style/AppTheme.NoActionBar" />
<activity android:name=".activities.SponsorsActivity" />
<activity android:name=".activities.CreditsActivity" />
<activity android:name=".activities.CreateLabelActivity" />
<activity android:name=".activities.CreateIssueActivity" />
<activity android:name=".activities.NewMilestoneActivity" />
<activity android:name=".activities.ReplyToIssueActivity" />
<activity
android:name=".activities.CreateLabelActivity"
android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|uiMode|keyboard|keyboardHidden|navigation" />
<activity
android:name=".activities.CreateIssueActivity"
android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|uiMode|keyboard|keyboardHidden|navigation" />
<activity
android:name=".activities.CreateMilestoneActivity"
android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|uiMode|keyboard|keyboardHidden|navigation" />
<activity
android:name=".activities.IssueDetailActivity"
android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|uiMode|keyboard|keyboardHidden|navigation"
android:windowSoftInputMode="adjustNothing" />
<activity
android:name=".activities.RepoDetailActivity"
android:label="@string/title_activity_repo_detail"
android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|uiMode|keyboard|keyboardHidden|navigation"
android:label="@string/titleActivityRepoDetail"
android:theme="@style/AppTheme.NoActionBar" />
<activity android:name=".activities.MainActivity" android:theme="@android:style/Theme.NoTitleBar.Fullscreen">
<activity
android:name=".activities.MainActivity"
android:theme="@android:style/Theme.NoTitleBar"
android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|uiMode|keyboard|keyboardHidden|navigation"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@ -68,11 +98,106 @@
</activity>
<activity
android:name=".activities.LoginActivity"
android:launchMode="singleTask" />
<activity android:name=".activities.NewRepoActivity" />
<activity android:name=".activities.NewOrganizationActivity" />
<activity android:name=".activities.OpenRepoInBrowserActivity" />
<activity android:name=".activities.FileDiffActivity" />
android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|uiMode|keyboard|keyboardHidden|navigation"
android:launchMode="singleTask"
android:theme="@android:style/Theme.NoTitleBar"/>
<activity
android:name=".activities.CreateRepoActivity"
android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|uiMode|keyboard|keyboardHidden|navigation" />
<activity
android:name=".activities.CreateOrganizationActivity"
android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|uiMode|keyboard|keyboardHidden|navigation" />
<activity
android:name=".activities.OpenRepoInBrowserActivity"
android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|uiMode|keyboard|keyboardHidden|navigation" />
<activity
android:name=".activities.FileDiffActivity"
android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|uiMode|keyboard|keyboardHidden|navigation" />
<activity
android:name=".activities.CommitsActivity"
android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|uiMode|keyboard|keyboardHidden|navigation" />
<activity
android:name=".helpers.ssl.MemorizingActivity"
android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|uiMode|keyboard|keyboardHidden|navigation"
android:theme="@android:style/Theme.Material.Dialog" />
<activity
android:name=".activities.SettingsAppearanceActivity"
android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|uiMode|keyboard|keyboardHidden|navigation" />
<activity
android:name=".activities.ProfileActivity"
android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|uiMode|keyboard|keyboardHidden|navigation" />
<activity
android:name=".activities.SettingsSecurityActivity"
android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|uiMode|keyboard|keyboardHidden|navigation" />
<activity
android:name=".activities.SettingsTranslationActivity"
android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|uiMode|keyboard|keyboardHidden|navigation" />
<activity
android:name=".activities.SettingsReportsActivity"
android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|uiMode|keyboard|keyboardHidden|navigation" />
<activity
android:name=".activities.AddNewTeamMemberActivity"
android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|uiMode|keyboard|keyboardHidden|navigation" />
<activity
android:name=".activities.SettingsDraftsActivity"
android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|uiMode|keyboard|keyboardHidden|navigation" />
<activity
android:name=".activities.RepoForksActivity"
android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|uiMode|keyboard|keyboardHidden|navigation" />
<activity
android:name=".activities.AddNewAccountActivity"
android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|uiMode|keyboard|keyboardHidden|navigation" />
<activity
android:name=".activities.RepositorySettingsActivity"
android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|uiMode|keyboard|keyboardHidden|navigation" />
<activity
android:name=".activities.CreatePullRequestActivity"
android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|uiMode|keyboard|keyboardHidden|navigation" />
<activity
android:name=".activities.SettingsGeneralActivity"
android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|uiMode|keyboard|keyboardHidden|navigation" />
<activity
android:name=".activities.SettingsNotificationsActivity"
android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|uiMode|keyboard|keyboardHidden|navigation" />
<activity
android:name=".activities.AdminCronTasksActivity"
android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|uiMode|keyboard|keyboardHidden|navigation" />
<!-- Version < 3.0. DeX Mode and Screen Mirroring support -->
<meta-data android:name="com.samsung.android.keepalive.density" android:value="true"/>
<!-- Version >= 3.0. DeX Dual Mode support -->
<meta-data android:name="com.samsung.android.multidisplay.keep_process_alive" android:value="true"/>
<!-- deep links -->
<activity
android:name=".activities.DeepLinksActivity"
android:theme="@android:style/Theme.Translucent.NoTitleBar"
android:noHistory="true"
android:launchMode="singleTask"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="http" />
<data android:scheme="https" />
<data android:host="codeberg.org" />
<data android:host="gitea.com" />
<data android:host="try.gitea.io" />
<data android:host="code.obermui.de" />
<data android:host="git.fsfe.org" />
<data android:host="opendev.org" />
<data android:host="git.shihaam.dev" />
<data android:host="git.athfan.com" />
<data android:host="git.athfan.dev" />
</intent-filter>
</activity>
<!-- deep links -->
</application>
</manifest>
</manifest>

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

View File

@ -0,0 +1,80 @@
package org.mian.gitnex.actions;
import androidx.annotation.NonNull;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
/**
* @author opyale
*/
public class ActionResult<R> {
public enum Status { SUCCESS, FAILED }
private final BlockingQueue<Boolean> blockingQueue;
private final List<OnFinishedListener<R>> onFinishedListeners;
private boolean invalidated = false;
public ActionResult() {
blockingQueue = new ArrayBlockingQueue<>(1);
onFinishedListeners = new ArrayList<>();
}
public void finish(@NonNull Status status) {
finish(status, null);
}
public void finish(@NonNull Status status, R result) {
try {
if(blockingQueue.poll(5, TimeUnit.SECONDS)) {
for(OnFinishedListener<R> onFinishedListener : onFinishedListeners)
onFinishedListener.onFinished(status, result);
}
} catch (InterruptedException ignored) {}
}
public void invalidate() {
if(invalidated) throw new IllegalStateException("Already invalidated");
this.invalidated = true;
}
@SafeVarargs
public synchronized final void accept(@NonNull OnFinishedListener<R>... onFinishedListeners) {
invalidate();
this.blockingQueue.add(true);
this.onFinishedListeners.addAll(Arrays.asList(onFinishedListeners));
}
public synchronized final void discard() {
invalidate();
this.blockingQueue.add(false);
}
public static class None {}
public interface OnFinishedListener<R> {
void onFinished(Status status, R result);
}
}

View File

@ -0,0 +1,118 @@
package org.mian.gitnex.actions;
import android.app.Dialog;
import android.content.Context;
import android.util.Log;
import android.view.View;
import androidx.annotation.NonNull;
import org.gitnex.tea4j.models.Collaborators;
import org.gitnex.tea4j.models.Issues;
import org.mian.gitnex.R;
import org.mian.gitnex.adapters.AssigneesListAdapter;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.databinding.CustomAssigneesSelectionDialogBinding;
import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.helpers.TinyDB;
import org.mian.gitnex.helpers.Toasty;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
/**
* Author M M Arif
*/
public class AssigneesActions {
public static void getCurrentIssueAssignees(Context ctx, String repoOwner, String repoName, int issueIndex, List<String> currentAssignees) {
Call<Issues> callSingleIssueLabels = RetrofitClient
.getApiInterface(ctx)
.getIssueByIndex(Authorization.get(ctx), repoOwner, repoName, issueIndex);
callSingleIssueLabels.enqueue(new Callback<Issues>() {
@Override
public void onResponse(@NonNull Call<Issues> call, @NonNull retrofit2.Response<Issues> response) {
if(response.code() == 200) {
Issues issueAssigneesList = response.body();
assert issueAssigneesList != null;
if (issueAssigneesList.getAssignees() != null) {
if(issueAssigneesList.getAssignees().size() > 0) {
for(int i = 0; i < issueAssigneesList.getAssignees().size(); i++) {
currentAssignees.add(issueAssigneesList.getAssignees().get(i).getLogin());
}
}
}
}
}
@Override
public void onFailure(@NonNull Call<Issues> call, @NonNull Throwable t) {
Log.e("onFailure", t.toString());
}
});
}
public static void getRepositoryAssignees(Context ctx, String repoOwner, String repoName, List<Collaborators> assigneesList, Dialog dialogAssignees, AssigneesListAdapter assigneesAdapter, CustomAssigneesSelectionDialogBinding assigneesBinding) {
TinyDB tinyDB = TinyDB.getInstance(ctx);
Call<List<Collaborators>> call = RetrofitClient
.getApiInterface(ctx)
.getCollaborators(Authorization.get(ctx), repoOwner, repoName);
call.enqueue(new Callback<List<Collaborators>>() {
@Override
public void onResponse(@NonNull Call<List<Collaborators>> call, @NonNull retrofit2.Response<List<Collaborators>> response) {
assigneesList.clear();
List<Collaborators> assigneesList_ = response.body();
assigneesBinding.progressBar.setVisibility(View.GONE);
assigneesBinding.dialogFrame.setVisibility(View.VISIBLE);
if (response.code() == 200) {
assert assigneesList_ != null;
if(assigneesList_.size() > 0) {
assigneesList.add(new Collaborators(tinyDB.getString("userFullname"), tinyDB.getString("loginUid"), tinyDB.getString("userAvatar")));
assigneesList.addAll(assigneesList_);
}
else {
dialogAssignees.dismiss();
Toasty.warning(ctx, ctx.getResources().getString(R.string.noAssigneesFound));
}
assigneesBinding.assigneesRecyclerView.setAdapter(assigneesAdapter);
}
else {
Toasty.error(ctx, ctx.getResources().getString(R.string.genericError));
}
}
@Override
public void onFailure(@NonNull Call<List<Collaborators>> call, @NonNull Throwable t) {
Toasty.error(ctx, ctx.getResources().getString(R.string.genericServerResponseError));
}
});
}
}

View File

@ -2,18 +2,20 @@ package org.mian.gitnex.actions;
import android.content.Context;
import android.util.Log;
import androidx.annotation.NonNull;
import org.gitnex.tea4j.models.Collaborators;
import org.gitnex.tea4j.models.Permission;
import org.mian.gitnex.R;
import org.mian.gitnex.activities.AddCollaboratorToRepositoryActivity;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.helpers.AlertDialogs;
import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.helpers.TinyDB;
import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.models.Collaborators;
import org.mian.gitnex.models.Permission;
import org.mian.gitnex.util.TinyDB;
import androidx.annotation.NonNull;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
/**
* Author M M Arif
@ -23,21 +25,16 @@ public class CollaboratorActions {
public static void deleteCollaborator(final Context context, final String searchKeyword, String userName) {
final TinyDB tinyDb = new TinyDB(context);
final String instanceUrl = tinyDb.getString("instanceUrl");
final String loginUid = tinyDb.getString("loginUid");
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
final TinyDB tinyDb = TinyDB.getInstance(context);
String repoFullName = tinyDb.getString("repoFullName");
String[] parts = repoFullName.split("/");
final String repoOwner = parts[0];
final String repoName = parts[1];
Call<Collaborators> call;
call = RetrofitClient
.getInstance(instanceUrl, context)
.getApiInterface()
.deleteCollaborator(Authorization.returnAuthentication(context, loginUid, instanceToken), repoOwner, repoName, userName);
Call<Collaborators> call = RetrofitClient
.getApiInterface(context)
.deleteCollaborator(Authorization.get(context), repoOwner, repoName, userName);
call.enqueue(new Callback<Collaborators>() {
@ -47,12 +44,12 @@ public class CollaboratorActions {
if(response.isSuccessful()) {
if(response.code() == 204) {
Toasty.info(context, context.getString(R.string.removeCollaboratorToastText));
Toasty.success(context, context.getString(R.string.removeCollaboratorToastText));
((AddCollaboratorToRepositoryActivity)context).finish();
//Log.i("addCollaboratorSearch", addCollaboratorSearch.getText().toString());
//tinyDb.putBoolean("updateDataSet", true);
//AddCollaboratorToRepositoryActivity usersSearchData = new AddCollaboratorToRepositoryActivity();
//usersSearchData.loadUserSearchList(instanceUrl, instanceToken, searchKeyword, context);
//usersSearchData.loadUserSearchList(instanceToken, searchKeyword, context);
}
}
@ -66,17 +63,17 @@ public class CollaboratorActions {
}
else if(response.code() == 403) {
Toasty.info(context, context.getString(R.string.authorizeError));
Toasty.error(context, context.getString(R.string.authorizeError));
}
else if(response.code() == 404) {
Toasty.info(context, context.getString(R.string.apiNotFound));
Toasty.warning(context, context.getString(R.string.apiNotFound));
}
else {
Toasty.info(context, context.getString(R.string.genericError));
Toasty.error(context, context.getString(R.string.genericError));
}
@ -92,22 +89,18 @@ public class CollaboratorActions {
public static void addCollaborator(final Context context, String permission, String userName) {
final TinyDB tinyDb = new TinyDB(context);
final String instanceUrl = tinyDb.getString("instanceUrl");
final String loginUid = tinyDb.getString("loginUid");
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
final TinyDB tinyDb = TinyDB.getInstance(context);
String repoFullName = tinyDb.getString("repoFullName");
String[] parts = repoFullName.split("/");
final String repoOwner = parts[0];
final String repoName = parts[1];
Permission permissionString = new Permission(permission);
Call<Permission> call;
call = RetrofitClient
.getInstance(instanceUrl, context)
.getApiInterface()
.addCollaborator(Authorization.returnAuthentication(context, loginUid, instanceToken), repoOwner, repoName, userName, permissionString);
Call<Permission> call = RetrofitClient
.getApiInterface(context)
.addCollaborator(Authorization.get(context), repoOwner, repoName, userName, permissionString);
call.enqueue(new Callback<Permission>() {
@ -117,10 +110,10 @@ public class CollaboratorActions {
if(response.isSuccessful()) {
if(response.code() == 204) {
Toasty.info(context, context.getString(R.string.addCollaboratorToastText));
Toasty.success(context, context.getString(R.string.addCollaboratorToastText));
((AddCollaboratorToRepositoryActivity)context).finish();
//AddCollaboratorToRepositoryActivity usersSearchData = new AddCollaboratorToRepositoryActivity();
//usersSearchData.loadUserSearchList(instanceUrl, instanceToken, searchKeyword, context);
//usersSearchData.loadUserSearchList(instanceToken, searchKeyword, context);
}
}
@ -134,17 +127,17 @@ public class CollaboratorActions {
}
else if(response.code() == 403) {
Toasty.info(context, context.getString(R.string.authorizeError));
Toasty.error(context, context.getString(R.string.authorizeError));
}
else if(response.code() == 404) {
Toasty.info(context, context.getString(R.string.apiNotFound));
Toasty.warning(context, context.getString(R.string.apiNotFound));
}
else {
Toasty.info(context, context.getString(R.string.genericError));
Toasty.error(context, context.getString(R.string.genericError));
}
@ -154,8 +147,50 @@ public class CollaboratorActions {
public void onFailure(@NonNull Call<Permission> call, @NonNull Throwable t) {
Log.e("onFailure", t.toString());
}
});
}
public static ActionResult<List<Collaborators>> getCollaborators(Context context) {
ActionResult<List<Collaborators>> actionResult = new ActionResult<>();
TinyDB tinyDb = TinyDB.getInstance(context);
String repoFullName = tinyDb.getString("repoFullName");
String[] parts = repoFullName.split("/");
String repoOwner = parts[0];
String repoName = parts[1];
Call<List<Collaborators>> call = RetrofitClient
.getApiInterface(context)
.getCollaborators(Authorization.get(context), 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;
actionResult.finish(ActionResult.Status.SUCCESS, response.body());
}
else {
actionResult.finish(ActionResult.Status.FAILED);
}
}
@Override
public void onFailure(@NonNull Call<List<Collaborators>> call, @NonNull Throwable t) {
actionResult.finish(ActionResult.Status.FAILED);
}
});
return actionResult;
}
}

View File

@ -1,20 +1,20 @@
package org.mian.gitnex.actions;
import android.content.Context;
import android.util.Log;
import androidx.annotation.NonNull;
import com.google.gson.JsonElement;
import org.gitnex.tea4j.models.IssueComments;
import org.gitnex.tea4j.models.Issues;
import org.gitnex.tea4j.models.UpdateIssueState;
import org.mian.gitnex.R;
import org.mian.gitnex.activities.ReplyToIssueActivity;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.helpers.AlertDialogs;
import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.helpers.TinyDB;
import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.models.UpdateIssueState;
import org.mian.gitnex.models.IssueComments;
import org.mian.gitnex.util.TinyDB;
import androidx.annotation.NonNull;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
/**
* Author M M Arif
@ -22,143 +22,306 @@ import retrofit2.Callback;
public class IssueActions {
public static void editIssueComment(final Context context, final int commentId, final String commentBody) {
public static ActionResult<Response<?>> edit(Context context, String comment, int commentId) {
final TinyDB tinyDb = new TinyDB(context);
final String instanceUrl = tinyDb.getString("instanceUrl");
final String loginUid = tinyDb.getString("loginUid");
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
String repoFullName = tinyDb.getString("repoFullName");
String[] parts = repoFullName.split("/");
final String repoOwner = parts[0];
final String repoName = parts[1];
ActionResult<Response<?>> actionResult = new ActionResult<>();
IssueComments commentBodyJson = new IssueComments(commentBody);
Call<IssueComments> call;
TinyDB tinyDb = TinyDB.getInstance(context);
call = RetrofitClient
.getInstance(instanceUrl, context)
.getApiInterface()
.patchIssueComment(Authorization.returnAuthentication(context, loginUid, instanceToken), repoOwner, repoName, commentId, commentBodyJson);
String repoFullName = tinyDb.getString("repoFullName");
String[] parts = repoFullName.split("/");
call.enqueue(new Callback<IssueComments>() {
String repoOwner = parts[0];
String repoName = parts[1];
@Override
public void onResponse(@NonNull Call<IssueComments> call, @NonNull retrofit2.Response<IssueComments> response) {
Call<IssueComments> call = RetrofitClient
.getApiInterface(context)
.patchIssueComment(Authorization.get(context), repoOwner, repoName, commentId, new IssueComments(comment));
if(response.isSuccessful()) {
if(response.code() == 200) {
call.enqueue(new Callback<IssueComments>() {
tinyDb.putBoolean("commentEdited", true);
Toasty.info(context, context.getString(R.string.editCommentUpdatedText));
((ReplyToIssueActivity)context).finish();
@Override
public void onResponse(@NonNull Call<IssueComments> call, @NonNull retrofit2.Response<IssueComments> response) {
}
}
else if(response.code() == 401) {
switch(response.code()) {
AlertDialogs.authorizationTokenRevokedDialog(context, context.getResources().getString(R.string.alertDialogTokenRevokedTitle),
context.getResources().getString(R.string.alertDialogTokenRevokedMessage),
context.getResources().getString(R.string.alertDialogTokenRevokedCopyNegativeButton),
context.getResources().getString(R.string.alertDialogTokenRevokedCopyPositiveButton));
case 200:
actionResult.finish(ActionResult.Status.SUCCESS);
break;
}
else if(response.code() == 403) {
case 401:
actionResult.finish(ActionResult.Status.FAILED, response);
AlertDialogs.authorizationTokenRevokedDialog(context, context.getResources().getString(R.string.alertDialogTokenRevokedTitle), context.getResources().getString(R.string.alertDialogTokenRevokedMessage), context.getResources().getString(R.string.alertDialogTokenRevokedCopyNegativeButton), context.getResources().getString(R.string.alertDialogTokenRevokedCopyPositiveButton));
break;
Toasty.info(context, context.getString(R.string.authorizeError));
default:
actionResult.finish(ActionResult.Status.FAILED, response);
break;
}
else if(response.code() == 404) {
}
}
Toasty.info(context, context.getString(R.string.apiNotFound));
@Override
public void onFailure(@NonNull Call<IssueComments> call, @NonNull Throwable t) {
}
else {
actionResult.finish(ActionResult.Status.FAILED);
}
});
Toasty.info(context, context.getString(R.string.genericError));
return actionResult;
}
}
}
public static void closeReopenIssue(final Context ctx, final int issueIndex, final String issueState) {
@Override
public void onFailure(@NonNull Call<IssueComments> call, @NonNull Throwable t) {
Log.e("onFailure", t.toString());
}
});
final TinyDB tinyDb = TinyDB.getInstance(ctx);
}
String repoFullName = tinyDb.getString("repoFullName");
String[] parts = repoFullName.split("/");
public static void closeReopenIssue(final Context context, final int issueIndex, final String issueState) {
final String repoOwner = parts[0];
final String repoName = parts[1];
final TinyDB tinyDb = new TinyDB(context);
final String instanceUrl = tinyDb.getString("instanceUrl");
final String loginUid = tinyDb.getString("loginUid");
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
String repoFullName = tinyDb.getString("repoFullName");
String[] parts = repoFullName.split("/");
final String repoOwner = parts[0];
final String repoName = parts[1];
UpdateIssueState issueStatJson = new UpdateIssueState(issueState);
Call<JsonElement> call;
UpdateIssueState issueStatJson = new UpdateIssueState(issueState);
Call<JsonElement> call;
call = RetrofitClient
.getApiInterface(ctx)
.closeReopenIssue(Authorization.get(ctx), repoOwner, repoName, issueIndex, issueStatJson);
call = RetrofitClient
.getInstance(instanceUrl, context)
.getApiInterface()
.closeReopenIssue(Authorization.returnAuthentication(context, loginUid, instanceToken), repoOwner, repoName, issueIndex, issueStatJson);
call.enqueue(new Callback<JsonElement>() {
call.enqueue(new Callback<JsonElement>() {
@Override
public void onResponse(@NonNull Call<JsonElement> call, @NonNull retrofit2.Response<JsonElement> response) {
@Override
public void onResponse(@NonNull Call<JsonElement> call, @NonNull retrofit2.Response<JsonElement> response) {
if(response.isSuccessful()) {
if(response.code() == 201) {
if(response.isSuccessful()) {
if(response.code() == 201) {
tinyDb.putBoolean("resumeIssues", true);
tinyDb.putBoolean("resumeClosedIssues", true);
tinyDb.putBoolean("resumeIssues", true);
tinyDb.putBoolean("resumeClosedIssues", true);
if(issueState.equals("closed")) {
Toasty.info(context, context.getString(R.string.issueStateClosed));
}
else if(issueState.equals("open")) {
Toasty.info(context, context.getString(R.string.issueStateReopened));
}
if(issueState.equals("closed")) {
}
}
else if(response.code() == 401) {
Toasty.success(ctx, ctx.getString(R.string.issueStateClosed));
tinyDb.putString("issueState", "closed");
AlertDialogs.authorizationTokenRevokedDialog(context, context.getResources().getString(R.string.alertDialogTokenRevokedTitle),
context.getResources().getString(R.string.alertDialogTokenRevokedMessage),
context.getResources().getString(R.string.alertDialogTokenRevokedCopyNegativeButton),
context.getResources().getString(R.string.alertDialogTokenRevokedCopyPositiveButton));
}
else if(issueState.equals("open")) {
}
else if(response.code() == 403) {
Toasty.success(ctx, ctx.getString(R.string.issueStateReopened));
tinyDb.putString("issueState", "open");
Toasty.info(context, context.getString(R.string.authorizeError));
}
}
else if(response.code() == 404) {
}
}
else if(response.code() == 401) {
Toasty.info(context, context.getString(R.string.apiNotFound));
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 {
}
else if(response.code() == 403) {
Toasty.info(context, context.getString(R.string.genericError));
Toasty.error(ctx, ctx.getString(R.string.authorizeError));
}
}
else if(response.code() == 404) {
}
Toasty.warning(ctx, ctx.getString(R.string.apiNotFound));
@Override
public void onFailure(@NonNull Call<JsonElement> call, @NonNull Throwable t) {
Log.e("onFailure", t.toString());
}
});
}
else {
}
Toasty.error(ctx, ctx.getString(R.string.genericError));
}
}
@Override
public void onFailure(@NonNull Call<JsonElement> call, @NonNull Throwable t) {
Toasty.error(ctx, ctx.getResources().getString(R.string.genericServerResponseError));
}
});
}
public static void subscribe(final Context ctx) {
final TinyDB tinyDB = TinyDB.getInstance(ctx);
String[] repoFullName = tinyDB.getString("repoFullName").split("/");
if(repoFullName.length != 2) {
return;
}
final String userLogin = tinyDB.getString("userLogin");
final String token = "token " + tinyDB.getString(tinyDB.getString("loginUid") + "-token");
final int issueNr = Integer.parseInt(tinyDB.getString("issueNumber"));
Call<Void> call;
call = RetrofitClient
.getApiInterface(ctx)
.addIssueSubscriber(token, repoFullName[0], repoFullName[1], 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) {
Toasty.success(ctx, ctx.getString(R.string.subscribedSuccessfully));
tinyDB.putBoolean("issueSubscribed", true);
}
else if(response.code() == 200) {
tinyDB.putBoolean("issueSubscribed", true);
Toasty.success(ctx, ctx.getString(R.string.alreadySubscribed));
}
}
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.error(ctx, ctx.getString(R.string.subscriptionError));
}
}
@Override
public void onFailure(@NonNull Call<Void> call, @NonNull Throwable t) {
Toasty.error(ctx, ctx.getResources().getString(R.string.genericServerResponseError));
}
});
}
public static void unsubscribe(final Context ctx) {
final TinyDB tinyDB = TinyDB.getInstance(ctx);
String[] repoFullName = tinyDB.getString("repoFullName").split("/");
if(repoFullName.length != 2) {
return;
}
final String userLogin = tinyDB.getString("userLogin");
final String token = "token " + tinyDB.getString(tinyDB.getString("loginUid") + "-token");
final int issueNr = Integer.parseInt(tinyDB.getString("issueNumber"));
Call<Void> call;
call = RetrofitClient.getApiInterface(ctx).delIssueSubscriber(token, repoFullName[0], repoFullName[1], 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) {
Toasty.success(ctx, ctx.getString(R.string.unsubscribedSuccessfully));
tinyDB.putBoolean("issueSubscribed", false);
}
else if(response.code() == 200) {
tinyDB.putBoolean("issueSubscribed", false);
Toasty.success(ctx, ctx.getString(R.string.alreadyUnsubscribed));
}
}
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.error(ctx, ctx.getString(R.string.unSubscriptionError));
}
}
@Override
public void onFailure(@NonNull Call<Void> call, @NonNull Throwable t) {
Toasty.error(ctx, ctx.getResources().getString(R.string.genericServerResponseError));
}
});
}
public static ActionResult<ActionResult.None> reply(Context context, String comment, int issueIndex) {
ActionResult<ActionResult.None> actionResult = new ActionResult<>();
TinyDB tinyDb = TinyDB.getInstance(context);
String repoFullName = tinyDb.getString("repoFullName");
String[] parts = repoFullName.split("/");
String repoOwner = parts[0];
String repoName = parts[1];
Issues issueComment = new Issues(comment);
Call<Issues> call = RetrofitClient
.getApiInterface(context)
.replyCommentToIssue(Authorization.get(context), repoOwner, repoName, issueIndex, issueComment);
call.enqueue(new Callback<Issues>() {
@Override
public void onResponse(@NonNull Call<Issues> call, @NonNull retrofit2.Response<Issues> response) {
if(response.code() == 201) {
actionResult.finish(ActionResult.Status.SUCCESS);
tinyDb.putBoolean("commentPosted", true);
tinyDb.putBoolean("resumeIssues", true);
tinyDb.putBoolean("resumePullRequests", true);
}
else if(response.code() == 401) {
AlertDialogs.authorizationTokenRevokedDialog(context, context.getString(R.string.alertDialogTokenRevokedTitle),
context.getString(R.string.alertDialogTokenRevokedMessage),
context.getString(R.string.alertDialogTokenRevokedCopyNegativeButton),
context.getString(R.string.alertDialogTokenRevokedCopyPositiveButton));
}
else {
actionResult.finish(ActionResult.Status.FAILED);
}
}
@Override
public void onFailure(@NonNull Call<Issues> call, @NonNull Throwable t) {
Toasty.error(context, context.getResources().getString(R.string.genericServerResponseError));
}
});
return actionResult;
}
}

View File

@ -0,0 +1,131 @@
package org.mian.gitnex.actions;
import android.app.Dialog;
import android.content.Context;
import android.util.Log;
import android.view.View;
import androidx.annotation.NonNull;
import org.gitnex.tea4j.models.Labels;
import org.mian.gitnex.R;
import org.mian.gitnex.adapters.LabelsListAdapter;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.databinding.CustomLabelsSelectionDialogBinding;
import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.helpers.Toasty;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
/**
* Author M M Arif
*/
public class LabelsActions {
public static void getCurrentIssueLabels(Context ctx, String repoOwner, String repoName, int issueIndex, List<Integer> currentLabelsIds) {
Call<List<Labels>> callSingleIssueLabels = RetrofitClient
.getApiInterface(ctx)
.getIssueLabels(Authorization.get(ctx), repoOwner, repoName, issueIndex);
callSingleIssueLabels.enqueue(new Callback<List<Labels>>() {
@Override
public void onResponse(@NonNull Call<List<Labels>> call, @NonNull retrofit2.Response<List<Labels>> response) {
if(response.code() == 200) {
List<Labels> issueLabelsList = response.body();
assert issueLabelsList != null;
if(issueLabelsList.size() > 0) {
for (int i = 0; i < issueLabelsList.size(); i++) {
currentLabelsIds.add(issueLabelsList.get(i).getId());
}
}
}
}
@Override
public void onFailure(@NonNull Call<List<Labels>> call, @NonNull Throwable t) {
Log.e("onFailure", t.toString());
}
});
}
public static void getRepositoryLabels(Context ctx, String repoOwner, String repoName, List<Labels> labelsList, Dialog dialogLabels, LabelsListAdapter labelsAdapter, CustomLabelsSelectionDialogBinding labelsBinding) {
Call<List<Labels>> call = RetrofitClient
.getApiInterface(ctx)
.getLabels(Authorization.get(ctx), repoOwner, repoName);
call.enqueue(new Callback<List<Labels>>() {
@Override
public void onResponse(@NonNull Call<List<Labels>> call, @NonNull retrofit2.Response<List<Labels>> response) {
labelsList.clear();
if (response.code() == 200) {
if(response.body() != null) {
labelsList.addAll(response.body());
}
// Load organization labels
Call<List<Labels>> callOrgLabels = RetrofitClient
.getApiInterface(ctx)
.getOrganizationLabels(Authorization.get(ctx), repoOwner);
callOrgLabels.enqueue(new Callback<List<Labels>>() {
@Override
public void onResponse(@NonNull Call<List<Labels>> call, @NonNull retrofit2.Response<List<Labels>> responseOrg) {
labelsBinding.progressBar.setVisibility(View.GONE);
labelsBinding.dialogFrame.setVisibility(View.VISIBLE);
if(responseOrg.body() != null) {
labelsList.addAll(responseOrg.body());
}
if(labelsList.isEmpty()) {
dialogLabels.dismiss();
Toasty.warning(ctx, ctx.getResources().getString(R.string.noLabelsFound));
}
labelsBinding.labelsRecyclerView.setAdapter(labelsAdapter);
}
@Override public void onFailure(@NonNull Call<List<Labels>> call, @NonNull Throwable t) {}
});
}
else {
Toasty.error(ctx, ctx.getResources().getString(R.string.genericError));
}
}
@Override
public void onFailure(@NonNull Call<List<Labels>> call, @NonNull Throwable t) {
Toasty.error(ctx, ctx.getResources().getString(R.string.genericServerResponseError));
}
});
}
}

View File

@ -0,0 +1,135 @@
package org.mian.gitnex.actions;
import android.content.Context;
import android.util.Log;
import androidx.annotation.NonNull;
import com.google.gson.JsonElement;
import org.gitnex.tea4j.models.Milestones;
import org.mian.gitnex.R;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.helpers.AlertDialogs;
import org.mian.gitnex.helpers.TinyDB;
import org.mian.gitnex.helpers.Toasty;
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 = TinyDB.getInstance(ctx);
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
.getApiInterface(ctx)
.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.success(ctx, ctx.getString(R.string.milestoneStatusUpdate));
}
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.error(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 = TinyDB.getInstance(ctx);
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
.getApiInterface(ctx)
.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.success(ctx, ctx.getString(R.string.milestoneStatusUpdate));
}
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.error(ctx, ctx.getString(R.string.genericError));
}
}
@Override
public void onFailure(@NonNull Call<JsonElement> call, @NonNull Throwable t) {
Log.e(TAG, t.toString());
}
});
}
}

View File

@ -0,0 +1,56 @@
package org.mian.gitnex.actions;
import android.content.Context;
import org.gitnex.tea4j.models.NotificationThread;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.helpers.AppUtil;
import org.mian.gitnex.helpers.TinyDB;
import java.io.IOException;
import java.util.Date;
import retrofit2.Call;
/**
* Author opyale
*/
public class NotificationsActions {
public enum NotificationStatus {READ, UNREAD, PINNED}
private TinyDB tinyDB;
private Context context;
private String instanceToken;
public NotificationsActions(Context context) {
this.context = context;
this.tinyDB = TinyDB.getInstance(context);
String loginUid = tinyDB.getString("loginUid");
instanceToken = "token " + tinyDB.getString(loginUid + "-token");
}
public void setNotificationStatus(NotificationThread notificationThread, NotificationStatus notificationStatus) throws IOException {
Call<Void> call = RetrofitClient.getApiInterface(context)
.markNotificationThreadAsRead(instanceToken, notificationThread.getId(), notificationStatus.name());
if(!call.execute().isSuccessful()) {
throw new IllegalStateException();
}
}
public boolean setAllNotificationsRead(Date date) throws IOException {
Call<Void> call = RetrofitClient.getApiInterface(context)
.markNotificationThreadsAsRead(instanceToken, AppUtil.getTimestampFromDate(context, date), true,
new String[]{"unread", "pinned"}, "read");
return call.execute().isSuccessful();
}
}

View File

@ -0,0 +1,102 @@
package org.mian.gitnex.actions;
import android.content.Context;
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 retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
/**
* Author qwerty287
*/
public class PullRequestActions {
public static void deleteHeadBranch(Context context, String repoOwner, String repoName, String headBranch, boolean showToasts) {
Call<JsonElement> call = RetrofitClient
.getApiInterface(context)
.deleteBranch(Authorization.get(context), repoOwner, repoName, headBranch);
call.enqueue(new Callback<JsonElement>() {
@Override
public void onResponse(@NonNull Call<JsonElement> call, @NonNull retrofit2.Response<JsonElement> response) {
if(response.code() == 204) {
if(showToasts) Toasty.success(context, context.getString(R.string.deleteBranchSuccess));
}
else if(response.code() == 401) {
AlertDialogs
.authorizationTokenRevokedDialog(context, context.getResources().getString(R.string.alertDialogTokenRevokedTitle), context.getResources().getString(R.string.alertDialogTokenRevokedMessage), context.getResources().getString(R.string.alertDialogTokenRevokedCopyNegativeButton), context.getResources().getString(R.string.alertDialogTokenRevokedCopyPositiveButton));
}
else if(response.code() == 403) {
if(showToasts) Toasty.error(context, context.getString(R.string.authorizeError));
}
else if(response.code() == 404) {
if(showToasts) Toasty.warning(context, context.getString(R.string.deleteBranchErrorNotFound));
}
else {
if(showToasts) Toasty.error(context, context.getString(R.string.genericError));
}
}
@Override
public void onFailure(@NonNull Call<JsonElement> call, @NonNull Throwable t) {
if(showToasts) Toasty.error(context, context.getString(R.string.deleteBranchError));
}
});
}
public static void updatePr(Context context, String repoOwner, String repoName, String index, Boolean rebase) {
String strategy;
if(rebase == null) {
strategy = null;
}
else if(!rebase) {
strategy = "merge";
}
else {
strategy = "rebase";
}
RetrofitClient.getApiInterface(context).updatePullRequest(Authorization.get(context), repoOwner, repoName, Integer.parseInt(index), strategy)
.enqueue(new Callback<Void>() {
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) {
if(response.isSuccessful()) {
Toasty.success(context, context.getString(R.string.updatePrSuccess));
}
else {
if(response.code() == 403) {
Toasty.error(context, context.getString(R.string.authorizeError));
}
else if(response.code() == 409) {
Toasty.error(context, context.getString(R.string.updatePrConflict));
}
else {
Toasty.error(context, context.getString(R.string.genericError));
}
}
}
@Override
public void onFailure(@NonNull Call call, @NonNull Throwable t) {
Toasty.error(context, context.getString(R.string.genericError));
}
});
}
}

View File

@ -8,8 +8,8 @@ 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.TinyDB;
import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.util.TinyDB;
import retrofit2.Call;
import retrofit2.Callback;
@ -21,10 +21,8 @@ public class RepositoryActions {
public static void starRepository(final Context context) {
final TinyDB tinyDb = new TinyDB(context);
final String instanceUrl = tinyDb.getString("instanceUrl");
final String loginUid = tinyDb.getString("loginUid");
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
final TinyDB tinyDb = TinyDB.getInstance(context);
String repoFullName = tinyDb.getString("repoFullName");
String[] parts = repoFullName.split("/");
final String repoOwner = parts[0];
@ -33,9 +31,8 @@ public class RepositoryActions {
Call<JsonElement> call;
call = RetrofitClient
.getInstance(instanceUrl, context)
.getApiInterface()
.starRepository(Authorization.returnAuthentication(context, loginUid, instanceToken), repoOwner, repoName);
.getApiInterface(context)
.starRepository(Authorization.get(context), repoOwner, repoName);
call.enqueue(new Callback<JsonElement>() {
@ -46,7 +43,7 @@ public class RepositoryActions {
if(response.code() == 204) {
tinyDb.putBoolean("repoCreated", true);
Toasty.info(context, context.getString(R.string.starRepositorySuccess));
Toasty.success(context, context.getString(R.string.starRepositorySuccess));
}
}
@ -60,17 +57,17 @@ public class RepositoryActions {
}
else if(response.code() == 403) {
Toasty.info(context, context.getString(R.string.authorizeError));
Toasty.error(context, context.getString(R.string.authorizeError));
}
else if(response.code() == 404) {
Toasty.info(context, context.getString(R.string.apiNotFound));
Toasty.warning(context, context.getString(R.string.apiNotFound));
}
else {
Toasty.info(context, context.getString(R.string.genericError));
Toasty.error(context, context.getString(R.string.genericError));
}
@ -86,10 +83,8 @@ public class RepositoryActions {
public static void unStarRepository(final Context context) {
final TinyDB tinyDb = new TinyDB(context);
final String instanceUrl = tinyDb.getString("instanceUrl");
final String loginUid = tinyDb.getString("loginUid");
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
final TinyDB tinyDb = TinyDB.getInstance(context);
String repoFullName = tinyDb.getString("repoFullName");
String[] parts = repoFullName.split("/");
final String repoOwner = parts[0];
@ -98,9 +93,8 @@ public class RepositoryActions {
Call<JsonElement> call;
call = RetrofitClient
.getInstance(instanceUrl, context)
.getApiInterface()
.unStarRepository(Authorization.returnAuthentication(context, loginUid, instanceToken), repoOwner, repoName);
.getApiInterface(context)
.unStarRepository(Authorization.get(context), repoOwner, repoName);
call.enqueue(new Callback<JsonElement>() {
@ -111,7 +105,7 @@ public class RepositoryActions {
if(response.code() == 204) {
tinyDb.putBoolean("repoCreated", true);
Toasty.info(context, context.getString(R.string.unStarRepositorySuccess));
Toasty.success(context, context.getString(R.string.unStarRepositorySuccess));
}
}
@ -125,17 +119,17 @@ public class RepositoryActions {
}
else if(response.code() == 403) {
Toasty.info(context, context.getString(R.string.authorizeError));
Toasty.error(context, context.getString(R.string.authorizeError));
}
else if(response.code() == 404) {
Toasty.info(context, context.getString(R.string.apiNotFound));
Toasty.warning(context, context.getString(R.string.apiNotFound));
}
else {
Toasty.info(context, context.getString(R.string.genericError));
Toasty.error(context, context.getString(R.string.genericError));
}
@ -151,10 +145,8 @@ public class RepositoryActions {
public static void watchRepository(final Context context) {
final TinyDB tinyDb = new TinyDB(context);
final String instanceUrl = tinyDb.getString("instanceUrl");
final String loginUid = tinyDb.getString("loginUid");
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
final TinyDB tinyDb = TinyDB.getInstance(context);
String repoFullName = tinyDb.getString("repoFullName");
String[] parts = repoFullName.split("/");
final String repoOwner = parts[0];
@ -163,9 +155,8 @@ public class RepositoryActions {
Call<JsonElement> call;
call = RetrofitClient
.getInstance(instanceUrl, context)
.getApiInterface()
.watchRepository(Authorization.returnAuthentication(context, loginUid, instanceToken), repoOwner, repoName);
.getApiInterface(context)
.watchRepository(Authorization.get(context), repoOwner, repoName);
call.enqueue(new Callback<JsonElement>() {
@ -176,7 +167,7 @@ public class RepositoryActions {
if(response.code() == 200) {
tinyDb.putBoolean("repoCreated", true);
Toasty.info(context, context.getString(R.string.watchRepositorySuccess));
Toasty.success(context, context.getString(R.string.watchRepositorySuccess));
}
}
@ -190,17 +181,17 @@ public class RepositoryActions {
}
else if(response.code() == 403) {
Toasty.info(context, context.getString(R.string.authorizeError));
Toasty.error(context, context.getString(R.string.authorizeError));
}
else if(response.code() == 404) {
Toasty.info(context, context.getString(R.string.apiNotFound));
Toasty.warning(context, context.getString(R.string.apiNotFound));
}
else {
Toasty.info(context, context.getString(R.string.genericError));
Toasty.error(context, context.getString(R.string.genericError));
}
@ -216,10 +207,8 @@ public class RepositoryActions {
public static void unWatchRepository(final Context context) {
final TinyDB tinyDb = new TinyDB(context);
final String instanceUrl = tinyDb.getString("instanceUrl");
final String loginUid = tinyDb.getString("loginUid");
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
final TinyDB tinyDb = TinyDB.getInstance(context);
String repoFullName = tinyDb.getString("repoFullName");
String[] parts = repoFullName.split("/");
final String repoOwner = parts[0];
@ -228,9 +217,8 @@ public class RepositoryActions {
Call<JsonElement> call;
call = RetrofitClient
.getInstance(instanceUrl, context)
.getApiInterface()
.unWatchRepository(Authorization.returnAuthentication(context, loginUid, instanceToken), repoOwner, repoName);
.getApiInterface(context)
.unWatchRepository(Authorization.get(context), repoOwner, repoName);
call.enqueue(new Callback<JsonElement>() {
@ -240,7 +228,7 @@ public class RepositoryActions {
if(response.code() == 204) {
tinyDb.putBoolean("repoCreated", true);
Toasty.info(context, context.getString(R.string.unWatchRepositorySuccess));
Toasty.success(context, context.getString(R.string.unWatchRepositorySuccess));
}
else if(response.code() == 401) {
@ -253,17 +241,17 @@ public class RepositoryActions {
}
else if(response.code() == 403) {
Toasty.info(context, context.getString(R.string.authorizeError));
Toasty.error(context, context.getString(R.string.authorizeError));
}
else if(response.code() == 404) {
Toasty.info(context, context.getString(R.string.apiNotFound));
Toasty.warning(context, context.getString(R.string.apiNotFound));
}
else {
Toasty.info(context, context.getString(R.string.genericError));
Toasty.error(context, context.getString(R.string.genericError));
}

View File

@ -0,0 +1,144 @@
package org.mian.gitnex.actions;
import android.content.Context;
import androidx.annotation.NonNull;
import com.google.gson.JsonElement;
import org.mian.gitnex.R;
import org.mian.gitnex.activities.AddNewTeamMemberActivity;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.helpers.AlertDialogs;
import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.helpers.TinyDB;
import org.mian.gitnex.helpers.Toasty;
import retrofit2.Call;
import retrofit2.Callback;
/**
* Author M M Arif
*/
public class TeamActions {
public static void removeTeamMember(final Context context, String userName, int teamId) {
final TinyDB tinyDb = TinyDB.getInstance(context);
Call<JsonElement> call;
call = RetrofitClient
.getApiInterface(context)
.removeTeamMember(Authorization.get(context), teamId, userName);
call.enqueue(new Callback<JsonElement>() {
@Override
public void onResponse(@NonNull Call<JsonElement> call, @NonNull retrofit2.Response<JsonElement> response) {
if(response.isSuccessful()) {
if(response.code() == 204) {
tinyDb.putBoolean("teamActionFlag", true);
Toasty.success(context, context.getString(R.string.memberRemovedMessage));
((AddNewTeamMemberActivity)context).finish();
}
}
else if(response.code() == 401) {
AlertDialogs.authorizationTokenRevokedDialog(context, context.getResources().getString(R.string.alertDialogTokenRevokedTitle),
context.getResources().getString(R.string.alertDialogTokenRevokedMessage),
context.getResources().getString(R.string.alertDialogTokenRevokedCopyNegativeButton),
context.getResources().getString(R.string.alertDialogTokenRevokedCopyPositiveButton));
}
else if(response.code() == 403) {
Toasty.error(context, context.getString(R.string.authorizeError));
}
else if(response.code() == 404) {
Toasty.warning(context, context.getString(R.string.apiNotFound));
}
else {
Toasty.error(context, context.getString(R.string.genericError));
}
}
@Override
public void onFailure(@NonNull Call<JsonElement> call, @NonNull Throwable t) {
Toasty.error(context, context.getResources().getString(R.string.genericServerResponseError));
}
});
}
public static void addTeamMember(final Context context, String userName, int teamId) {
final TinyDB tinyDb = TinyDB.getInstance(context);
Call<JsonElement> call = RetrofitClient
.getApiInterface(context)
.addTeamMember(Authorization.get(context), teamId, userName);
call.enqueue(new Callback<JsonElement>() {
@Override
public void onResponse(@NonNull Call<JsonElement> call, @NonNull retrofit2.Response<JsonElement> response) {
if(response.isSuccessful()) {
if(response.code() == 204) {
tinyDb.putBoolean("teamActionFlag", true);
Toasty.success(context, context.getString(R.string.memberAddedMessage));
((AddNewTeamMemberActivity)context).finish();
}
}
else if(response.code() == 401) {
AlertDialogs.authorizationTokenRevokedDialog(context, context.getResources().getString(R.string.alertDialogTokenRevokedTitle),
context.getResources().getString(R.string.alertDialogTokenRevokedMessage),
context.getResources().getString(R.string.alertDialogTokenRevokedCopyNegativeButton),
context.getResources().getString(R.string.alertDialogTokenRevokedCopyPositiveButton));
}
else if(response.code() == 403) {
Toasty.error(context, context.getString(R.string.authorizeError));
}
else if(response.code() == 404) {
Toasty.warning(context, context.getString(R.string.apiNotFound));
}
else {
Toasty.error(context, context.getString(R.string.genericError));
}
}
@Override
public void onFailure(@NonNull Call<JsonElement> call, @NonNull Throwable t) {
Toasty.error(context, context.getResources().getString(R.string.genericServerResponseError));
}
});
}
}

View File

@ -1,29 +1,28 @@
package org.mian.gitnex.activities;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import org.gitnex.tea4j.models.UserInfo;
import org.gitnex.tea4j.models.UserSearch;
import org.mian.gitnex.adapters.UserSearchAdapter;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.databinding.ActivityAddCollaboratorToRepositoryBinding;
import org.mian.gitnex.helpers.Authorization;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import org.mian.gitnex.R;
import org.mian.gitnex.adapters.UserSearchAdapter;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.models.UserSearch;
import org.mian.gitnex.models.UserInfo;
import org.mian.gitnex.util.TinyDB;
import java.util.List;
/**
* Author M M Arif
@ -32,68 +31,72 @@ import java.util.List;
public class AddCollaboratorToRepositoryActivity extends BaseActivity {
private View.OnClickListener onClickListener;
final Context ctx = this;
private TextView addCollaboratorSearch;
private TextView noData;
private ProgressBar mProgressBar;
private RecyclerView mRecyclerView;
@Override
protected int getLayoutResourceId(){
return R.layout.activity_add_collaborator_to_repository;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TinyDB tinyDb = new TinyDB(getApplicationContext());
final String instanceUrl = tinyDb.getString("instanceUrl");
final String loginUid = tinyDb.getString("loginUid");
String repoFullName = tinyDb.getString("repoFullName");
String[] parts = repoFullName.split("/");
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
ActivityAddCollaboratorToRepositoryBinding activityAddCollaboratorToRepositoryBinding = ActivityAddCollaboratorToRepositoryBinding.inflate(getLayoutInflater());
setContentView(activityAddCollaboratorToRepositoryBinding.getRoot());
ImageView closeActivity = findViewById(R.id.close);
addCollaboratorSearch = findViewById(R.id.addCollaboratorSearch);
mRecyclerView = findViewById(R.id.recyclerViewUserSearch);
mProgressBar = findViewById(R.id.progress_bar);
noData = findViewById(R.id.noData);
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
ImageView closeActivity = activityAddCollaboratorToRepositoryBinding.close;
addCollaboratorSearch = activityAddCollaboratorToRepositoryBinding.addCollaboratorSearch;
mRecyclerView = activityAddCollaboratorToRepositoryBinding.recyclerViewUserSearch;
mProgressBar = activityAddCollaboratorToRepositoryBinding.progressBar;
noData = activityAddCollaboratorToRepositoryBinding.noData;
addCollaboratorSearch.requestFocus();
assert imm != null;
imm.showSoftInput(addCollaboratorSearch, InputMethodManager.SHOW_IMPLICIT);
initCloseListener();
closeActivity.setOnClickListener(onClickListener);
addCollaboratorSearch.setOnEditorActionListener(new TextView.OnEditorActionListener() {
@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if (actionId == EditorInfo.IME_ACTION_SEND) {
if(!addCollaboratorSearch.getText().toString().equals("")) {
loadUserSearchList(instanceUrl, instanceToken, addCollaboratorSearch.getText().toString(), getApplicationContext(), loginUid);
}
addCollaboratorSearch.setOnEditorActionListener((v, actionId, event) -> {
if (actionId == EditorInfo.IME_ACTION_SEND) {
if(!addCollaboratorSearch.getText().toString().equals("")) {
mProgressBar.setVisibility(View.VISIBLE);
loadUserSearchList(addCollaboratorSearch.getText().toString());
}
return false;
}
return false;
});
}
public void loadUserSearchList(String instanceUrl, String token, String searchKeyword, final Context context, String loginUid) {
public void loadUserSearchList(String searchKeyword) {
Call<UserSearch> call = RetrofitClient
.getInstance(instanceUrl, getApplicationContext())
.getApiInterface()
.getUserBySearch(Authorization.returnAuthentication(getApplicationContext(), loginUid, token), searchKeyword, 10);
.getApiInterface(appCtx)
.getUserBySearch(Authorization.get(ctx), searchKeyword, 10, 1);
call.enqueue(new Callback<UserSearch>() {
@Override
public void onResponse(@NonNull Call<UserSearch> call, @NonNull Response<UserSearch> response) {
if (response.isSuccessful()) {
mProgressBar.setVisibility(View.GONE);
if (response.code() == 200) {
assert response.body() != null;
getUsersList(response.body().getData(), context);
} else {
getUsersList(response.body().getData(), ctx);
}
else {
Log.i("onResponse", String.valueOf(response.code()));
}
@ -112,7 +115,7 @@ public class AddCollaboratorToRepositoryActivity extends BaseActivity {
UserSearchAdapter adapter = new UserSearchAdapter(dataList, context);
mRecyclerView.setHasFixedSize(true);
mRecyclerView.setLayoutManager(new LinearLayoutManager(getApplicationContext()));
mRecyclerView.setLayoutManager(new LinearLayoutManager(ctx));
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(mRecyclerView.getContext(),
DividerItemDecoration.VERTICAL);
mRecyclerView.addItemDecoration(dividerItemDecoration);
@ -120,25 +123,20 @@ public class AddCollaboratorToRepositoryActivity extends BaseActivity {
mProgressBar.setVisibility(View.VISIBLE);
if(adapter.getItemCount() > 0) {
mRecyclerView.setAdapter(adapter);
noData.setVisibility(View.GONE);
mProgressBar.setVisibility(View.GONE);
}
else {
noData.setVisibility(View.VISIBLE);
mProgressBar.setVisibility(View.GONE);
}
mProgressBar.setVisibility(View.GONE);
}
private void initCloseListener() {
onClickListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
finish();
}
};
onClickListener = view -> finish();
}
}

View File

@ -0,0 +1,251 @@
package org.mian.gitnex.activities;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ArrayAdapter;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import org.gitnex.tea4j.models.GiteaVersion;
import org.gitnex.tea4j.models.UserInfo;
import org.mian.gitnex.R;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.database.api.BaseApi;
import org.mian.gitnex.database.api.UserAccountsApi;
import org.mian.gitnex.databinding.ActivityAddNewAccountBinding;
import org.mian.gitnex.helpers.AppUtil;
import org.mian.gitnex.helpers.PathsHelper;
import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.helpers.UrlHelper;
import org.mian.gitnex.helpers.Version;
import java.net.URI;
import io.mikael.urlbuilder.UrlBuilder;
import retrofit2.Call;
import retrofit2.Callback;
/**
* Author M M Arif
*/
public class AddNewAccountActivity extends BaseActivity {
private View.OnClickListener onClickListener;
private ActivityAddNewAccountBinding viewBinding;
private enum Protocol {HTTPS, HTTP}
private String spinnerSelectedValue;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
viewBinding = ActivityAddNewAccountBinding.inflate(getLayoutInflater());
setContentView(viewBinding.getRoot());
getWindow().getDecorView().setBackground(new ColorDrawable(Color.TRANSPARENT));
initCloseListener();
viewBinding.close.setOnClickListener(onClickListener);
viewBinding.instanceUrl.setText(getIntent().getStringExtra("instanceUrl"));
ArrayAdapter<Protocol> adapterProtocols = new ArrayAdapter<>(ctx, R.layout.list_spinner_items, Protocol.values());
viewBinding.protocolSpinner.setAdapter(adapterProtocols);
viewBinding.protocolSpinner.setOnItemClickListener((parent, view1, position, id) -> spinnerSelectedValue = String.valueOf(parent.getItemAtPosition(position)));
viewBinding.addNewAccount.setOnClickListener(login -> {
boolean connToInternet = AppUtil.hasNetworkConnection(appCtx);
if(!connToInternet) {
Toasty.error(ctx, getResources().getString(R.string.checkNetConnection));
}
else {
processLogin();
}
});
}
private void processLogin() {
try {
String instanceUrlET = String.valueOf(viewBinding.instanceUrl.getText());
String loginToken = String.valueOf(viewBinding.loginToken.getText());
String protocol = spinnerSelectedValue;
if(protocol == null) {
Toasty.error(ctx, getResources().getString(R.string.protocolEmptyError));
return;
}
if(instanceUrlET.equals("")) {
Toasty.error(ctx, getResources().getString(R.string.emptyFieldURL));
return;
}
if(loginToken.equals("")) {
Toasty.error(ctx, getResources().getString(R.string.loginTokenError));
return;
}
URI rawInstanceUrl = UrlBuilder.fromString(UrlHelper.fixScheme(instanceUrlET, "http")).toUri();
URI instanceUrl = UrlBuilder.fromUri(rawInstanceUrl).withScheme(protocol.toLowerCase()).withPath(PathsHelper.join(rawInstanceUrl.getPath(), "/api/v1/"))
.toUri();
versionCheck(instanceUrl.toString(), loginToken);
}
catch(Exception e) {
Log.e("onFailure-login", e.toString());
Toasty.error(ctx, getResources().getString(R.string.malformedUrl));
}
}
private void versionCheck(final String instanceUrl, final String loginToken) {
Call<GiteaVersion> callVersion;
callVersion = RetrofitClient.getApiInterface(ctx, instanceUrl).getGiteaVersionWithToken("token " + loginToken);
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;
if(!Version.valid(version.getVersion())) {
Toasty.error(ctx, getResources().getString(R.string.versionUnknown));
return;
}
tinyDB.putString("giteaVersion", version.getVersion());
Version giteaVersion = new Version(version.getVersion());
if(giteaVersion.less(getString(R.string.versionLow))) {
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(ctx).setTitle(getString(R.string.versionAlertDialogHeader))
.setMessage(getResources().getString(R.string.versionUnsupportedOld, version.getVersion())).setIcon(R.drawable.ic_warning)
.setCancelable(true);
alertDialogBuilder.setNeutralButton(getString(R.string.cancelButton), (dialog, which) -> {
dialog.dismiss();
});
alertDialogBuilder.setPositiveButton(getString(R.string.textContinue), (dialog, which) -> {
dialog.dismiss();
login(instanceUrl, loginToken);
});
alertDialogBuilder.create().show();
}
else if(giteaVersion.lessOrEqual(getString(R.string.versionHigh))) {
login(instanceUrl, loginToken);
}
else {
Toasty.warning(ctx, getResources().getString(R.string.versionUnsupportedNew));
login(instanceUrl, loginToken);
}
}
else if(responseVersion.code() == 403) {
login(instanceUrl, loginToken);
}
}
private void login(String instanceUrl, String loginToken) {
setupNewAccountWithToken(instanceUrl, loginToken);
}
@Override
public void onFailure(@NonNull Call<GiteaVersion> callVersion, @NonNull Throwable t) {
Log.e("onFailure-versionCheck", t.toString());
Toasty.error(ctx, getResources().getString(R.string.errorOnLogin));
}
});
}
private void setupNewAccountWithToken(String instanceUrl, final String loginToken) {
Call<UserInfo> call = RetrofitClient.getApiInterface(ctx, instanceUrl).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();
switch(response.code()) {
case 200:
assert userDetails != null;
// insert new account to db if does not exist
String accountName = userDetails.getUsername() + "@" + instanceUrl;
UserAccountsApi userAccountsApi = BaseApi.getInstance(ctx, UserAccountsApi.class);
boolean userAccountExists = userAccountsApi.userAccountExists(accountName);
if(!userAccountExists) {
userAccountsApi.createNewAccount(accountName, instanceUrl, userDetails.getUsername(), loginToken, "");
Toasty.success(ctx, getResources().getString(R.string.accountAddedMessage));
finish();
}
else {
Toasty.warning(ctx, getResources().getString(R.string.accountAlreadyExistsError));
}
break;
case 401:
Toasty.error(ctx, getResources().getString(R.string.unauthorizedApiError));
break;
default:
Toasty.error(ctx, getResources().getString(R.string.genericApiStatusError) + response.code());
}
}
@Override
public void onFailure(@NonNull Call<UserInfo> call, @NonNull Throwable t) {
Log.e("onFailure", t.toString());
Toasty.error(ctx, getResources().getString(R.string.genericError));
}
});
}
private void initCloseListener() {
onClickListener = view -> finish();
}
}

View File

@ -0,0 +1,154 @@
package org.mian.gitnex.activities;
import android.content.Context;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import org.gitnex.tea4j.models.UserInfo;
import org.gitnex.tea4j.models.UserSearch;
import org.mian.gitnex.adapters.UserSearchForTeamMemberAdapter;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.databinding.ActivityAddNewTeamMemberBinding;
import org.mian.gitnex.helpers.Authorization;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
/**
* Author M M Arif
*/
public class AddNewTeamMemberActivity extends BaseActivity {
private View.OnClickListener onClickListener;
private TextView addNewTeamMember;
private TextView noData;
private ProgressBar mProgressBar;
private RecyclerView mRecyclerView;
private List<UserInfo> dataList;
private UserSearchForTeamMemberAdapter adapter;
private String teamId;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityAddNewTeamMemberBinding activityAddNewTeamMemberBinding = ActivityAddNewTeamMemberBinding.inflate(getLayoutInflater());
setContentView(activityAddNewTeamMemberBinding.getRoot());
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
ImageView closeActivity = activityAddNewTeamMemberBinding.close;
addNewTeamMember = activityAddNewTeamMemberBinding.addNewTeamMember;
mRecyclerView = activityAddNewTeamMemberBinding.recyclerViewUserSearch;
mProgressBar = activityAddNewTeamMemberBinding.progressBar;
noData = activityAddNewTeamMemberBinding.noData;
addNewTeamMember.requestFocus();
assert imm != null;
imm.showSoftInput(addNewTeamMember, InputMethodManager.SHOW_IMPLICIT);
initCloseListener();
closeActivity.setOnClickListener(onClickListener);
if(getIntent().getStringExtra("teamId") != null && !Objects.requireNonNull(getIntent().getStringExtra("teamId")).equals("")) {
teamId = getIntent().getStringExtra("teamId");
}
else {
teamId = "0";
}
mRecyclerView.setHasFixedSize(true);
mRecyclerView.setLayoutManager(new LinearLayoutManager(ctx));
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(mRecyclerView.getContext(), DividerItemDecoration.VERTICAL);
mRecyclerView.addItemDecoration(dividerItemDecoration);
dataList = new ArrayList<>();
addNewTeamMember.addTextChangedListener(new TextWatcher() {
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if(!addNewTeamMember.getText().toString().equals("") && addNewTeamMember.getText().toString().length() > 1) {
adapter = new UserSearchForTeamMemberAdapter(dataList, ctx, Integer.parseInt(teamId));
loadUserSearchList(addNewTeamMember.getText().toString(), teamId);
}
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void afterTextChanged(Editable s) {
}
});
}
public void loadUserSearchList(String searchKeyword, String teamId) {
Call<UserSearch> call = RetrofitClient.getApiInterface(ctx).getUserBySearch(Authorization.get(ctx), searchKeyword, 10, 1);
mProgressBar.setVisibility(View.VISIBLE);
call.enqueue(new Callback<UserSearch>() {
@Override
public void onResponse(@NonNull Call<UserSearch> call, @NonNull Response<UserSearch> response) {
if(response.isSuccessful()) {
assert response.body() != null;
if(response.body().getData().size() > 0) {
dataList.clear();
dataList.addAll(response.body().getData());
mRecyclerView.setAdapter(adapter);
noData.setVisibility(View.GONE);
}
else {
noData.setVisibility(View.VISIBLE);
}
mProgressBar.setVisibility(View.GONE);
}
}
@Override
public void onFailure(@NonNull Call<UserSearch> call, @NonNull Throwable t) {
Log.e("onFailure", t.toString());
}
});
}
private void initCloseListener() {
onClickListener = view -> finish();
}
}

View File

@ -1,292 +0,0 @@
package org.mian.gitnex.activities;
import androidx.annotation.NonNull;
import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.util.Log;
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.MultiSelectDialog;
import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.models.Collaborators;
import org.mian.gitnex.models.Issues;
import org.mian.gitnex.models.MultiSelectModel;
import org.mian.gitnex.models.UpdateIssueAssignees;
import org.mian.gitnex.util.TinyDB;
import java.util.ArrayList;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
/**
* Author M M Arif
*/
public class AddRemoveAssigneesActivity extends BaseActivity {
private ArrayList<MultiSelectModel> listOfCollaborators = new ArrayList<>();
private ArrayList<Integer> issueAssigneesIds = new ArrayList<>();
private Boolean assigneesFlag = false;
private MultiSelectDialog multiSelectDialogAssignees;
final Context ctx = this;
@Override
protected int getLayoutResourceId(){
return R.layout.activity_add_remove_assignees;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().getDecorView().setBackground(new ColorDrawable(Color.TRANSPARENT));
TinyDB tinyDb = new TinyDB(getApplicationContext());
final String instanceUrl = tinyDb.getString("instanceUrl");
final String loginUid = tinyDb.getString("loginUid");
String repoFullName = tinyDb.getString("repoFullName");
String[] parts = repoFullName.split("/");
final String repoOwner = parts[0];
final String repoName = parts[1];
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
final int issueIndex = Integer.parseInt(tinyDb.getString("issueNumber"));
getAssignees(instanceUrl, instanceToken, repoOwner, repoName, issueIndex, loginUid);
}
private void getAssignees(final String instanceUrl, final String instanceToken, final String repoOwner, final String repoName, final int issueIndex, final String loginUid) {
final TinyDB tinyDb = new TinyDB(getApplicationContext());
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 final Call<List<Collaborators>> call, @NonNull final retrofit2.Response<List<Collaborators>> response) {
if(response.isSuccessful()) {
if(response.code() == 200) {
final List<Collaborators> collaboratorsList_ = response.body();
assert collaboratorsList_ != null;
if(collaboratorsList_.size() > 0) {
for (int i = 0; i < collaboratorsList_.size(); i++) {
listOfCollaborators.add(new MultiSelectModel(collaboratorsList_.get(i).getId(), collaboratorsList_.get(i).getUsername().trim()));
}
}
// get current issue assignees
Call<Issues> callSingleIssueAssignees = RetrofitClient
.getInstance(instanceUrl, getApplicationContext())
.getApiInterface()
.getIssueByIndex(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName, issueIndex);
callSingleIssueAssignees.enqueue(new Callback<Issues>() {
@Override
public void onResponse(@NonNull Call<Issues> call, @NonNull retrofit2.Response<Issues> response) {
if(response.code() == 200) {
Issues issueAssigneesList = response.body();
assert issueAssigneesList != null;
if (issueAssigneesList.getAssignees() != null) {
if (issueAssigneesList.getAssignees().size() > 0) {
for (int i = 0; i < issueAssigneesList.getAssignees().size(); i++) {
issueAssigneesIds.add(issueAssigneesList.getAssignees().get(i).getId());
if(issueAssigneesList.getAssignees().get(i).getUsername().equals(loginUid)) {
listOfCollaborators.add(new MultiSelectModel(issueAssigneesList.getAssignees().get(i).getId(), issueAssigneesList.getAssignees().get(i).getUsername().trim()));
}
}
assigneesFlag = true;
}
}
else {
listOfCollaborators.add(new MultiSelectModel(tinyDb.getInt("userId"), loginUid));
}
if(assigneesFlag) {
multiSelectDialogAssignees = new MultiSelectDialog()
.title(getResources().getString(R.string.newIssueSelectAssigneesListTitle))
.titleSize(25)
.positiveText(getResources().getString(R.string.saveButton))
.negativeText(getResources().getString(R.string.cancelButton))
.setMinSelectionLimit(0)
.preSelectIDsList(issueAssigneesIds)
.setMaxSelectionLimit(listOfCollaborators.size())
.multiSelectList(listOfCollaborators)
.onSubmit(new MultiSelectDialog.SubmitCallbackListener() {
@Override
public void onSelected(ArrayList<Integer> selectedIds, ArrayList<String> selectedNames, String dataString) {
Log.i("selectedNames", String.valueOf(selectedNames));
updateIssueAssignees(instanceUrl, Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName, loginUid, issueIndex, selectedNames);
tinyDb.putBoolean("singleIssueUpdate", true);
CloseActivity();
}
@Override
public void onCancel() {
CloseActivity();
}
});
}
else {
multiSelectDialogAssignees = new MultiSelectDialog()
.title(getResources().getString(R.string.newIssueSelectAssigneesListTitle))
.titleSize(25)
.positiveText(getResources().getString(R.string.saveButton))
.negativeText(getResources().getString(R.string.cancelButton))
.setMinSelectionLimit(0)
.setMaxSelectionLimit(listOfCollaborators.size())
.multiSelectList(listOfCollaborators)
.onSubmit(new MultiSelectDialog.SubmitCallbackListener() {
@Override
public void onSelected(ArrayList<Integer> selectedIds, ArrayList<String> selectedNames, String dataString) {
updateIssueAssignees(instanceUrl, Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName, loginUid, issueIndex, selectedNames);
tinyDb.putBoolean("singleIssueUpdate", true);
CloseActivity();
}
@Override
public void onCancel() {
CloseActivity();
}
});
}
multiSelectDialogAssignees.show(getSupportFragmentManager(), "issueMultiSelectDialog");
}
}
@Override
public void onFailure(@NonNull Call<Issues> call, @NonNull Throwable t) {
Log.e("onFailure", t.toString());
}
});
// get current issue assignees
}
else if(response.code() == 401) {
AlertDialogs.authorizationTokenRevokedDialog(ctx, getResources().getString(R.string.alertDialogTokenRevokedTitle),
getResources().getString(R.string.alertDialogTokenRevokedMessage),
getResources().getString(R.string.alertDialogTokenRevokedCopyNegativeButton),
getResources().getString(R.string.alertDialogTokenRevokedCopyPositiveButton));
}
else if(response.code() == 403) {
Toasty.info(ctx, ctx.getString(R.string.authorizeError));
}
else if(response.code() == 404) {
Toasty.info(ctx, ctx.getString(R.string.apiNotFound));
}
else {
Toasty.info(getApplicationContext(), getString(R.string.genericError));
}
}
}
@Override
public void onFailure(@NonNull Call<List<Collaborators>> call, @NonNull Throwable t) {
Log.e("onFailure", t.toString());
}
});
}
private void CloseActivity() {
this.finish();
}
private void updateIssueAssignees(final String instanceUrl, final String instanceToken, String repoOwner, String repoName, String loginUid, int issueIndex, List<String> issueAssigneesList) {
UpdateIssueAssignees updateAssigneeJson = new UpdateIssueAssignees(issueAssigneesList);
Call<JsonElement> call3;
call3 = RetrofitClient
.getInstance(instanceUrl, getApplicationContext())
.getApiInterface()
.patchIssueAssignees(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName, issueIndex, updateAssigneeJson);
call3.enqueue(new Callback<JsonElement>() {
@Override
public void onResponse(@NonNull Call<JsonElement> call, @NonNull retrofit2.Response<JsonElement> response2) {
if(response2.code() == 201) {
Toasty.info(ctx, ctx.getString(R.string.assigneesUpdated));
}
else if(response2.code() == 401) {
AlertDialogs.authorizationTokenRevokedDialog(ctx, getResources().getString(R.string.alertDialogTokenRevokedTitle),
getResources().getString(R.string.alertDialogTokenRevokedMessage),
getResources().getString(R.string.alertDialogTokenRevokedCopyNegativeButton),
getResources().getString(R.string.alertDialogTokenRevokedCopyPositiveButton));
}
else if(response2.code() == 403) {
Toasty.info(ctx, ctx.getString(R.string.authorizeError));
}
else if(response2.code() == 404) {
Toasty.info(ctx, ctx.getString(R.string.apiNotFound));
}
else {
Toasty.info(getApplicationContext(), getString(R.string.genericError));
}
}
@Override
public void onFailure(@NonNull Call<JsonElement> call, @NonNull Throwable t) {
Log.e("onFailure", t.toString());
}
});
}
}

View File

@ -1,305 +0,0 @@
package org.mian.gitnex.activities;
import androidx.annotation.NonNull;
import retrofit2.Call;
import retrofit2.Callback;
import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.util.Log;
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.MultiSelectDialog;
import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.models.Labels;
import org.mian.gitnex.models.MultiSelectModel;
import org.mian.gitnex.util.TinyDB;
import java.util.ArrayList;
import java.util.List;
/**
* Author M M Arif
*/
public class AddRemoveLabelsActivity extends BaseActivity {
private ArrayList<MultiSelectModel> listOfLabels = new ArrayList<>();
private ArrayList<Integer> issueLabelIds = new ArrayList<>();
private Boolean labelsFlag = false;
private MultiSelectDialog multiSelectDialogLabels;
final Context ctx = this;
@Override
protected int getLayoutResourceId(){
return R.layout.activity_add_remove_labels;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().getDecorView().setBackground(new ColorDrawable(Color.TRANSPARENT));
TinyDB tinyDb = new TinyDB(getApplicationContext());
final String instanceUrl = tinyDb.getString("instanceUrl");
final String loginUid = tinyDb.getString("loginUid");
String repoFullName = tinyDb.getString("repoFullName");
String[] parts = repoFullName.split("/");
final String repoOwner = parts[0];
final String repoName = parts[1];
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
final int issueIndex = Integer.parseInt(tinyDb.getString("issueNumber"));
getLabels(instanceUrl, instanceToken, repoOwner, repoName, issueIndex, loginUid);
}
private void getLabels(final String instanceUrl, final String instanceToken, final String repoOwner, final String repoName, final int issueIndex, final String loginUid) {
final TinyDB tinyDb = new TinyDB(getApplicationContext());
Call<List<Labels>> call = RetrofitClient
.getInstance(instanceUrl, getApplicationContext())
.getApiInterface()
.getlabels(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName);
call.enqueue(new Callback<List<Labels>>() {
@Override
public void onResponse(@NonNull Call<List<Labels>> call, @NonNull retrofit2.Response<List<Labels>> response) {
if(response.isSuccessful()) {
if(response.code() == 200) {
List<Labels> labelsList_ = response.body();
assert labelsList_ != null;
if(labelsList_.size() > 0) {
for (int i = 0; i < labelsList_.size(); i++) {
listOfLabels.add(new MultiSelectModel(labelsList_.get(i).getId(), labelsList_.get(i).getName().trim()));
}
}
// get current issue labels
Call<List<Labels>> callSingleIssueLabels = RetrofitClient
.getInstance(instanceUrl, getApplicationContext())
.getApiInterface()
.getIssueLabels(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName, issueIndex);
callSingleIssueLabels.enqueue(new Callback<List<Labels>>() {
@Override
public void onResponse(@NonNull Call<List<Labels>> call, @NonNull retrofit2.Response<List<Labels>> response) {
if(response.code() == 200) {
List<Labels> issueLabelsList = response.body();
assert issueLabelsList != null;
if(issueLabelsList.size() > 0) {
for (int i = 0; i < issueLabelsList.size(); i++) {
issueLabelIds.add(issueLabelsList.get(i).getId());
}
labelsFlag = true;
}
if(labelsFlag) {
multiSelectDialogLabels = new MultiSelectDialog()
.title(getResources().getString(R.string.newIssueSelectLabelsListTitle))
.titleSize(25)
.positiveText(getResources().getString(R.string.saveButton))
.negativeText(getResources().getString(R.string.cancelButton))
.setMinSelectionLimit(0)
.preSelectIDsList(issueLabelIds)
.setMaxSelectionLimit(listOfLabels.size())
.multiSelectList(listOfLabels)
.onSubmit(new MultiSelectDialog.SubmitCallbackListener() {
@Override
public void onSelected(ArrayList<Integer> selectedIds, ArrayList<String> selectedNames, String dataString) {
String labelIds = selectedIds.toString();
int[] integers;
if (selectedIds.size() > 0) {
String[] items = labelIds.replaceAll("\\[", "").replaceAll("\\]", "").replaceAll("\\s", "").split(",");
integers = new int[items.length];
for (int i = 0; i < integers.length; i++) {
integers[i] = Integer.parseInt(items[i]);
}
}
else {
integers = new int[0];
}
updateIssueLabels(instanceUrl, Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName, issueIndex, integers, loginUid);
tinyDb.putBoolean("singleIssueUpdate", true);
CloseActivity();
}
@Override
public void onCancel() {
CloseActivity();
}
});
}
else {
multiSelectDialogLabels = new MultiSelectDialog()
.title(getResources().getString(R.string.newIssueSelectLabelsListTitle))
.titleSize(25)
.positiveText(getResources().getString(R.string.saveButton))
.negativeText(getResources().getString(R.string.cancelButton))
.setMinSelectionLimit(0)
.setMaxSelectionLimit(listOfLabels.size())
.multiSelectList(listOfLabels)
.onSubmit(new MultiSelectDialog.SubmitCallbackListener() {
@Override
public void onSelected(ArrayList<Integer> selectedIds, ArrayList<String> selectedNames, String dataString) {
String labelIds = selectedIds.toString();
int[] integers;
if (selectedIds.size() > 0) {
String[] items = labelIds.replaceAll("\\[", "").replaceAll("\\]", "").replaceAll("\\s", "").split(",");
integers = new int[items.length];
for (int i = 0; i < integers.length; i++) {
integers[i] = Integer.parseInt(items[i]);
}
}
else {
integers = new int[0];
}
updateIssueLabels(instanceUrl, Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName, issueIndex, integers, loginUid);
tinyDb.putBoolean("singleIssueUpdate", true);
CloseActivity();
}
@Override
public void onCancel() {
CloseActivity();
}
});
}
multiSelectDialogLabels.show(getSupportFragmentManager(), "issueMultiSelectDialog");
}
}
@Override
public void onFailure(@NonNull Call<List<Labels>> call, @NonNull Throwable t) {
Log.e("onFailure", t.toString());
}
});
// get current issue labels
}
else if(response.code() == 401) {
AlertDialogs.authorizationTokenRevokedDialog(ctx, getResources().getString(R.string.alertDialogTokenRevokedTitle),
getResources().getString(R.string.alertDialogTokenRevokedMessage),
getResources().getString(R.string.alertDialogTokenRevokedCopyNegativeButton),
getResources().getString(R.string.alertDialogTokenRevokedCopyPositiveButton));
}
else if(response.code() == 403) {
Toasty.info(ctx, ctx.getString(R.string.authorizeError));
}
else if(response.code() == 404) {
Toasty.info(ctx, ctx.getString(R.string.apiNotFound));
}
else {
Toasty.info(getApplicationContext(), getString(R.string.genericError));
}
}
}
@Override
public void onFailure(@NonNull Call<List<Labels>> call, @NonNull Throwable t) {
Log.e("onFailure", t.toString());
}
});
}
private void updateIssueLabels(final String instanceUrl, final String instanceToken, String repoOwner, String repoName, int issueIndex, int[] issueLabels, String loginUid) {
Labels patchIssueLabels = new Labels(issueLabels);
Call<JsonElement> call = RetrofitClient
.getInstance(instanceUrl, getApplicationContext())
.getApiInterface()
.updateIssueLabels(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName, issueIndex, patchIssueLabels);
call.enqueue(new Callback<JsonElement>() {
@Override
public void onResponse(@NonNull Call<JsonElement> call, @NonNull retrofit2.Response<JsonElement> response) {
if(response.code() == 200) {
Toasty.info(ctx, ctx.getString(R.string.labelsUpdated));
}
else if(response.code() == 401) {
AlertDialogs.authorizationTokenRevokedDialog(ctx, getResources().getString(R.string.alertDialogTokenRevokedTitle),
getResources().getString(R.string.alertDialogTokenRevokedMessage),
getResources().getString(R.string.alertDialogTokenRevokedCopyNegativeButton),
getResources().getString(R.string.alertDialogTokenRevokedCopyPositiveButton));
}
else if(response.code() == 403) {
Toasty.info(ctx, ctx.getString(R.string.authorizeError));
}
else if(response.code() == 404) {
Toasty.info(ctx, ctx.getString(R.string.apiNotFound));
}
else {
Toasty.info(getApplicationContext(), getString(R.string.genericError));
}
}
@Override
public void onFailure(@NonNull Call<JsonElement> call, @NonNull Throwable t) {
Log.e("onFailure", t.toString());
}
});
}
private void CloseActivity() {
this.finish();
}
}

View File

@ -0,0 +1,89 @@
package org.mian.gitnex.activities;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.view.View;
import androidx.appcompat.widget.Toolbar;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import org.mian.gitnex.adapters.AdminCronTasksAdapter;
import org.mian.gitnex.databinding.ActivityAdminCronTasksBinding;
import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.viewmodels.AdminCronTasksViewModel;
/**
* Author M M Arif
*/
public class AdminCronTasksActivity extends BaseActivity {
private View.OnClickListener onClickListener;
private AdminCronTasksAdapter adapter;
private ActivityAdminCronTasksBinding activityAdminCronTasksBinding;
public static final int PAGE = 1;
public static final int LIMIT = 50;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
activityAdminCronTasksBinding = ActivityAdminCronTasksBinding.inflate(getLayoutInflater());
setContentView(activityAdminCronTasksBinding.getRoot());
initCloseListener();
activityAdminCronTasksBinding.close.setOnClickListener(onClickListener);
Toolbar toolbar = activityAdminCronTasksBinding.toolbar;
setSupportActionBar(toolbar);
activityAdminCronTasksBinding.recyclerView.setHasFixedSize(true);
activityAdminCronTasksBinding.recyclerView.setLayoutManager(new LinearLayoutManager(ctx));
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(activityAdminCronTasksBinding.recyclerView.getContext(),
DividerItemDecoration.VERTICAL);
activityAdminCronTasksBinding.recyclerView.addItemDecoration(dividerItemDecoration);
activityAdminCronTasksBinding.pullToRefresh.setOnRefreshListener(() -> new Handler(Looper.getMainLooper()).postDelayed(() -> {
activityAdminCronTasksBinding.pullToRefresh.setRefreshing(false);
AdminCronTasksViewModel.loadCronTasksList(ctx, Authorization.get(ctx), PAGE, LIMIT);
}, 500));
fetchDataAsync(ctx, Authorization.get(ctx));
}
private void fetchDataAsync(Context ctx, String instanceToken) {
AdminCronTasksViewModel cronTasksViewModel = new ViewModelProvider(this).get(AdminCronTasksViewModel.class);
cronTasksViewModel.getCronTasksList(ctx, instanceToken, PAGE, LIMIT).observe(this, cronTasksListMain -> {
adapter = new AdminCronTasksAdapter(ctx, cronTasksListMain);
if(adapter.getItemCount() > 0) {
activityAdminCronTasksBinding.recyclerView.setVisibility(View.VISIBLE);
activityAdminCronTasksBinding.recyclerView.setAdapter(adapter);
activityAdminCronTasksBinding.noData.setVisibility(View.GONE);
}
else {
activityAdminCronTasksBinding.recyclerView.setVisibility(View.GONE);
activityAdminCronTasksBinding.noData.setVisibility(View.VISIBLE);
}
});
}
private void initCloseListener() {
onClickListener = view -> finish();
}
}

View File

@ -1,17 +1,10 @@
package org.mian.gitnex.activities;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.Toolbar;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProviders;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
@ -19,102 +12,91 @@ import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.appcompat.widget.SearchView;
import androidx.appcompat.widget.Toolbar;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import org.mian.gitnex.R;
import org.mian.gitnex.adapters.AdminGetUsersAdapter;
import org.mian.gitnex.fragments.AdminUsersBottomSheetFragment;
import org.mian.gitnex.databinding.ActivityAdminGetUsersBinding;
import org.mian.gitnex.fragments.BottomSheetAdminUsersFragment;
import org.mian.gitnex.helpers.AppUtil;
import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.models.UserInfo;
import org.mian.gitnex.util.AppUtil;
import org.mian.gitnex.util.TinyDB;
import org.mian.gitnex.viewmodels.AdminGetUsersViewModel;
import java.util.List;
import java.util.Objects;
/**
* Author M M Arif
*/
public class AdminGetUsersActivity extends BaseActivity implements AdminUsersBottomSheetFragment.BottomSheetListener {
public class AdminGetUsersActivity extends BaseActivity implements BottomSheetAdminUsersFragment.BottomSheetListener {
private View.OnClickListener onClickListener;
final Context ctx = this;
private AdminGetUsersAdapter adapter;
private RecyclerView mRecyclerView;
private TextView noDataUsers;
private Boolean searchFilter = false;
@Override
protected int getLayoutResourceId(){
return R.layout.activity_admin_get_users;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
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");
ActivityAdminGetUsersBinding activityAdminGetUsersBinding = ActivityAdminGetUsersBinding.inflate(getLayoutInflater());
setContentView(activityAdminGetUsersBinding.getRoot());
ImageView closeActivity = findViewById(R.id.close);
noDataUsers = findViewById(R.id.noDataUsers);
mRecyclerView = findViewById(R.id.recyclerView);
ImageView closeActivity = activityAdminGetUsersBinding.close;
noDataUsers = activityAdminGetUsersBinding.noDataUsers;
mRecyclerView = activityAdminGetUsersBinding.recyclerView;
final SwipeRefreshLayout swipeRefresh = findViewById(R.id.pullToRefresh);
final SwipeRefreshLayout swipeRefresh = activityAdminGetUsersBinding.pullToRefresh;
Toolbar toolbar = findViewById(R.id.toolbar);
Toolbar toolbar = activityAdminGetUsersBinding.toolbar;
setSupportActionBar(toolbar);
initCloseListener();
closeActivity.setOnClickListener(onClickListener);
mRecyclerView.setHasFixedSize(true);
mRecyclerView.setLayoutManager(new LinearLayoutManager(getApplicationContext()));
mRecyclerView.setLayoutManager(new LinearLayoutManager(ctx));
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(mRecyclerView.getContext(),
DividerItemDecoration.VERTICAL);
mRecyclerView.addItemDecoration(dividerItemDecoration);
swipeRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
swipeRefresh.setRefreshing(false);
AdminGetUsersViewModel.loadUsersList(getApplicationContext(), instanceUrl, Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken));
}
}, 500);
}
});
swipeRefresh.setOnRefreshListener(() -> new Handler(Looper.getMainLooper()).postDelayed(() -> {
fetchDataAsync(getApplicationContext(), instanceUrl, Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken));
swipeRefresh.setRefreshing(false);
AdminGetUsersViewModel.loadUsersList(ctx, Authorization.get(ctx));
}, 500));
fetchDataAsync(ctx, Authorization.get(ctx));
}
private void fetchDataAsync(Context ctx, String instanceUrl, String instanceToken) {
private void fetchDataAsync(Context ctx, String instanceToken) {
AdminGetUsersViewModel usersModel = ViewModelProviders.of(this).get(AdminGetUsersViewModel.class);
AdminGetUsersViewModel usersModel = new ViewModelProvider(this).get(AdminGetUsersViewModel.class);
usersModel.getUsersList(ctx, instanceUrl, instanceToken).observe(this, new Observer<List<UserInfo>>() {
@Override
public void onChanged(@Nullable List<UserInfo> usersListMain) {
adapter = new AdminGetUsersAdapter(getApplicationContext(), usersListMain);
if(adapter.getItemCount() > 0) {
mRecyclerView.setVisibility(View.VISIBLE);
mRecyclerView.setAdapter(adapter);
noDataUsers.setVisibility(View.GONE);
searchFilter = true;
}
else {
//adapter.notifyDataSetChanged();
//mRecyclerView.setAdapter(adapter);
mRecyclerView.setVisibility(View.GONE);
noDataUsers.setVisibility(View.VISIBLE);
}
usersModel.getUsersList(ctx, instanceToken).observe(this, usersListMain -> {
adapter = new AdminGetUsersAdapter(ctx, usersListMain);
if(adapter.getItemCount() > 0) {
mRecyclerView.setVisibility(View.VISIBLE);
mRecyclerView.setAdapter(adapter);
noDataUsers.setVisibility(View.GONE);
searchFilter = true;
}
else {
mRecyclerView.setVisibility(View.GONE);
noDataUsers.setVisibility(View.VISIBLE);
}
});
}
@ -125,37 +107,37 @@ public class AdminGetUsersActivity extends BaseActivity implements AdminUsersBot
final MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.generic_nav_dotted_menu, menu);
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
if(searchFilter) {
new Handler(Looper.getMainLooper()).postDelayed(() -> {
boolean connToInternet = AppUtil.haveNetworkConnection(Objects.requireNonNull(getApplicationContext()));
if(searchFilter) {
inflater.inflate(R.menu.search_menu, menu);
boolean connToInternet = AppUtil.hasNetworkConnection(appCtx);
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);
inflater.inflate(R.menu.search_menu, menu);
if(!connToInternet) {
return;
MenuItem searchItem = menu.findItem(R.id.action_search);
SearchView searchView = (SearchView) searchItem.getActionView();
searchView.setImeOptions(EditorInfo.IME_ACTION_DONE);
if(!connToInternet) {
return;
}
searchView.setOnQueryTextListener(new androidx.appcompat.widget.SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) { return true; }
@Override
public boolean onQueryTextChange(String newText) {
adapter.getFilter().filter(newText);
return false;
}
searchView.setOnQueryTextListener(new androidx.appcompat.widget.SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
return true;
}
@Override
public boolean onQueryTextChange(String newText) {
adapter.getFilter().filter(newText);
return false;
}
});
}
});
}
}, 500);
return true;
@ -166,18 +148,21 @@ public class AdminGetUsersActivity extends BaseActivity implements AdminUsersBot
int id = item.getItemId();
switch (id) {
case android.R.id.home:
finish();
return true;
case R.id.genericMenu:
AdminUsersBottomSheetFragment bottomSheet = new AdminUsersBottomSheetFragment();
bottomSheet.show(getSupportFragmentManager(), "usersBottomSheet");
return true;
default:
return super.onOptionsItemSelected(item);
}
if(id == android.R.id.home) {
finish();
return true;
}
else if(id == R.id.genericMenu) {
BottomSheetAdminUsersFragment bottomSheet = new BottomSheetAdminUsersFragment();
bottomSheet.show(getSupportFragmentManager(), "usersBottomSheet");
return true;
}
else {
return super.onOptionsItemSelected(item);
}
}
@Override
@ -192,12 +177,7 @@ public class AdminGetUsersActivity extends BaseActivity implements AdminUsersBot
}
private void initCloseListener() {
onClickListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
finish();
}
};
onClickListener = view -> finish();
}
}

View File

@ -1,10 +1,18 @@
package org.mian.gitnex.activities;
import android.content.Context;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.biometric.BiometricPrompt;
import androidx.core.content.ContextCompat;
import org.mian.gitnex.R;
import org.mian.gitnex.helpers.FontsOverride;
import org.mian.gitnex.util.TinyDB;
import org.mian.gitnex.helpers.AppUtil;
import org.mian.gitnex.helpers.TimeHelper;
import org.mian.gitnex.helpers.TinyDB;
import org.mian.gitnex.notifications.Notifications;
import java.util.Locale;
import java.util.concurrent.Executor;
/**
* Author M M Arif
@ -12,58 +20,117 @@ import org.mian.gitnex.util.TinyDB;
public abstract class BaseActivity extends AppCompatActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
protected TinyDB tinyDB;
final TinyDB tinyDb = new TinyDB(getApplicationContext());
protected Context ctx = this;
protected Context appCtx;
if(tinyDb.getInt("themeId") == 1) {
setTheme(R.style.AppThemeLight);
}
else {
setTheme(R.style.AppTheme);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(getLayoutResourceId());
super.onCreate(savedInstanceState);
if(tinyDb.getInt("customFontId") == 0) {
this.appCtx = getApplicationContext();
this.tinyDB = TinyDB.getInstance(appCtx);
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");
switch(tinyDB.getInt("themeId")) {
}
else if (tinyDb.getInt("customFontId") == 1) {
case 1:
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");
tinyDB.putString("currentTheme", "light");
setTheme(R.style.AppThemeLight);
break;
case 2:
}
else if (tinyDb.getInt("customFontId") == 2) {
if(TimeHelper.timeBetweenHours(tinyDB.getInt("darkThemeTimeHour"), tinyDB.getInt("lightThemeTimeHour"), tinyDB.getInt("darkThemeTimeMinute"), tinyDB.getInt("lightThemeTimeMinute"))) {
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");
tinyDB.putString("currentTheme", "dark");
setTheme(R.style.AppTheme);
}
else {
}
else {
tinyDB.putString("currentTheme", "light");
setTheme(R.style.AppThemeLight);
}
break;
case 3:
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");
tinyDB.putString("currentTheme", "light");
setTheme(R.style.AppThemeRetro);
break;
case 4:
if(TimeHelper.timeBetweenHours(tinyDB.getInt("darkThemeTimeHour"), tinyDB.getInt("lightThemeTimeHour"), tinyDB.getInt("darkThemeTimeMinute"), tinyDB.getInt("lightThemeTimeMinute"))) {
}
tinyDB.putString("currentTheme", "dark");
setTheme(R.style.AppTheme);
}
else {
}
tinyDB.putString("currentTheme", "light");
setTheme(R.style.AppThemeRetro);
}
break;
case 5:
protected abstract int getLayoutResourceId();
tinyDB.putString("currentTheme", "dark");
setTheme(R.style.AppThemePitchBlack);
break;
default:
tinyDB.putString("currentTheme", "dark");
setTheme(R.style.AppTheme);
}
String locale = tinyDB.getString("locale");
if (locale.isEmpty()) {
AppUtil.setAppLocale(getResources(), Locale.getDefault().getLanguage());
}
else {
AppUtil.setAppLocale(getResources(), locale);
}
Notifications.startWorker(appCtx);
}
public void onResume() {
super.onResume();
if(tinyDB.getBoolean("biometricStatus") && !tinyDB.getBoolean("biometricLifeCycle")) {
Executor executor = ContextCompat.getMainExecutor(this);
BiometricPrompt biometricPrompt = new BiometricPrompt(this, executor, new BiometricPrompt.AuthenticationCallback() {
@Override
public void onAuthenticationError(int errorCode, @NonNull CharSequence errString) {
super.onAuthenticationError(errorCode, errString);
// Authentication error, close the app
if(errorCode == BiometricPrompt.ERROR_USER_CANCELED ||
errorCode == BiometricPrompt.ERROR_NEGATIVE_BUTTON) {
finish();
}
}
// Authentication succeeded, continue to app
@Override public void onAuthenticationSucceeded(@NonNull BiometricPrompt.AuthenticationResult result) { super.onAuthenticationSucceeded(result); tinyDB.putBoolean("biometricLifeCycle", true); }
// Authentication failed, close the app
@Override public void onAuthenticationFailed() { super.onAuthenticationFailed(); }
});
BiometricPrompt.PromptInfo biometricPromptBuilder = new BiometricPrompt.PromptInfo.Builder()
.setTitle(getString(R.string.biometricAuthTitle))
.setSubtitle(getString(R.string.biometricAuthSubTitle))
.setNegativeButtonText(getString(R.string.cancelButton)).build();
biometricPrompt.authenticate(biometricPromptBuilder);
}
}
}

View File

@ -0,0 +1,268 @@
package org.mian.gitnex.activities;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
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.appcompat.widget.Toolbar;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import org.gitnex.tea4j.models.Commits;
import org.mian.gitnex.R;
import org.mian.gitnex.adapters.CommitsAdapter;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.databinding.ActivityCommitsBinding;
import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.helpers.Constants;
import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.helpers.Version;
import java.util.ArrayList;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
/**
* Author M M Arif
*/
public class CommitsActivity extends BaseActivity {
private View.OnClickListener onClickListener;
private TextView noData;
private ProgressBar progressBar;
private String TAG = "CommitsActivity";
private int resultLimit = Constants.resultLimitOldGiteaInstances;
private int pageSize = 1;
private RecyclerView recyclerView;
private List<Commits> commitsList;
private CommitsAdapter adapter;
private ProgressBar progressLoadMore;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityCommitsBinding activityCommitsBinding = ActivityCommitsBinding.inflate(getLayoutInflater());
setContentView(activityCommitsBinding.getRoot());
Toolbar toolbar = activityCommitsBinding.toolbar;
setSupportActionBar(toolbar);
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 = activityCommitsBinding.toolbarTitle;
toolbar_title.setMovementMethod(new ScrollingMovementMethod());
toolbar_title.setText(branchName);
ImageView closeActivity = activityCommitsBinding.close;
noData = activityCommitsBinding.noDataCommits;
progressLoadMore = activityCommitsBinding.progressLoadMore;
progressBar = activityCommitsBinding.progressBar;
SwipeRefreshLayout swipeRefresh = activityCommitsBinding.pullToRefresh;
initCloseListener();
closeActivity.setOnClickListener(onClickListener);
// if gitea is 1.12 or higher use the new limit (resultLimitNewGiteaInstances)
if(new Version(tinyDB.getString("giteaVersion")).higherOrEqual("1.12")) {
resultLimit = Constants.resultLimitNewGiteaInstances;
}
recyclerView = activityCommitsBinding.recyclerView;
commitsList = new ArrayList<>();
swipeRefresh.setOnRefreshListener(() -> new Handler(Looper.getMainLooper()).postDelayed(() -> {
swipeRefresh.setRefreshing(false);
loadInitial(Authorization.get(ctx), repoOwner, repoName, branchName, resultLimit);
adapter.notifyDataChanged();
}, 200));
adapter = new CommitsAdapter(ctx, commitsList);
adapter.setLoadMoreListener(() -> recyclerView.post(() -> {
if(commitsList.size() == resultLimit || pageSize == resultLimit) {
int page = (commitsList.size() + resultLimit) / resultLimit;
loadMore(Authorization.get(ctx), repoOwner, repoName, page, branchName, resultLimit);
}
}));
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(ctx));
recyclerView.setAdapter(adapter);
loadInitial(Authorization.get(ctx), repoOwner, repoName, branchName, resultLimit);
}
private void loadInitial(String token, String repoOwner, String repoName, String branchName, int resultLimit) {
Call<List<Commits>> call = RetrofitClient.getApiInterface(ctx).getRepositoryCommits(token, repoOwner, repoName, 1, branchName, resultLimit);
call.enqueue(new Callback<List<Commits>>() {
@Override
public void onResponse(@NonNull Call<List<Commits>> call, @NonNull Response<List<Commits>> response) {
if(response.code() == 200) {
assert response.body() != null;
if(response.body().size() > 0) {
commitsList.clear();
commitsList.addAll(response.body());
adapter.notifyDataChanged();
noData.setVisibility(View.GONE);
}
else {
commitsList.clear();
adapter.notifyDataChanged();
noData.setVisibility(View.VISIBLE);
}
}
if(response.code() == 409) {
noData.setVisibility(View.VISIBLE);
}
else {
Log.e(TAG, String.valueOf(response.code()));
}
progressBar.setVisibility(View.GONE);
}
@Override
public void onFailure(@NonNull Call<List<Commits>> call, @NonNull Throwable t) {
Toasty.error(ctx, getResources().getString(R.string.errorOnLogin));
}
});
}
private void loadMore(String token, String repoOwner, String repoName, final int page, String branchName, int resultLimit) {
progressLoadMore.setVisibility(View.VISIBLE);
Call<List<Commits>> call = RetrofitClient.getApiInterface(ctx).getRepositoryCommits(token, repoOwner, repoName, page, branchName, resultLimit);
call.enqueue(new Callback<List<Commits>>() {
@Override
public void onResponse(@NonNull Call<List<Commits>> call, @NonNull Response<List<Commits>> response) {
if(response.isSuccessful()) {
List<Commits> result = response.body();
assert result != null;
if(result.size() > 0) {
pageSize = result.size();
commitsList.addAll(result);
}
else {
adapter.setMoreDataAvailable(false);
}
adapter.notifyDataChanged();
}
else {
Log.e(TAG, String.valueOf(response.code()));
}
progressLoadMore.setVisibility(View.GONE);
}
@Override
public void onFailure(@NonNull Call<List<Commits>> call, @NonNull Throwable t) {
Toasty.error(ctx, getResources().getString(R.string.errorOnLogin));
}
});
}
@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) {
filter(newText);
return true;
}
});
return super.onCreateOptionsMenu(menu);
}
private void filter(String text) {
List<Commits> arr = new ArrayList<>();
for(Commits d : commitsList) {
if(d.getCommit().getMessage().toLowerCase().contains(text) || d.getSha().toLowerCase().contains(text)) {
arr.add(d);
}
}
adapter.updateList(arr);
}
private void initCloseListener() {
onClickListener = view -> {
getIntent().removeExtra("branchName");
finish();
};
}
}

View File

@ -0,0 +1,388 @@
package org.mian.gitnex.activities;
import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.ArrayAdapter;
import android.widget.TextView;
import androidx.annotation.NonNull;
import com.google.gson.JsonElement;
import org.gitnex.tea4j.models.Branches;
import org.gitnex.tea4j.models.DeleteFile;
import org.gitnex.tea4j.models.EditFile;
import org.gitnex.tea4j.models.NewFile;
import org.mian.gitnex.R;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.databinding.ActivityCreateFileBinding;
import org.mian.gitnex.helpers.AlertDialogs;
import org.mian.gitnex.helpers.AppUtil;
import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.helpers.NetworkStatusObserver;
import org.mian.gitnex.helpers.Toasty;
import java.util.ArrayList;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
/**
* Author M M Arif
*/
public class CreateFileActivity extends BaseActivity {
private ActivityCreateFileBinding binding;
public static final int FILE_ACTION_CREATE = 0;
public static final int FILE_ACTION_DELETE = 1;
public static final int FILE_ACTION_EDIT = 2;
private int fileAction = FILE_ACTION_CREATE;
private String filePath;
private String fileSha;
private final List<String> branches = new ArrayList<>();
private String repoOwner;
private String repoName;
@SuppressLint("ClickableViewAccessibility")
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityCreateFileBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
String repoFullName = tinyDB.getString("repoFullName");
String[] parts = repoFullName.split("/");
repoOwner = parts[0];
repoName = parts[1];
TextView toolbarTitle = binding.toolbarTitle;
binding.newFileName.requestFocus();
InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
assert inputMethodManager != null;
inputMethodManager.showSoftInput(binding.newFileName, InputMethodManager.SHOW_IMPLICIT);
binding.close.setOnClickListener(view -> finish());
binding.newFileContent.setOnTouchListener((touchView, motionEvent) -> {
touchView.getParent().requestDisallowInterceptTouchEvent(true);
if ((motionEvent.getAction() & MotionEvent.ACTION_UP) != 0 &&
(motionEvent.getActionMasked() & MotionEvent.ACTION_UP) != 0) {
touchView.getParent().requestDisallowInterceptTouchEvent(false);
}
return false;
});
if(getIntent().getStringExtra("filePath") != null && getIntent().getIntExtra("fileAction", FILE_ACTION_DELETE) == FILE_ACTION_DELETE) {
fileAction = getIntent().getIntExtra("fileAction", FILE_ACTION_DELETE);
filePath = getIntent().getStringExtra("filePath");
fileSha = getIntent().getStringExtra("fileSha");
toolbarTitle.setText(getString(R.string.deleteFileText, filePath));
binding.newFileCreate.setText(R.string.deleteFile);
binding.newFileNameLayout.setVisibility(View.GONE);
binding.newFileContentLayout.setVisibility(View.GONE);
}
if(getIntent().getStringExtra("filePath") != null && getIntent().getIntExtra("fileAction", FILE_ACTION_EDIT) == FILE_ACTION_EDIT) {
fileAction = getIntent().getIntExtra("fileAction", FILE_ACTION_EDIT);
filePath = getIntent().getStringExtra("filePath");
fileSha = getIntent().getStringExtra("fileSha");
toolbarTitle.setText(getString(R.string.editFileText, filePath));
binding.newFileCreate.setText(R.string.editFile);
binding.newFileName.setText(filePath);
binding.newFileName.setEnabled(false);
binding.newFileName.setFocusable(false);
binding.newFileContent.setText(getIntent().getStringExtra("fileContents"));
}
getBranches(repoOwner, repoName);
disableProcessButton();
NetworkStatusObserver networkStatusObserver = NetworkStatusObserver.getInstance(ctx);
networkStatusObserver.registerNetworkStatusListener(binding.newFileCreate::setEnabled);
binding.newFileCreate.setOnClickListener(v -> processNewFile());
}
private void processNewFile() {
String newFileName = binding.newFileName.getText() != null ? binding.newFileName.getText().toString() : "";
String newFileContent = binding.newFileContent.getText() != null ? binding.newFileContent.getText().toString() : "";
String newFileBranchName = binding.newFileBranches.getText() != null ? binding.newFileBranches.getText().toString() : "";
String newFileCommitMessage = binding.newFileCommitMessage.getText() != null ? binding.newFileCommitMessage.getText().toString() : "";
if(!AppUtil.hasNetworkConnection(appCtx)) {
Toasty.error(ctx, getResources().getString(R.string.checkNetConnection));
return;
}
if(((newFileName.isEmpty() || newFileContent.isEmpty()) && fileAction != FILE_ACTION_DELETE) || newFileCommitMessage.isEmpty()) {
Toasty.error(ctx, getString(R.string.newFileRequiredFields));
return;
}
if(!AppUtil.checkStringsWithDash(newFileBranchName)) {
Toasty.error(ctx, getString(R.string.newFileInvalidBranchName));
return;
}
if(newFileCommitMessage.length() > 255) {
Toasty.warning(ctx, getString(R.string.newFileCommitMessageError));
return;
}
disableProcessButton();
switch(fileAction) {
case FILE_ACTION_CREATE:
createNewFile(repoOwner, repoName, newFileName, AppUtil.encodeBase64(newFileContent), newFileCommitMessage, newFileBranchName);
break;
case FILE_ACTION_DELETE:
deleteFile(repoOwner, repoName, filePath, newFileCommitMessage, newFileBranchName, fileSha);
break;
case FILE_ACTION_EDIT:
editFile(repoOwner, repoName, filePath, AppUtil.encodeBase64(newFileContent), newFileCommitMessage, newFileBranchName, fileSha);
break;
}
}
private void createNewFile(String repoOwner, String repoName, String fileName, String fileContent, String fileCommitMessage, String branchName) {
NewFile createNewFileJsonStr = branches.contains(branchName) ?
new NewFile(branchName, fileContent, fileCommitMessage, "") :
new NewFile("", fileContent, fileCommitMessage, branchName);
Call<JsonElement> call = RetrofitClient
.getApiInterface(ctx)
.createNewFile(Authorization.get(ctx), repoOwner, repoName, fileName, createNewFileJsonStr);
call.enqueue(new Callback<JsonElement>() {
@Override
public void onResponse(@NonNull Call<JsonElement> call, @NonNull retrofit2.Response<JsonElement> response) {
switch(response.code()) {
case 201:
enableProcessButton();
Toasty.success(ctx, getString(R.string.newFileSuccessMessage));
finish();
break;
case 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));
break;
case 404:
enableProcessButton();
Toasty.warning(ctx, getString(R.string.apiNotFound));
break;
default:
enableProcessButton();
Toasty.error(ctx, getString(R.string.orgCreatedError));
break;
}
}
@Override
public void onFailure(@NonNull Call<JsonElement> call, @NonNull Throwable t) {
Log.e("onFailure", t.toString());
enableProcessButton();
}
});
}
private void deleteFile(String repoOwner, String repoName, String fileName, String fileCommitMessage, String branchName, String fileSha) {
DeleteFile deleteFileJsonStr = branches.contains(branchName) ?
new DeleteFile(branchName, fileCommitMessage, "", fileSha) :
new DeleteFile("", fileCommitMessage, branchName, fileSha);
Call<JsonElement> call = RetrofitClient
.getApiInterface(ctx)
.deleteFile(Authorization.get(ctx), repoOwner, repoName, fileName, deleteFileJsonStr);
call.enqueue(new Callback<JsonElement>() {
@Override
public void onResponse(@NonNull Call<JsonElement> call, @NonNull retrofit2.Response<JsonElement> response) {
switch(response.code()) {
case 200:
enableProcessButton();
Toasty.info(ctx, getString(R.string.deleteFileMessage, tinyDB.getString("repoBranch")));
getIntent().removeExtra("filePath");
getIntent().removeExtra("fileSha");
getIntent().removeExtra("fileContents");
finish();
break;
case 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));
break;
case 404:
enableProcessButton();
Toasty.info(ctx, getString(R.string.apiNotFound));
break;
default:
enableProcessButton();
Toasty.info(ctx, getString(R.string.genericError));
break;
}
}
@Override
public void onFailure(@NonNull Call<JsonElement> call, @NonNull Throwable t) {
Log.e("onFailure", t.toString());
enableProcessButton();
}
});
}
private void editFile(String repoOwner, String repoName, String fileName, String fileContent, String fileCommitMessage, String branchName, String fileSha) {
EditFile editFileJsonStr = branches.contains(branchName) ?
new EditFile(branchName, fileCommitMessage, "", fileSha, fileContent) :
new EditFile("", fileCommitMessage, branchName, fileSha, fileContent);
Call<JsonElement> call = RetrofitClient
.getApiInterface(ctx)
.editFile(Authorization.get(ctx), repoOwner, repoName, fileName, editFileJsonStr);
call.enqueue(new Callback<JsonElement>() {
@Override
public void onResponse(@NonNull Call<JsonElement> call, @NonNull retrofit2.Response<JsonElement> response) {
switch(response.code()) {
case 200:
enableProcessButton();
Toasty.info(ctx, getString(R.string.editFileMessage, branchName));
getIntent().removeExtra("filePath");
getIntent().removeExtra("fileSha");
getIntent().removeExtra("fileContents");
tinyDB.putBoolean("fileModified", true);
finish();
break;
case 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));
break;
case 404:
enableProcessButton();
Toasty.info(ctx, getString(R.string.apiNotFound));
break;
default:
enableProcessButton();
Toasty.info(ctx, getString(R.string.genericError));
break;
}
}
@Override
public void onFailure(@NonNull Call<JsonElement> call, @NonNull Throwable t) {
Log.e("onFailure", t.toString());
enableProcessButton();
}
});
}
private void getBranches(String repoOwner, String repoName) {
Call<List<Branches>> call = RetrofitClient
.getApiInterface(ctx)
.getBranches(Authorization.get(ctx), repoOwner, repoName);
call.enqueue(new Callback<List<Branches>>() {
@Override
public void onResponse(@NonNull Call<List<Branches>> call, @NonNull retrofit2.Response<List<Branches>> response) {
if(response.code() == 200) {
assert response.body() != null;
for(Branches branch : response.body()) branches.add(branch.getName());
ArrayAdapter<String> adapter = new ArrayAdapter<>(CreateFileActivity.this, R.layout.list_spinner_items, branches);
binding.newFileBranches.setAdapter(adapter);
binding.newFileBranches.setText(tinyDB.getString("repoBranch"), false);
enableProcessButton();
}
}
@Override
public void onFailure(@NonNull Call<List<Branches>> call, @NonNull Throwable t) {
Log.e("onFailure", t.toString());
}
});
}
private void disableProcessButton() { binding.newFileCreate.setEnabled(false); }
private void enableProcessButton() { binding.newFileCreate.setEnabled(true); }
}

View File

@ -1,292 +1,262 @@
package org.mian.gitnex.activities;
import androidx.annotation.NonNull;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import android.annotation.SuppressLint;
import android.app.DatePickerDialog;
import android.app.Dialog;
import android.content.Context;
import android.graphics.PorterDuff;
import android.graphics.drawable.GradientDrawable;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.DatePicker;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.Spinner;
import android.widget.TextView;
import androidx.annotation.NonNull;
import com.google.gson.JsonElement;
import com.hendraanggrian.appcompat.socialview.Mention;
import com.hendraanggrian.appcompat.widget.MentionArrayAdapter;
import com.hendraanggrian.appcompat.widget.SocialAutoCompleteTextView;
import org.gitnex.tea4j.models.Collaborators;
import org.gitnex.tea4j.models.CreateIssue;
import org.gitnex.tea4j.models.Labels;
import org.gitnex.tea4j.models.Milestones;
import org.mian.gitnex.R;
import org.mian.gitnex.actions.AssigneesActions;
import org.mian.gitnex.actions.LabelsActions;
import org.mian.gitnex.adapters.AssigneesListAdapter;
import org.mian.gitnex.adapters.LabelsListAdapter;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.databinding.ActivityCreateIssueBinding;
import org.mian.gitnex.databinding.CustomAssigneesSelectionDialogBinding;
import org.mian.gitnex.databinding.CustomLabelsSelectionDialogBinding;
import org.mian.gitnex.helpers.AlertDialogs;
import org.mian.gitnex.helpers.AppUtil;
import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.helpers.MultiSelectDialog;
import org.mian.gitnex.models.Collaborators;
import org.mian.gitnex.models.CreateIssue;
import org.mian.gitnex.models.Labels;
import org.mian.gitnex.models.Milestones;
import org.mian.gitnex.models.MultiSelectModel;
import org.mian.gitnex.util.AppUtil;
import org.mian.gitnex.util.TinyDB;
import org.mian.gitnex.helpers.Constants;
import org.mian.gitnex.helpers.TinyDB;
import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.helpers.Version;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.List;
import java.util.Objects;
import retrofit2.Call;
import retrofit2.Callback;
/**
* Author M M Arif
*/
public class CreateIssueActivity extends BaseActivity implements View.OnClickListener {
public class CreateIssueActivity extends BaseActivity implements View.OnClickListener, LabelsListAdapter.LabelsListAdapterListener, AssigneesListAdapter.AssigneesListAdapterListener {
private ActivityCreateIssueBinding viewBinding;
private CustomLabelsSelectionDialogBinding labelsBinding;
private CustomAssigneesSelectionDialogBinding assigneesBinding;
private View.OnClickListener onClickListener;
MultiSelectDialog multiSelectDialog;
MultiSelectDialog multiSelectDialogLabels;
private TextView assigneesList;
private TextView newIssueLabels;
private TextView newIssueDueDate;
private Spinner newIssueMilestoneSpinner;
private EditText newIssueTitle;
private SocialAutoCompleteTextView newIssueDescription;
private Button createNewIssueButton;
private TextView labelsIdHolder;
private boolean assigneesFlag;
private boolean labelsFlag;
final Context ctx = this;
private int resultLimit = Constants.resultLimitOldGiteaInstances;
private Dialog dialogLabels;
private Dialog dialogAssignees;
private String labelsSetter;
private String assigneesSetter;
private int milestoneId;
List<Milestones> milestonesList = new ArrayList<>();
ArrayList<MultiSelectModel> listOfAssignees = new ArrayList<>();
ArrayList<MultiSelectModel> listOfLabels= new ArrayList<>();
private ArrayAdapter<Mention> defaultMentionAdapter;
private String loginUid;
private String repoOwner;
private String repoName;
@Override
protected int getLayoutResourceId(){
return R.layout.activity_create_issue;
}
private LabelsListAdapter labelsAdapter;
private AssigneesListAdapter assigneesAdapter;
private List<Integer> labelsIds = new ArrayList<>();
private List<Labels> labelsList = new ArrayList<>();
private List<Milestones> milestonesList = new ArrayList<>();
private List<Collaborators> assigneesList = new ArrayList<>();
private List<String> assigneesListData = new ArrayList<>();
@SuppressLint("ClickableViewAccessibility")
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
boolean connToInternet = AppUtil.haveNetworkConnection(getApplicationContext());
viewBinding = ActivityCreateIssueBinding.inflate(getLayoutInflater());
setContentView(viewBinding.getRoot());
TinyDB tinyDb = new TinyDB(getApplicationContext());
final String instanceUrl = tinyDb.getString("instanceUrl");
final String loginUid = tinyDb.getString("loginUid");
final String loginFullName = tinyDb.getString("userFullname");
String repoFullName = tinyDb.getString("repoFullName");
boolean connToInternet = AppUtil.hasNetworkConnection(appCtx);
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
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");
repoOwner = parts[0];
repoName = parts[1];
ImageView closeActivity = findViewById(R.id.close);
assigneesList = findViewById(R.id.newIssueAssigneesList);
newIssueLabels = findViewById(R.id.newIssueLabels);
newIssueDueDate = findViewById(R.id.newIssueDueDate);
createNewIssueButton = findViewById(R.id.createNewIssueButton);
newIssueTitle = findViewById(R.id.newIssueTitle);
newIssueDescription = findViewById(R.id.newIssueDescription);
labelsIdHolder = findViewById(R.id.labelsIdHolder);
// require gitea 1.12 or higher
if(new Version(tinyDB.getString("giteaVersion")).higherOrEqual("1.12.0")) {
defaultMentionAdapter = new MentionArrayAdapter<>(this);
loadCollaboratorsList();
resultLimit = Constants.resultLimitNewGiteaInstances;
}
newIssueDescription.setMentionAdapter(defaultMentionAdapter);
viewBinding.newIssueTitle.requestFocus();
assert imm != null;
imm.showSoftInput(viewBinding.newIssueTitle, InputMethodManager.SHOW_IMPLICIT);
viewBinding.newIssueDescription.setOnTouchListener((touchView, motionEvent) -> {
touchView.getParent().requestDisallowInterceptTouchEvent(true);
if ((motionEvent.getAction() & MotionEvent.ACTION_UP) != 0 && (motionEvent.getActionMasked() & MotionEvent.ACTION_UP) != 0) {
touchView.getParent().requestDisallowInterceptTouchEvent(false);
}
return false;
});
labelsAdapter = new LabelsListAdapter(labelsList, CreateIssueActivity.this, labelsIds);
assigneesAdapter = new AssigneesListAdapter(ctx, assigneesList, CreateIssueActivity.this, assigneesListData);
initCloseListener();
closeActivity.setOnClickListener(onClickListener);
viewBinding.close.setOnClickListener(onClickListener);
assigneesList.setOnClickListener(this);
newIssueLabels.setOnClickListener(this);
newIssueDueDate.setOnClickListener(this);
viewBinding.newIssueAssigneesList.setOnClickListener(this);
viewBinding.newIssueLabels.setOnClickListener(this);
viewBinding.newIssueDueDate.setOnClickListener(this);
newIssueMilestoneSpinner = findViewById(R.id.newIssueMilestoneSpinner);
newIssueMilestoneSpinner.getBackground().setColorFilter(getResources().getColor(R.color.white), PorterDuff.Mode.SRC_ATOP);
getMilestones(instanceUrl, instanceToken, repoOwner, repoName, loginUid);
getLabels(instanceUrl, instanceToken, repoOwner, repoName, loginUid);
getCollaborators(instanceUrl, instanceToken, repoOwner, repoName, loginUid, loginFullName);
getMilestones(repoOwner, repoName, resultLimit);
disableProcessButton();
viewBinding.newIssueLabels.setOnClickListener(newIssueLabels -> showLabels());
viewBinding.newIssueAssigneesList.setOnClickListener(newIssueAssigneesList -> showAssignees());
if(!connToInternet) {
createNewIssueButton.setEnabled(false);
GradientDrawable shape = new GradientDrawable();
shape.setCornerRadius( 8 );
shape.setColor(getResources().getColor(R.color.hintColor));
createNewIssueButton.setBackground(shape);
} else {
createNewIssueButton.setOnClickListener(this);
viewBinding.createNewIssueButton.setEnabled(false);
}
else {
viewBinding.createNewIssueButton.setOnClickListener(this);
}
}
@Override
public void assigneesInterface(List<String> data) {
assigneesSetter = String.valueOf(data);
viewBinding.newIssueAssigneesList.setText(assigneesSetter.replace("]", "").replace("[", ""));
assigneesListData = data;
}
@Override
public void labelsInterface(List<String> data) {
labelsSetter = String.valueOf(data);
viewBinding.newIssueLabels.setText(labelsSetter.replace("]", "").replace("[", ""));
}
@Override
public void labelsIdsInterface(List<Integer> data) {
labelsIds = data;
}
private void showAssignees() {
dialogAssignees = new Dialog(ctx, R.style.ThemeOverlay_MaterialComponents_Dialog_Alert);
if (dialogAssignees.getWindow() != null) {
dialogAssignees.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
}
assigneesBinding = CustomAssigneesSelectionDialogBinding.inflate(LayoutInflater.from(ctx));
View view = assigneesBinding.getRoot();
dialogAssignees.setContentView(view);
assigneesBinding.cancel.setOnClickListener(assigneesBinding_ -> dialogAssignees.dismiss());
dialogAssignees.show();
AssigneesActions.getRepositoryAssignees(ctx, repoOwner, repoName, assigneesList, dialogAssignees, assigneesAdapter, assigneesBinding);
}
private void showLabels() {
dialogLabels = new Dialog(ctx, R.style.ThemeOverlay_MaterialComponents_Dialog_Alert);
if (dialogLabels.getWindow() != null) {
dialogLabels.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
}
labelsBinding = CustomLabelsSelectionDialogBinding.inflate(LayoutInflater.from(ctx));
View view = labelsBinding.getRoot();
dialogLabels.setContentView(view);
labelsBinding.cancel.setOnClickListener(labelsBinding_ -> dialogLabels.dismiss());
dialogLabels.show();
LabelsActions.getRepositoryLabels(ctx, repoOwner, repoName, labelsList, dialogLabels, labelsAdapter, labelsBinding);
}
private void processNewIssue() {
boolean connToInternet = AppUtil.haveNetworkConnection(getApplicationContext());
TinyDB tinyDb = new TinyDB(getApplicationContext());
final String instanceUrl = tinyDb.getString("instanceUrl");
final String loginUid = tinyDb.getString("loginUid");
String repoFullName = tinyDb.getString("repoFullName");
String[] parts = repoFullName.split("/");
final String repoOwner = parts[0];
final String repoName = parts[1];
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
boolean connToInternet = AppUtil.hasNetworkConnection(appCtx);
Milestones mModel = (Milestones) newIssueMilestoneSpinner.getSelectedItem();
int newIssueMilestoneIdForm = mModel.getId();
String newIssueTitleForm = newIssueTitle.getText().toString();
String newIssueDescriptionForm = newIssueDescription.getText().toString();
String newIssueAssigneesListForm = assigneesList.getText().toString();
//String newIssueLabelsForm = newIssueLabels.getText().toString();
String newIssueDueDateForm = newIssueDueDate.getText().toString();
String newIssueLabelsIdHolderForm = labelsIdHolder.getText().toString();
String newIssueTitleForm = Objects.requireNonNull(viewBinding.newIssueTitle.getText()).toString();
String newIssueDescriptionForm = Objects.requireNonNull(viewBinding.newIssueDescription.getText()).toString();
String newIssueDueDateForm = Objects.requireNonNull(viewBinding.newIssueDueDate.getText()).toString();
if(!connToInternet) {
Toasty.info(getApplicationContext(), getResources().getString(R.string.checkNetConnection));
Toasty.error(ctx, getResources().getString(R.string.checkNetConnection));
return;
}
if (newIssueTitleForm.equals("")) {
Toasty.info(getApplicationContext(), getString(R.string.issueTitleEmpty));
Toasty.error(ctx, getString(R.string.issueTitleEmpty));
return;
}
/*if (newIssueDescriptionForm.equals("")) {
Toasty.info(getApplicationContext(), getString(R.string.issueDescriptionEmpty));
return;
}*/
if (newIssueDueDateForm.equals("")) {
newIssueDueDateForm = null;
} else {
}
else {
newIssueDueDateForm = (AppUtil.customDateCombine(AppUtil.customDateFormat(newIssueDueDateForm)));
}
List<String> newIssueAssigneesListForm_ = new ArrayList<>(Arrays.asList(newIssueAssigneesListForm.split(",")));
for (int i = 0; i < newIssueAssigneesListForm_.size(); i++) {
newIssueAssigneesListForm_.set(i, newIssueAssigneesListForm_.get(i).trim());
}
int[] integers;
if (!newIssueLabelsIdHolderForm.equals("")) {
String[] items = newIssueLabelsIdHolderForm.replaceAll("\\[", "").replaceAll("\\]", "").replaceAll("\\s", "").split(",");
integers = new int[items.length];
for (int i = 0; i < integers.length; i++) {
integers[i] = Integer.parseInt(items[i]);
}
}
else {
integers = new int[0];
}
//Log.i("FormData", String.valueOf(newIssueLabelsForm));
disableProcessButton();
createNewIssueFunc(instanceUrl, instanceToken, repoOwner, repoName, loginUid, newIssueDescriptionForm, newIssueDueDateForm, newIssueMilestoneIdForm, newIssueTitleForm, newIssueAssigneesListForm_, integers);
createNewIssueFunc(repoOwner, repoName, loginUid, newIssueDescriptionForm, newIssueDueDateForm, milestoneId, newIssueTitleForm);
}
public void loadCollaboratorsList() {
private void createNewIssueFunc(String repoOwner, String repoName, String loginUid, String newIssueDescriptionForm, String newIssueDueDateForm, int newIssueMilestoneIdForm, String newIssueTitleForm) {
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 createNewIssueFunc(final String instanceUrl, final String instanceToken, String repoOwner, String repoName, String loginUid, String newIssueDescriptionForm, String newIssueDueDateForm, int newIssueMilestoneIdForm, String newIssueTitleForm, List<String> newIssueAssigneesListForm, int[] newIssueLabelsForm) {
CreateIssue createNewIssueJson = new CreateIssue(loginUid, newIssueDescriptionForm, false, newIssueDueDateForm, newIssueMilestoneIdForm, newIssueTitleForm, newIssueAssigneesListForm, newIssueLabelsForm);
CreateIssue createNewIssueJson = new CreateIssue(loginUid, newIssueDescriptionForm, false, newIssueDueDateForm, newIssueMilestoneIdForm, newIssueTitleForm, assigneesListData, labelsIds);
Call<JsonElement> call3;
call3 = RetrofitClient
.getInstance(instanceUrl, getApplicationContext())
.getApiInterface()
.createNewIssue(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName, createNewIssueJson);
.getApiInterface(ctx)
.createNewIssue(Authorization.get(ctx), repoOwner, repoName, createNewIssueJson);
call3.enqueue(new Callback<JsonElement>() {
@Override
public void onResponse(@NonNull Call<JsonElement> call, @NonNull retrofit2.Response<JsonElement> response2) {
if(response2.isSuccessful()) {
if(response2.code() == 201) {
if(response2.code() == 201) {
//Log.i("isSuccessful1", String.valueOf(response2.body()));
TinyDB tinyDb = new TinyDB(getApplicationContext());
tinyDb.putBoolean("resumeIssues", true);
Toasty.info(getApplicationContext(), getString(R.string.issueCreated));
enableProcessButton();
finish();
}
TinyDB tinyDb = TinyDB.getInstance(appCtx);
tinyDb.putBoolean("resumeIssues", true);
Toasty.success(ctx, getString(R.string.issueCreated));
enableProcessButton();
finish();
}
else if(response2.code() == 401) {
@ -295,21 +265,19 @@ public class CreateIssueActivity extends BaseActivity implements View.OnClickLis
getResources().getString(R.string.alertDialogTokenRevokedMessage),
getResources().getString(R.string.alertDialogTokenRevokedCopyNegativeButton),
getResources().getString(R.string.alertDialogTokenRevokedCopyPositiveButton));
}
else {
Toasty.info(getApplicationContext(), getString(R.string.issueCreatedError));
Toasty.error(ctx, getString(R.string.issueCreatedError));
enableProcessButton();
//Log.i("isSuccessful2", String.valueOf(response2.body()));
}
}
@Override
public void onFailure(@NonNull Call<JsonElement> call, @NonNull Throwable t) {
Log.e("onFailure", t.toString());
Toasty.error(ctx, getString(R.string.genericServerResponseError));
enableProcessButton();
}
});
@ -317,21 +285,16 @@ public class CreateIssueActivity extends BaseActivity implements View.OnClickLis
}
private void initCloseListener() {
onClickListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
finish();
}
};
onClickListener = view -> finish();
}
private void getMilestones(String instanceUrl, String instanceToken, String repoOwner, String repoName, String loginUid) {
private void getMilestones(String repoOwner, String repoName, int resultLimit) {
String msState = "open";
Call<List<Milestones>> call = RetrofitClient
.getInstance(instanceUrl, getApplicationContext())
.getApiInterface()
.getMilestones(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName, msState);
.getApiInterface(ctx)
.getMilestones(Authorization.get(ctx), repoOwner, repoName, 1, resultLimit, msState);
call.enqueue(new Callback<List<Milestones>>() {
@ -339,13 +302,16 @@ public class CreateIssueActivity extends BaseActivity implements View.OnClickLis
public void onResponse(@NonNull Call<List<Milestones>> call, @NonNull retrofit2.Response<List<Milestones>> response) {
if(response.isSuccessful()) {
if(response.code() == 200) {
List<Milestones> milestonesList_ = response.body();
milestonesList.add(new Milestones(0,getString(R.string.issueCreatedNoMilestone)));
assert milestonesList_ != null;
if(milestonesList_.size() > 0) {
for (int i = 0; i < milestonesList_.size(); i++) {
//Don't translate "open" is a enum
@ -356,17 +322,20 @@ public class CreateIssueActivity extends BaseActivity implements View.OnClickLis
);
milestonesList.add(data);
}
}
}
ArrayAdapter<Milestones> adapter = new ArrayAdapter<>(getApplicationContext(),
R.layout.spinner_item, milestonesList);
ArrayAdapter<Milestones> adapter = new ArrayAdapter<>(CreateIssueActivity.this,
R.layout.list_spinner_items, milestonesList);
adapter.setDropDownViewResource(R.layout.spinner_dropdown_item);
newIssueMilestoneSpinner.setAdapter(adapter);
viewBinding.newIssueMilestoneSpinner.setAdapter(adapter);
enableProcessButton();
viewBinding.newIssueMilestoneSpinner.setOnItemClickListener ((parent, view, position, id) ->
milestoneId = milestonesList.get(position).getId()
);
}
}
@ -374,143 +343,8 @@ public class CreateIssueActivity extends BaseActivity implements View.OnClickLis
@Override
public void onFailure(@NonNull Call<List<Milestones>> call, @NonNull Throwable t) {
Log.e("onFailure", t.toString());
}
});
}
private void getCollaborators(String instanceUrl, String instanceToken, String repoOwner, String repoName, String loginUid, String loginFullName) {
Call<List<Collaborators>> call = RetrofitClient
.getInstance(instanceUrl, getApplicationContext())
.getApiInterface()
.getCollaborators(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName);
listOfAssignees.add(new MultiSelectModel(-1, loginFullName));
call.enqueue(new Callback<List<Collaborators>>() {
@Override
public void onResponse(@NonNull Call<List<Collaborators>> call, @NonNull retrofit2.Response<List<Collaborators>> response) {
if(response.isSuccessful()) {
if(response.code() == 200) {
List<Collaborators> assigneesList_ = response.body();
assert assigneesList_ != null;
if(assigneesList_.size() > 0) {
for (int i = 0; i < assigneesList_.size(); i++) {
/*String assigneesCopy;
if(!assigneesList_.get(i).getFull_name().equals("")) {
assigneesCopy = getString(R.string.dialogAssignessText, assigneesList_.get(i).getFull_name(), assigneesList_.get(i).getLogin());
}
else {
assigneesCopy = assigneesList_.get(i).getLogin();
}*/
listOfAssignees.add(new MultiSelectModel(assigneesList_.get(i).getId(), assigneesList_.get(i).getLogin().trim()));
}
assigneesFlag = true;
}
multiSelectDialog = new MultiSelectDialog()
.title(getResources().getString(R.string.newIssueSelectAssigneesListTitle))
.titleSize(25)
.positiveText(getResources().getString(R.string.okButton))
.negativeText(getResources().getString(R.string.cancelButton))
.setMinSelectionLimit(0)
.setMaxSelectionLimit(listOfAssignees.size())
.multiSelectList(listOfAssignees)
.onSubmit(new MultiSelectDialog.SubmitCallbackListener() {
@Override
public void onSelected(ArrayList<Integer> selectedIds, ArrayList<String> selectedNames, String dataString) {
assigneesList.setText(dataString);
}
@Override
public void onCancel() {
//Log.d("multiSelect","Dialog cancelled");
}
});
}
}
}
@Override
public void onFailure(@NonNull Call<List<Collaborators>> call, @NonNull Throwable t) {
Log.e("onFailure", t.toString());
}
});
}
private void getLabels(String instanceUrl, String instanceToken, String repoOwner, String repoName, String loginUid) {
Call<List<Labels>> call = RetrofitClient
.getInstance(instanceUrl, getApplicationContext())
.getApiInterface()
.getlabels(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName);
call.enqueue(new Callback<List<Labels>>() {
@Override
public void onResponse(@NonNull Call<List<Labels>> call, @NonNull retrofit2.Response<List<Labels>> response) {
if(response.isSuccessful()) {
if(response.code() == 200) {
List<Labels> labelsList_ = response.body();
assert labelsList_ != null;
if(labelsList_.size() > 0) {
for (int i = 0; i < labelsList_.size(); i++) {
listOfLabels.add(new MultiSelectModel(labelsList_.get(i).getId(), labelsList_.get(i).getName().trim()));
}
labelsFlag = true;
}
multiSelectDialogLabels = new MultiSelectDialog()
.title(getResources().getString(R.string.newIssueSelectLabelsListTitle))
.titleSize(25)
.positiveText(getResources().getString(R.string.okButton))
.negativeText(getResources().getString(R.string.cancelButton))
.setMinSelectionLimit(0)
.setMaxSelectionLimit(listOfLabels.size())
.multiSelectList(listOfLabels)
.onSubmit(new MultiSelectDialog.SubmitCallbackListener() {
@Override
public void onSelected(ArrayList<Integer> selectedIds, ArrayList<String> selectedNames, String dataString) {
newIssueLabels.setText(dataString.trim());
labelsIdHolder.setText(selectedIds.toString());
}
@Override
public void onCancel() {
//Log.d("multiSelect","Dialog cancelled");
}
});
}
}
}
@Override
public void onFailure(@NonNull Call<List<Labels>> call, @NonNull Throwable t) {
Log.e("onFailure", t.toString());
Toasty.error(ctx, getString(R.string.genericServerResponseError));
}
});
@ -518,23 +352,8 @@ public class CreateIssueActivity extends BaseActivity implements View.OnClickLis
@Override
public void onClick(View v) {
if (v == assigneesList) {
if(assigneesFlag) {
multiSelectDialog.show(getSupportFragmentManager(), "multiSelectDialog");
}
else {
Toasty.info(getApplicationContext(), getResources().getString(R.string.noAssigneesFound));
}
}
else if (v == newIssueLabels) {
if(labelsFlag) {
multiSelectDialogLabels.show(getSupportFragmentManager(), "multiSelectDialogLabels");
}
else {
Toasty.info(getApplicationContext(), getResources().getString(R.string.noLabelsFound));
}
}
else if (v == newIssueDueDate) {
if (v == viewBinding.newIssueDueDate) {
final Calendar c = Calendar.getInstance();
int mYear = c.get(Calendar.YEAR);
@ -542,41 +361,22 @@ public class CreateIssueActivity extends BaseActivity implements View.OnClickLis
final int mDay = c.get(Calendar.DAY_OF_MONTH);
DatePickerDialog datePickerDialog = new DatePickerDialog(this,
new DatePickerDialog.OnDateSetListener() {
@Override
public void onDateSet(DatePicker view, int year,
int monthOfYear, int dayOfMonth) {
newIssueDueDate.setText(getString(R.string.setDueDate, year, (monthOfYear + 1), dayOfMonth));
}
}, mYear, mMonth, mDay);
(view, year, monthOfYear, dayOfMonth) -> viewBinding.newIssueDueDate.setText(getString(R.string.setDueDate, year, (monthOfYear + 1), dayOfMonth)), mYear, mMonth, mDay);
datePickerDialog.show();
}
else if(v == createNewIssueButton) {
else if(v == viewBinding.createNewIssueButton) {
processNewIssue();
}
}
private void disableProcessButton() {
createNewIssueButton.setEnabled(false);
GradientDrawable shape = new GradientDrawable();
shape.setCornerRadius( 8 );
shape.setColor(getResources().getColor(R.color.hintColor));
createNewIssueButton.setBackground(shape);
viewBinding.createNewIssueButton.setEnabled(false);
}
private void enableProcessButton() {
createNewIssueButton.setEnabled(true);
GradientDrawable shape = new GradientDrawable();
shape.setCornerRadius( 8 );
shape.setColor(getResources().getColor(R.color.btnBackground));
createNewIssueButton.setBackground(shape);
viewBinding.createNewIssueButton.setEnabled(true);
}
}

View File

@ -1,33 +1,33 @@
package org.mian.gitnex.activities;
import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
import retrofit2.Call;
import retrofit2.Callback;
import android.content.Context;
import android.graphics.Color;
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.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
import com.pes.androidmaterialcolorpickerdialog.ColorPicker;
import com.pes.androidmaterialcolorpickerdialog.ColorPickerCallback;
import org.gitnex.tea4j.models.CreateLabel;
import org.gitnex.tea4j.models.Labels;
import org.mian.gitnex.R;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.databinding.ActivityCreateLabelBinding;
import org.mian.gitnex.helpers.AlertDialogs;
import org.mian.gitnex.helpers.AppUtil;
import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.helpers.TinyDB;
import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.models.CreateLabel;
import org.mian.gitnex.models.Labels;
import org.mian.gitnex.util.AppUtil;
import org.mian.gitnex.util.TinyDB;
import org.mian.gitnex.viewmodels.LabelsViewModel;
import org.mian.gitnex.viewmodels.OrganizationLabelsViewModel;
import java.util.Objects;
import retrofit2.Call;
import retrofit2.Callback;
/**
* Author M M Arif
@ -39,61 +39,54 @@ public class CreateLabelActivity extends BaseActivity {
private TextView colorPicker;
private EditText labelName;
private Button createLabelButton;
final Context ctx = this;
@Override
protected int getLayoutResourceId(){
return R.layout.activity_create_label;
}
private TinyDB tinyDB;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final TinyDB tinyDb = new TinyDB(getApplicationContext());
String repoFullName = tinyDb.getString("repoFullName");
ActivityCreateLabelBinding activityCreateLabelBinding = ActivityCreateLabelBinding.inflate(getLayoutInflater());
setContentView(activityCreateLabelBinding.getRoot());
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
tinyDB = TinyDB.getInstance(appCtx);
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");
if(getIntent().getStringExtra("labelAction") != null && Objects.requireNonNull(getIntent().getStringExtra("labelAction")).equals("delete")) {
deleteLabel(instanceUrl, instanceToken, repoOwner, repoName, Integer.valueOf(Objects.requireNonNull(getIntent().getStringExtra("labelId"))), loginUid);
deleteLabel(repoOwner, repoName, Integer.parseInt(Objects.requireNonNull(getIntent().getStringExtra("labelId"))));
finish();
return;
}
boolean connToInternet = AppUtil.haveNetworkConnection(getApplicationContext());
boolean connToInternet = AppUtil.hasNetworkConnection(appCtx);
ImageView closeActivity = findViewById(R.id.close);
colorPicker = findViewById(R.id.colorPicker);
labelName = findViewById(R.id.labelName);
createLabelButton = findViewById(R.id.createLabelButton);
ImageView closeActivity = activityCreateLabelBinding.close;
colorPicker = activityCreateLabelBinding.colorPicker;
labelName = activityCreateLabelBinding.labelName;
createLabelButton = activityCreateLabelBinding.createLabelButton;
labelName.requestFocus();
assert imm != null;
imm.showSoftInput(labelName, InputMethodManager.SHOW_IMPLICIT);
final ColorPicker cp = new ColorPicker(CreateLabelActivity.this, 235, 113, 33);
initCloseListener();
closeActivity.setOnClickListener(onClickListener);
colorPicker.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
cp.show();
}
});
colorPicker.setOnClickListener(v -> cp.show());
cp.setCallback(new ColorPickerCallback() {
@Override
public void onColorChosen(@ColorInt int color) {
cp.setCallback(color -> {
//Log.i("#Hex no alpha", String.format("#%06X", (0xFFFFFF & color)));
colorPicker.setBackgroundColor(color);
tinyDb.putString("labelColor", String.format("#%06X", (0xFFFFFF & color)));
cp.dismiss();
}
//Log.i("#Hex no alpha", String.format("#%06X", (0xFFFFFF & color)));
colorPicker.setBackgroundColor(color);
tinyDB.putString("labelColor", String.format("#%06X", (0xFFFFFF & color)));
cp.dismiss();
});
if(getIntent().getStringExtra("labelAction") != null && Objects.requireNonNull(getIntent().getStringExtra("labelAction")).equals("edit")) {
@ -101,154 +94,133 @@ public class CreateLabelActivity extends BaseActivity {
labelName.setText(getIntent().getStringExtra("labelTitle"));
int labelColor_ = Color.parseColor("#" + getIntent().getStringExtra("labelColor"));
colorPicker.setBackgroundColor(labelColor_);
tinyDb.putString("labelColorDefault", "#" + getIntent().getStringExtra("labelColor"));
tinyDB.putString("labelColorDefault", "#" + getIntent().getStringExtra("labelColor"));
TextView toolbar_title = findViewById(R.id.toolbar_title);
TextView toolbar_title = activityCreateLabelBinding.toolbarTitle;
toolbar_title.setText(getResources().getString(R.string.pageTitleLabelUpdate));
createLabelButton.setText(getResources().getString(R.string.newUpdateButtonCopy));
createLabelButton.setOnClickListener(updateLabelListener);
return;
}
if(!connToInternet) {
createLabelButton.setEnabled(false);
GradientDrawable shape = new GradientDrawable();
shape.setCornerRadius( 8 );
shape.setColor(getResources().getColor(R.color.hintColor));
createLabelButton.setBackground(shape);
} else {
}
else {
createLabelButton.setOnClickListener(createLabelListener);
}
}
private View.OnClickListener createLabelListener = new View.OnClickListener() {
public void onClick(View v) {
processCreateLabel();
}
};
private final View.OnClickListener createLabelListener = v -> processCreateLabel();
private View.OnClickListener updateLabelListener = new View.OnClickListener() {
public void onClick(View v) {
processUpdateLabel();
}
};
private final View.OnClickListener updateLabelListener = v -> processUpdateLabel();
private void processUpdateLabel() {
final TinyDB tinyDb = new TinyDB(getApplicationContext());
boolean connToInternet = AppUtil.haveNetworkConnection(getApplicationContext());
AppUtil appUtil = new AppUtil();
String repoFullName = tinyDb.getString("repoFullName");
boolean connToInternet = AppUtil.hasNetworkConnection(appCtx);
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");
String updateLabelName = labelName.getText().toString();
String updateLabelColor;
if(tinyDb.getString("labelColor").isEmpty()) {
updateLabelColor = tinyDb.getString("labelColorDefault");
if(tinyDB.getString("labelColor").isEmpty()) {
updateLabelColor = tinyDB.getString("labelColorDefault");
}
else {
updateLabelColor = tinyDb.getString("labelColor");
updateLabelColor = tinyDB.getString("labelColor");
}
if(!connToInternet) {
Toasty.info(getApplicationContext(), getResources().getString(R.string.checkNetConnection));
Toasty.error(ctx, getResources().getString(R.string.checkNetConnection));
return;
}
if(updateLabelName.equals("")) {
Toasty.info(getApplicationContext(), getString(R.string.labelEmptyError));
Toasty.error(ctx, getString(R.string.labelEmptyError));
return;
}
if(!appUtil.checkStrings(updateLabelName)) {
if(!AppUtil.checkStrings(updateLabelName)) {
Toasty.info(getApplicationContext(), getString(R.string.labelNameError));
Toasty.error(ctx, getString(R.string.labelNameError));
return;
}
disableProcessButton();
patchLabel(instanceUrl, instanceToken, repoOwner, repoName, updateLabelName, updateLabelColor, Integer.valueOf(getIntent().getStringExtra("labelId")), loginUid);
patchLabel(repoOwner, repoName, updateLabelName, updateLabelColor, Integer.parseInt(
Objects.requireNonNull(getIntent().getStringExtra("labelId"))));
}
private void processCreateLabel() {
boolean connToInternet = AppUtil.haveNetworkConnection(getApplicationContext());
AppUtil appUtil = new AppUtil();
TinyDB tinyDb = new TinyDB(getApplicationContext());
String repoFullName = tinyDb.getString("repoFullName");
boolean connToInternet = AppUtil.hasNetworkConnection(appCtx);
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");
String newLabelName = labelName.getText().toString();
String newLabelColor;
if(tinyDb.getString("labelColor").isEmpty()) {
newLabelColor = String.format("#%06X", (0xFFFFFF & ContextCompat.getColor(getApplicationContext(), R.color.releasePre)));
if(tinyDB.getString("labelColor").isEmpty()) {
newLabelColor = String.format("#%06X", (0xFFFFFF & ContextCompat.getColor(ctx, R.color.releasePre)));
}
else {
newLabelColor = tinyDb.getString("labelColor");
newLabelColor = tinyDB.getString("labelColor");
}
if(!connToInternet) {
Toasty.info(getApplicationContext(), getResources().getString(R.string.checkNetConnection));
Toasty.error(ctx, getResources().getString(R.string.checkNetConnection));
return;
}
if(newLabelName.equals("")) {
Toasty.info(getApplicationContext(), getString(R.string.labelEmptyError));
Toasty.error(ctx, getString(R.string.labelEmptyError));
return;
}
if(!appUtil.checkStrings(newLabelName)) {
if(!AppUtil.checkStrings(newLabelName)) {
Toasty.info(getApplicationContext(), getString(R.string.labelNameError));
Toasty.error(ctx, getString(R.string.labelNameError));
return;
}
disableProcessButton();
createNewLabel(instanceUrl, instanceToken, repoOwner, repoName, newLabelName, newLabelColor, loginUid);
createNewLabel(repoOwner, repoName, newLabelName, newLabelColor);
}
private void createNewLabel(final String instanceUrl, final String instanceToken, String repoOwner, String repoName, String newLabelName, String newLabelColor, String loginUid) {
private void createNewLabel(String repoOwner, String repoName, String newLabelName, String newLabelColor) {
CreateLabel createLabelFunc = new CreateLabel(newLabelName, newLabelColor);
final TinyDB tinyDb = new TinyDB(getApplicationContext());
Call<CreateLabel> call;
call = RetrofitClient
.getInstance(instanceUrl, getApplicationContext())
.getApiInterface()
.createLabel(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName, createLabelFunc);
if(getIntent().getStringExtra("type") != null && Objects.requireNonNull(getIntent().getStringExtra("type")).equals("org")) {
call = RetrofitClient.getApiInterface(ctx).createOrganizationLabel(Authorization.get(ctx), getIntent().getStringExtra("orgName"), createLabelFunc);
}
else {
call = RetrofitClient.getApiInterface(ctx).createLabel(Authorization.get(ctx), repoOwner, repoName, createLabelFunc);
}
call.enqueue(new Callback<CreateLabel>() {
@ -257,11 +229,10 @@ public class CreateLabelActivity extends BaseActivity {
if(response.code() == 201) {
Toasty.info(getApplicationContext(), getString(R.string.labelCreated));
tinyDb.putString("labelColor", "");
tinyDb.putBoolean("labelsRefresh", true);
Toasty.success(ctx, getString(R.string.labelCreated));
tinyDB.putString("labelColor", "");
tinyDB.putBoolean("labelsRefresh", true);
finish();
}
else if(response.code() == 401) {
@ -270,21 +241,19 @@ public class CreateLabelActivity extends BaseActivity {
getResources().getString(R.string.alertDialogTokenRevokedMessage),
getResources().getString(R.string.alertDialogTokenRevokedCopyNegativeButton),
getResources().getString(R.string.alertDialogTokenRevokedCopyPositiveButton));
}
else {
enableProcessButton();
tinyDb.putString("labelColor", "");
Toasty.info(getApplicationContext(), getString(R.string.labelGeneralError));
tinyDB.putString("labelColor", "");
Toasty.error(ctx, getString(R.string.labelGeneralError));
}
}
@Override
public void onFailure(@NonNull Call<CreateLabel> call, @NonNull Throwable t) {
tinyDb.putString("labelColor", "");
tinyDB.putString("labelColor", "");
Log.e("onFailure", t.toString());
enableProcessButton();
}
@ -292,17 +261,20 @@ public class CreateLabelActivity extends BaseActivity {
}
private void patchLabel(final String instanceUrl, final String instanceToken, String repoOwner, String repoName, String updateLabelName, String updateLabelColor, int labelId, String loginUid) {
private void patchLabel(String repoOwner, String repoName, String updateLabelName, String updateLabelColor, int labelId) {
CreateLabel createLabelFunc = new CreateLabel(updateLabelName, updateLabelColor);
final TinyDB tinyDb = new TinyDB(getApplicationContext());
Call<CreateLabel> call;
call = RetrofitClient
.getInstance(instanceUrl, getApplicationContext())
.getApiInterface()
.patchLabel(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName, labelId, createLabelFunc);
if(getIntent().getStringExtra("type") != null && Objects.requireNonNull(getIntent().getStringExtra("type")).equals("org")) {
call = RetrofitClient.getApiInterface(ctx).patchOrganizationLabel(Authorization.get(ctx), getIntent().getStringExtra("orgName"), labelId, createLabelFunc);
}
else {
call = RetrofitClient.getApiInterface(appCtx).patchLabel(Authorization.get(ctx), repoOwner, repoName, labelId, createLabelFunc);
}
call.enqueue(new Callback<CreateLabel>() {
@ -310,18 +282,19 @@ public class CreateLabelActivity extends BaseActivity {
public void onResponse(@NonNull Call<CreateLabel> call, @NonNull retrofit2.Response<CreateLabel> response) {
if(response.isSuccessful()) {
if(response.code() == 200) {
Toasty.info(getApplicationContext(), getString(R.string.labelUpdated));
tinyDb.putString("labelColor", "");
tinyDb.putBoolean("labelsRefresh", true);
tinyDb.putString("labelColorDefault", "");
Toasty.success(ctx, getString(R.string.labelUpdated));
tinyDB.putString("labelColor", "");
tinyDB.putBoolean("labelsRefresh", true);
tinyDB.putString("labelColorDefault", "");
getIntent().removeExtra("labelAction");
getIntent().removeExtra("labelId");
getIntent().removeExtra("labelTitle");
getIntent().removeExtra("labelColor");
getIntent().removeExtra("type");
finish();
}
}
else if(response.code() == 401) {
@ -331,23 +304,21 @@ public class CreateLabelActivity extends BaseActivity {
getResources().getString(R.string.alertDialogTokenRevokedMessage),
getResources().getString(R.string.alertDialogTokenRevokedCopyNegativeButton),
getResources().getString(R.string.alertDialogTokenRevokedCopyPositiveButton));
}
else {
enableProcessButton();
tinyDb.putString("labelColor", "");
tinyDb.putString("labelColorDefault", "");
Toasty.info(getApplicationContext(), getString(R.string.labelGeneralError));
tinyDB.putString("labelColor", "");
tinyDB.putString("labelColorDefault", "");
Toasty.error(ctx, getString(R.string.labelGeneralError));
}
}
@Override
public void onFailure(@NonNull Call<CreateLabel> call, @NonNull Throwable t) {
tinyDb.putString("labelColor", "");
tinyDb.putString("labelColorDefault", "");
tinyDB.putString("labelColor", "");
tinyDB.putString("labelColorDefault", "");
Log.e("onFailure", t.toString());
enableProcessButton();
}
@ -356,26 +327,30 @@ public class CreateLabelActivity extends BaseActivity {
}
private void initCloseListener() {
onClickListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
getIntent().removeExtra("labelAction");
getIntent().removeExtra("labelId");
getIntent().removeExtra("labelTitle");
getIntent().removeExtra("labelColor");
finish();
}
onClickListener = view -> {
getIntent().removeExtra("labelAction");
getIntent().removeExtra("labelId");
getIntent().removeExtra("labelTitle");
getIntent().removeExtra("labelColor");
getIntent().removeExtra("type");
finish();
};
}
private void deleteLabel(final String instanceUrl, final String instanceToken, final String repoOwner, final String repoName, int labelId, String loginUid) {
private void deleteLabel(final String repoOwner, final String repoName, int labelId) {
Call<Labels> call;
call = RetrofitClient
.getInstance(instanceUrl, getApplicationContext())
.getApiInterface()
.deleteLabel(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName, labelId);
if(getIntent().getStringExtra("type") != null && Objects.requireNonNull(getIntent().getStringExtra("type")).equals("org")) {
call = RetrofitClient.getApiInterface(appCtx).deleteOrganizationLabel(Authorization.get(ctx), getIntent().getStringExtra("orgName"), labelId);
}
else {
call = RetrofitClient.getApiInterface(appCtx).deleteLabel(Authorization.get(ctx), repoOwner, repoName, labelId);
}
call.enqueue(new Callback<Labels>() {
@ -383,13 +358,21 @@ public class CreateLabelActivity extends BaseActivity {
public void onResponse(@NonNull Call<Labels> call, @NonNull retrofit2.Response<Labels> response) {
if(response.isSuccessful()) {
if(response.code() == 204) {
Toasty.info(getApplicationContext(), getString(R.string.labelDeleteText));
LabelsViewModel.loadLabelsList(instanceUrl, instanceToken, repoOwner, repoName, getApplicationContext());
Toasty.success(ctx, getString(R.string.labelDeleteText));
if(getIntent().getStringExtra("type") != null && Objects.requireNonNull(getIntent().getStringExtra("type")).equals("org")) {
OrganizationLabelsViewModel.loadOrgLabelsList(Authorization.get(ctx), getIntent().getStringExtra("orgName"), ctx, null, null);
}
else {
LabelsViewModel.loadLabelsList(Authorization.get(ctx), repoOwner, repoName, ctx);
}
getIntent().removeExtra("labelAction");
getIntent().removeExtra("labelId");
getIntent().removeExtra("type");
}
}
else if(response.code() == 401) {
@ -398,14 +381,11 @@ public class CreateLabelActivity extends BaseActivity {
getResources().getString(R.string.alertDialogTokenRevokedMessage),
getResources().getString(R.string.alertDialogTokenRevokedCopyNegativeButton),
getResources().getString(R.string.alertDialogTokenRevokedCopyPositiveButton));
}
else {
Toasty.info(getApplicationContext(), getString(R.string.labelDeleteErrorText));
Toasty.error(ctx, getString(R.string.labelDeleteErrorText));
}
}
@Override
@ -419,21 +399,11 @@ public class CreateLabelActivity extends BaseActivity {
private void disableProcessButton() {
createLabelButton.setEnabled(false);
GradientDrawable shape = new GradientDrawable();
shape.setCornerRadius( 8 );
shape.setColor(getResources().getColor(R.color.hintColor));
createLabelButton.setBackground(shape);
}
private void enableProcessButton() {
createLabelButton.setEnabled(true);
GradientDrawable shape = new GradientDrawable();
shape.setCornerRadius( 8 );
shape.setColor(getResources().getColor(R.color.btnBackground));
createLabelButton.setBackground(shape);
}
}
}

View File

@ -1,58 +1,76 @@
package org.mian.gitnex.activities;
import androidx.annotation.NonNull;
import retrofit2.Call;
import retrofit2.Callback;
import android.annotation.SuppressLint;
import android.app.DatePickerDialog;
import android.content.Context;
import android.graphics.drawable.GradientDrawable;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.DatePicker;
import android.widget.EditText;
import android.widget.ImageView;
import androidx.annotation.NonNull;
import org.gitnex.tea4j.models.Milestones;
import org.mian.gitnex.R;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.databinding.ActivityCreateMilestoneBinding;
import org.mian.gitnex.helpers.AlertDialogs;
import org.mian.gitnex.helpers.AppUtil;
import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.helpers.VersionCheck;
import org.mian.gitnex.helpers.TinyDB;
import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.models.Milestones;
import org.mian.gitnex.util.AppUtil;
import org.mian.gitnex.util.TinyDB;
import org.mian.gitnex.helpers.Version;
import java.util.Calendar;
import retrofit2.Call;
import retrofit2.Callback;
/**
* Author M M Arif
*/
public class NewMilestoneActivity extends BaseActivity implements View.OnClickListener {
public class CreateMilestoneActivity extends BaseActivity implements View.OnClickListener {
private EditText milestoneDueDate;
private View.OnClickListener onClickListener;
private EditText milestoneTitle;
private EditText milestoneDescription;
private Button createNewMilestoneButton;
final Context ctx = this;
@Override
protected int getLayoutResourceId(){
return R.layout.activity_new_milestone;
}
@SuppressLint("ClickableViewAccessibility")
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
boolean connToInternet = AppUtil.haveNetworkConnection(getApplicationContext());
ActivityCreateMilestoneBinding activityCreateMilestoneBinding = ActivityCreateMilestoneBinding.inflate(getLayoutInflater());
setContentView(activityCreateMilestoneBinding.getRoot());
milestoneDueDate = findViewById(R.id.milestoneDueDate);
ImageView closeActivity = findViewById(R.id.close);
createNewMilestoneButton = findViewById(R.id.createNewMilestoneButton);
milestoneTitle = findViewById(R.id.milestoneTitle);
milestoneDescription = findViewById(R.id.milestoneDescription);
boolean connToInternet = AppUtil.hasNetworkConnection(appCtx);
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
milestoneDueDate = activityCreateMilestoneBinding.milestoneDueDate;
ImageView closeActivity = activityCreateMilestoneBinding.close;
createNewMilestoneButton = activityCreateMilestoneBinding.createNewMilestoneButton;
milestoneTitle = activityCreateMilestoneBinding.milestoneTitle;
milestoneDescription = activityCreateMilestoneBinding.milestoneDescription;
milestoneTitle.requestFocus();
assert imm != null;
imm.showSoftInput(milestoneTitle, InputMethodManager.SHOW_IMPLICIT);
milestoneDescription.setOnTouchListener((touchView, motionEvent) -> {
touchView.getParent().requestDisallowInterceptTouchEvent(true);
if ((motionEvent.getAction() & MotionEvent.ACTION_UP) != 0 && (motionEvent.getActionMasked() & MotionEvent.ACTION_UP) != 0) {
touchView.getParent().requestDisallowInterceptTouchEvent(false);
}
return false;
});
initCloseListener();
closeActivity.setOnClickListener(onClickListener);
@ -61,38 +79,25 @@ public class NewMilestoneActivity extends BaseActivity implements View.OnClickLi
if(!connToInternet) {
createNewMilestoneButton.setEnabled(false);
GradientDrawable shape = new GradientDrawable();
shape.setCornerRadius( 8 );
shape.setColor(getResources().getColor(R.color.hintColor));
createNewMilestoneButton.setBackground(shape);
} else {
}
else {
createNewMilestoneButton.setOnClickListener(createMilestoneListener);
}
}
private View.OnClickListener createMilestoneListener = new View.OnClickListener() {
public void onClick(View v) {
processNewMilestone();
}
};
private final View.OnClickListener createMilestoneListener = v -> processNewMilestone();
private void processNewMilestone() {
boolean connToInternet = AppUtil.haveNetworkConnection(getApplicationContext());
AppUtil appUtil = new AppUtil();
TinyDB tinyDb = new TinyDB(getApplicationContext());
boolean connToInternet = AppUtil.hasNetworkConnection(appCtx);
TinyDB tinyDb = TinyDB.getInstance(appCtx);
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");
//String appLocale = tinyDb.getString("locale");
String newMilestoneTitle = milestoneTitle.getText().toString();
String newMilestoneDescription = milestoneDescription.getText().toString();
@ -100,50 +105,50 @@ public class NewMilestoneActivity extends BaseActivity implements View.OnClickLi
if(!connToInternet) {
Toasty.info(getApplicationContext(), getResources().getString(R.string.checkNetConnection));
Toasty.error(ctx, getResources().getString(R.string.checkNetConnection));
return;
}
if(newMilestoneTitle.equals("")) {
Toasty.info(getApplicationContext(), getString(R.string.milestoneNameErrorEmpty));
Toasty.error(ctx, getString(R.string.milestoneNameErrorEmpty));
return;
}
if(!newMilestoneDescription.equals("")) {
if (appUtil.charactersLength(newMilestoneDescription) > 255) {
Toasty.info(getApplicationContext(), getString(R.string.milestoneDescError));
if (newMilestoneDescription.length() > 255) {
Toasty.warning(ctx, getString(R.string.milestoneDescError));
return;
}
}
String finalMilestoneDueDate = null;
if(!newMilestoneDueDate.isEmpty()) {
finalMilestoneDueDate = (AppUtil.customDateCombine(AppUtil.customDateFormat(newMilestoneDueDate)));
} else if (VersionCheck.compareVersion("1.10.0", tinyDb.getString("giteaVersion")) > 1) {
}
else if (new Version(tinyDb.getString("giteaVersion")).less("1.10.0")) {
// if Gitea version is less than 1.10.0 DueDate is required
Toasty.info(getApplicationContext(), getString(R.string.milestoneDateEmpty));
Toasty.warning(ctx, getString(R.string.milestoneDateEmpty));
return;
}
disableProcessButton();
createNewMilestone(instanceUrl, Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName, newMilestoneTitle, newMilestoneDescription, finalMilestoneDueDate);
createNewMilestone(Authorization.get(ctx), repoOwner, repoName, newMilestoneTitle, newMilestoneDescription, finalMilestoneDueDate);
}
private void createNewMilestone(final String instanceUrl, final String token, String repoOwner, String repoName, String newMilestoneTitle, String newMilestoneDescription, String newMilestoneDueDate) {
private void createNewMilestone(final String token, String repoOwner, String repoName, String newMilestoneTitle, String newMilestoneDescription, String newMilestoneDueDate) {
Milestones createMilestone = new Milestones(newMilestoneDescription, newMilestoneTitle, newMilestoneDueDate);
Call<Milestones> call;
call = RetrofitClient
.getInstance(instanceUrl, getApplicationContext())
.getApiInterface()
.getApiInterface(appCtx)
.createMilestone(token, repoOwner, repoName, createMilestone);
call.enqueue(new Callback<Milestones>() {
@ -152,14 +157,14 @@ public class NewMilestoneActivity extends BaseActivity implements View.OnClickLi
public void onResponse(@NonNull Call<Milestones> call, @NonNull retrofit2.Response<Milestones> response) {
if(response.isSuccessful()) {
if(response.code() == 201) {
TinyDB tinyDb = new TinyDB(getApplicationContext());
TinyDB tinyDb = TinyDB.getInstance(appCtx);
tinyDb.putBoolean("milestoneCreated", true);
Toasty.info(getApplicationContext(), getString(R.string.milestoneCreated));
Toasty.success(ctx, getString(R.string.milestoneCreated));
enableProcessButton();
finish();
}
}
else if(response.code() == 401) {
@ -169,19 +174,17 @@ public class NewMilestoneActivity extends BaseActivity implements View.OnClickLi
getResources().getString(R.string.alertDialogTokenRevokedMessage),
getResources().getString(R.string.alertDialogTokenRevokedCopyNegativeButton),
getResources().getString(R.string.alertDialogTokenRevokedCopyPositiveButton));
}
else {
enableProcessButton();
Toasty.info(getApplicationContext(), getString(R.string.milestoneCreatedError));
Toasty.error(ctx, getString(R.string.milestoneCreatedError));
}
}
@Override
public void onFailure(@NonNull Call<Milestones> call, @NonNull Throwable t) {
Log.e("onFailure", t.toString());
enableProcessButton();
}
@ -200,48 +203,25 @@ public class NewMilestoneActivity extends BaseActivity implements View.OnClickLi
final int mDay = c.get(Calendar.DAY_OF_MONTH);
DatePickerDialog datePickerDialog = new DatePickerDialog(this,
new DatePickerDialog.OnDateSetListener() {
@Override
public void onDateSet(DatePicker view, int year,
int monthOfYear, int dayOfMonth) {
milestoneDueDate.setText(getString(R.string.setDueDate, year, (monthOfYear + 1), dayOfMonth));
}
}, mYear, mMonth, mDay);
(view, year, monthOfYear, dayOfMonth) -> milestoneDueDate.setText(getString(R.string.setDueDate, year, (monthOfYear + 1), dayOfMonth)), mYear, mMonth, mDay);
datePickerDialog.show();
}
}
private void initCloseListener() {
onClickListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
finish();
}
};
onClickListener = view -> finish();
}
private void disableProcessButton() {
createNewMilestoneButton.setEnabled(false);
GradientDrawable shape = new GradientDrawable();
shape.setCornerRadius( 8 );
shape.setColor(getResources().getColor(R.color.hintColor));
createNewMilestoneButton.setBackground(shape);
}
private void enableProcessButton() {
createNewMilestoneButton.setEnabled(true);
GradientDrawable shape = new GradientDrawable();
shape.setCornerRadius( 8 );
shape.setColor(getResources().getColor(R.color.btnBackground));
createNewMilestoneButton.setBackground(shape);
}
}

View File

@ -1,25 +1,25 @@
package org.mian.gitnex.activities;
import androidx.annotation.NonNull;
import retrofit2.Call;
import retrofit2.Callback;
import android.content.Context;
import android.graphics.drawable.GradientDrawable;
import android.os.Bundle;
import android.util.Log;
import android.util.Patterns;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import androidx.annotation.NonNull;
import org.gitnex.tea4j.models.UserInfo;
import org.mian.gitnex.R;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.databinding.ActivityCreateNewUserBinding;
import org.mian.gitnex.helpers.AlertDialogs;
import org.mian.gitnex.helpers.AppUtil;
import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.models.UserInfo;
import org.mian.gitnex.util.AppUtil;
import org.mian.gitnex.util.TinyDB;
import retrofit2.Call;
import retrofit2.Callback;
/**
* Author M M Arif
@ -33,26 +33,29 @@ public class CreateNewUserActivity extends BaseActivity {
private EditText userEmail;
private EditText userPassword;
private Button createUserButton;
final Context ctx = this;
@Override
protected int getLayoutResourceId(){
return R.layout.activity_create_new_user;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
boolean connToInternet = AppUtil.haveNetworkConnection(getApplicationContext());
ActivityCreateNewUserBinding activityCreateNewUserBinding = ActivityCreateNewUserBinding.inflate(getLayoutInflater());
setContentView(activityCreateNewUserBinding.getRoot());
ImageView closeActivity = findViewById(R.id.close);
createUserButton = findViewById(R.id.createUserButton);
fullName = findViewById(R.id.fullName);
userUserName = findViewById(R.id.userUserName);
userEmail = findViewById(R.id.userEmail);
userPassword = findViewById(R.id.userPassword);
boolean connToInternet = AppUtil.hasNetworkConnection(appCtx);
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
ImageView closeActivity = activityCreateNewUserBinding.close;
createUserButton = activityCreateNewUserBinding.createUserButton;
fullName = activityCreateNewUserBinding.fullName;
userUserName = activityCreateNewUserBinding.userUserName;
userEmail = activityCreateNewUserBinding.userEmail;
userPassword = activityCreateNewUserBinding.userPassword;
fullName.requestFocus();
assert imm != null;
imm.showSoftInput(fullName, InputMethodManager.SHOW_IMPLICIT);
initCloseListener();
closeActivity.setOnClickListener(onClickListener);
@ -60,23 +63,16 @@ public class CreateNewUserActivity extends BaseActivity {
if(!connToInternet) {
disableProcessButton();
} else {
}
else {
createUserButton.setOnClickListener(createNewUserListener);
}
}
private void processCreateNewUser() {
boolean connToInternet = AppUtil.haveNetworkConnection(getApplicationContext());
AppUtil appUtil = new AppUtil();
TinyDB tinyDb = new TinyDB(getApplicationContext());
final String instanceUrl = tinyDb.getString("instanceUrl");
final String loginUid = tinyDb.getString("loginUid");
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
boolean connToInternet = AppUtil.hasNetworkConnection(appCtx);
String newFullName = fullName.getText().toString().trim();
String newUserName = userUserName.getText().toString().trim();
@ -85,53 +81,46 @@ public class CreateNewUserActivity extends BaseActivity {
if(!connToInternet) {
Toasty.info(getApplicationContext(), getResources().getString(R.string.checkNetConnection));
Toasty.error(ctx, getResources().getString(R.string.checkNetConnection));
return;
}
if(newFullName.equals("") || newUserName.equals("") | newUserEmail.equals("") || newUserPassword.equals("")) {
Toasty.info(getApplicationContext(), getString(R.string.emptyFields));
Toasty.error(ctx, getString(R.string.emptyFields));
return;
}
if(!appUtil.checkStrings(newFullName)) {
if(!AppUtil.checkStrings(newFullName)) {
Toasty.info(getApplicationContext(), getString(R.string.userInvalidFullName));
Toasty.error(ctx, getString(R.string.userInvalidFullName));
return;
}
if(!appUtil.checkStringsWithAlphaNumeric(newUserName)) {
if(!AppUtil.checkStringsWithAlphaNumeric(newUserName)) {
Toasty.info(getApplicationContext(), getString(R.string.userInvalidUserName));
Toasty.error(ctx, getString(R.string.userInvalidUserName));
return;
}
if(!Patterns.EMAIL_ADDRESS.matcher(newUserEmail).matches()) {
Toasty.info(getApplicationContext(), getString(R.string.userInvalidEmail));
Toasty.error(ctx, getString(R.string.userInvalidEmail));
return;
}
disableProcessButton();
createNewUser(instanceUrl, Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), newFullName, newUserName, newUserEmail, newUserPassword);
createNewUser(Authorization.get(ctx), newFullName, newUserName, newUserEmail, newUserPassword);
}
private void createNewUser(final String instanceUrl, final String instanceToken, String newFullName, String newUserName, String newUserEmail, String newUserPassword) {
private void createNewUser(final String instanceToken, String newFullName, String newUserName, String newUserEmail, String newUserPassword) {
UserInfo createUser = new UserInfo(newUserEmail, newFullName, newUserName, newUserPassword, newUserName, 0, true);
Call<UserInfo> call;
call = RetrofitClient
.getInstance(instanceUrl, getApplicationContext())
.getApiInterface()
.getApiInterface(appCtx)
.createNewUser(instanceToken, createUser);
call.enqueue(new Callback<UserInfo>() {
@ -141,10 +130,9 @@ public class CreateNewUserActivity extends BaseActivity {
if(response.code() == 201) {
Toasty.info(getApplicationContext(), getString(R.string.userCreatedText));
Toasty.success(ctx, getString(R.string.userCreatedText));
enableProcessButton();
finish();
}
else if(response.code() == 401) {
@ -153,37 +141,32 @@ public class CreateNewUserActivity extends BaseActivity {
getResources().getString(R.string.alertDialogTokenRevokedMessage),
getResources().getString(R.string.alertDialogTokenRevokedCopyNegativeButton),
getResources().getString(R.string.alertDialogTokenRevokedCopyPositiveButton));
}
else if(response.code() == 403) {
enableProcessButton();
Toasty.info(ctx, ctx.getString(R.string.authorizeError));
Toasty.error(ctx, ctx.getString(R.string.authorizeError));
}
else if(response.code() == 404) {
enableProcessButton();
Toasty.info(ctx, ctx.getString(R.string.apiNotFound));
Toasty.warning(ctx, ctx.getString(R.string.apiNotFound));
}
else if(response.code() == 422) {
enableProcessButton();
Toasty.info(ctx, ctx.getString(R.string.userExistsError));
Toasty.warning(ctx, ctx.getString(R.string.userExistsError));
}
else {
enableProcessButton();
Toasty.info(getApplicationContext(), getString(R.string.genericError));
Toasty.error(ctx, getString(R.string.genericError));
}
}
@Override
public void onFailure(@NonNull Call<UserInfo> call, @NonNull Throwable t) {
Log.e("onFailure", t.toString());
enableProcessButton();
}
@ -191,39 +174,21 @@ public class CreateNewUserActivity extends BaseActivity {
}
private View.OnClickListener createNewUserListener = new View.OnClickListener() {
public void onClick(View v) {
processCreateNewUser();
}
};
private final View.OnClickListener createNewUserListener = v -> processCreateNewUser();
private void initCloseListener() {
onClickListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
finish();
}
};
onClickListener = view -> finish();
}
private void disableProcessButton() {
createUserButton.setEnabled(false);
GradientDrawable shape = new GradientDrawable();
shape.setCornerRadius( 8 );
shape.setColor(getResources().getColor(R.color.hintColor));
createUserButton.setBackground(shape);
}
private void enableProcessButton() {
createUserButton.setEnabled(true);
GradientDrawable shape = new GradientDrawable();
shape.setCornerRadius( 8 );
shape.setColor(getResources().getColor(R.color.btnBackground));
createUserButton.setBackground(shape);
}
}

View File

@ -1,22 +1,25 @@
package org.mian.gitnex.activities;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.drawable.GradientDrawable;
import android.os.Bundle;
import androidx.annotation.NonNull;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import androidx.annotation.NonNull;
import org.gitnex.tea4j.models.UserOrganizations;
import org.mian.gitnex.R;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.databinding.ActivityCreateOrganizationBinding;
import org.mian.gitnex.helpers.AlertDialogs;
import org.mian.gitnex.helpers.AppUtil;
import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.helpers.TinyDB;
import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.models.UserOrganizations;
import org.mian.gitnex.util.AppUtil;
import org.mian.gitnex.util.TinyDB;
import retrofit2.Call;
import retrofit2.Callback;
@ -24,7 +27,7 @@ import retrofit2.Callback;
* Author M M Arif
*/
public class NewOrganizationActivity extends BaseActivity {
public class CreateOrganizationActivity extends BaseActivity {
public ImageView closeActivity;
private View.OnClickListener onClickListener;
@ -32,113 +35,106 @@ public class NewOrganizationActivity extends BaseActivity {
private EditText orgName;
private EditText orgDesc;
final Context ctx = this;
@Override
protected int getLayoutResourceId(){
return R.layout.activity_new_organization;
}
@SuppressLint("ClickableViewAccessibility")
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
boolean connToInternet = AppUtil.haveNetworkConnection(getApplicationContext());
ActivityCreateOrganizationBinding activityCreateOrganizationBinding = ActivityCreateOrganizationBinding.inflate(getLayoutInflater());
setContentView(activityCreateOrganizationBinding.getRoot());
closeActivity = findViewById(R.id.close);
orgName = findViewById(R.id.newOrganizationName);
orgDesc = findViewById(R.id.newOrganizationDescription);
boolean connToInternet = AppUtil.hasNetworkConnection(appCtx);
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
closeActivity = activityCreateOrganizationBinding.close;
orgName = activityCreateOrganizationBinding.newOrganizationName;
orgDesc = activityCreateOrganizationBinding.newOrganizationDescription;
orgName.requestFocus();
assert imm != null;
imm.showSoftInput(orgName, InputMethodManager.SHOW_IMPLICIT);
orgDesc.setOnTouchListener((touchView, motionEvent) -> {
touchView.getParent().requestDisallowInterceptTouchEvent(true);
if ((motionEvent.getAction() & MotionEvent.ACTION_UP) != 0 && (motionEvent.getActionMasked() & MotionEvent.ACTION_UP) != 0) {
touchView.getParent().requestDisallowInterceptTouchEvent(false);
}
return false;
});
initCloseListener();
closeActivity.setOnClickListener(onClickListener);
createOrganizationButton = findViewById(R.id.createNewOrganizationButton);
createOrganizationButton = activityCreateOrganizationBinding.createNewOrganizationButton;
if(!connToInternet) {
createOrganizationButton.setEnabled(false);
GradientDrawable shape = new GradientDrawable();
shape.setCornerRadius( 8 );
shape.setColor(getResources().getColor(R.color.hintColor));
createOrganizationButton.setBackground(shape);
} else {
}
else {
createOrganizationButton.setOnClickListener(createOrgListener);
}
}
private void initCloseListener() {
onClickListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
finish();
}
};
onClickListener = view -> finish();
}
private View.OnClickListener createOrgListener = new View.OnClickListener() {
public void onClick(View v) {
processNewOrganization();
}
};
private final View.OnClickListener createOrgListener = v -> processNewOrganization();
private void processNewOrganization() {
boolean connToInternet = AppUtil.haveNetworkConnection(getApplicationContext());
AppUtil appUtil = new AppUtil();
TinyDB tinyDb = new TinyDB(getApplicationContext());
final String instanceUrl = tinyDb.getString("instanceUrl");
final String loginUid = tinyDb.getString("loginUid");
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
boolean connToInternet = AppUtil.hasNetworkConnection(appCtx);
String newOrgName = orgName.getText().toString();
String newOrgDesc = orgDesc.getText().toString();
if(!connToInternet) {
Toasty.info(getApplicationContext(), getResources().getString(R.string.checkNetConnection));
Toasty.error(ctx, getResources().getString(R.string.checkNetConnection));
return;
}
if(!newOrgDesc.equals("")) {
if (appUtil.charactersLength(newOrgDesc) > 255) {
Toasty.info(getApplicationContext(), getString(R.string.orgDescError));
if (newOrgDesc.length() > 255) {
Toasty.warning(ctx, getString(R.string.orgDescError));
return;
}
}
if(newOrgName.equals("")) {
Toasty.info(getApplicationContext(), getString(R.string.orgNameErrorEmpty));
Toasty.error(ctx, getString(R.string.orgNameErrorEmpty));
}
else if(!appUtil.checkStrings(newOrgName)) {
Toasty.info(getApplicationContext(), getString(R.string.orgNameErrorInvalid));
else if(!AppUtil.checkStrings(newOrgName)) {
Toasty.warning(ctx, getString(R.string.orgNameErrorInvalid));
}
else {
disableProcessButton();
createNewOrganization(instanceUrl, Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), newOrgName, newOrgDesc);
createNewOrganization(Authorization.get(ctx), newOrgName, newOrgDesc);
}
}
private void createNewOrganization(final String instanceUrl, final String token, String orgName, String orgDesc) {
private void createNewOrganization(final String token, String orgName, String orgDesc) {
UserOrganizations createOrganization = new UserOrganizations(orgName, null, orgDesc, null, null);
Call<UserOrganizations> call = RetrofitClient
.getInstance(instanceUrl, getApplicationContext())
.getApiInterface()
.getApiInterface(appCtx)
.createNewOrganization(token, createOrganization);
call.enqueue(new Callback<UserOrganizations>() {
@ -148,12 +144,11 @@ public class NewOrganizationActivity extends BaseActivity {
if(response.code() == 201) {
TinyDB tinyDb = new TinyDB(getApplicationContext());
TinyDB tinyDb = TinyDB.getInstance(appCtx);
tinyDb.putBoolean("orgCreated", true);
enableProcessButton();
Toasty.info(getApplicationContext(), getString(R.string.orgCreated));
Toasty.success(ctx, getString(R.string.orgCreated));
finish();
}
else if(response.code() == 401) {
@ -162,37 +157,35 @@ public class NewOrganizationActivity extends BaseActivity {
getResources().getString(R.string.alertDialogTokenRevokedMessage),
getResources().getString(R.string.alertDialogTokenRevokedCopyNegativeButton),
getResources().getString(R.string.alertDialogTokenRevokedCopyPositiveButton));
}
else if(response.code() == 409) {
enableProcessButton();
Toasty.info(getApplicationContext(), getString(R.string.orgExistsError));
Toasty.warning(ctx, getString(R.string.orgExistsError));
}
else if(response.code() == 422) {
enableProcessButton();
Toasty.info(getApplicationContext(), getString(R.string.orgExistsError));
Toasty.warning(ctx, getString(R.string.orgExistsError));
}
else {
if(response.code() == 404) {
enableProcessButton();
Toasty.info(getApplicationContext(), getString(R.string.apiNotFound));
Toasty.warning(ctx, getString(R.string.apiNotFound));
}
else {
enableProcessButton();
Toasty.info(getApplicationContext(), getString(R.string.orgCreatedError));
Toasty.error(ctx, getString(R.string.orgCreatedError));
}
}
}
@Override
public void onFailure(@NonNull Call<UserOrganizations> call, @NonNull Throwable t) {
Log.e("onFailure", t.toString());
enableProcessButton();
}
@ -203,21 +196,11 @@ public class NewOrganizationActivity extends BaseActivity {
private void disableProcessButton() {
createOrganizationButton.setEnabled(false);
GradientDrawable shape = new GradientDrawable();
shape.setCornerRadius( 8 );
shape.setColor(getResources().getColor(R.color.hintColor));
createOrganizationButton.setBackground(shape);
}
private void enableProcessButton() {
createOrganizationButton.setEnabled(true);
GradientDrawable shape = new GradientDrawable();
shape.setCornerRadius( 8 );
shape.setColor(getResources().getColor(R.color.btnBackground));
createOrganizationButton.setBackground(shape);
}
}

View File

@ -0,0 +1,373 @@
package org.mian.gitnex.activities;
import android.annotation.SuppressLint;
import android.app.DatePickerDialog;
import android.app.Dialog;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import androidx.annotation.NonNull;
import org.gitnex.tea4j.models.Branches;
import org.gitnex.tea4j.models.CreatePullRequest;
import org.gitnex.tea4j.models.Labels;
import org.gitnex.tea4j.models.Milestones;
import org.mian.gitnex.R;
import org.mian.gitnex.actions.LabelsActions;
import org.mian.gitnex.adapters.LabelsListAdapter;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.databinding.ActivityCreatePrBinding;
import org.mian.gitnex.databinding.CustomLabelsSelectionDialogBinding;
import org.mian.gitnex.helpers.AppUtil;
import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.helpers.Constants;
import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.helpers.Version;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
/**
* Author M M Arif
*/
public class CreatePullRequestActivity extends BaseActivity implements LabelsListAdapter.LabelsListAdapterListener {
private View.OnClickListener onClickListener;
private ActivityCreatePrBinding viewBinding;
private CustomLabelsSelectionDialogBinding labelsBinding;
private int resultLimit = Constants.resultLimitOldGiteaInstances;
private Dialog dialogLabels;
private String labelsSetter;
private List<Integer> labelsIds = new ArrayList<>();
private List<String> assignees = new ArrayList<>();
private int milestoneId;
private String loginUid;
private String instanceToken;
private String repoOwner;
private String repoName;
private LabelsListAdapter labelsAdapter;
List<Milestones> milestonesList = new ArrayList<>();
List<Branches> branchesList = new ArrayList<>();
List<Labels> labelsList = new ArrayList<>();
@SuppressLint("ClickableViewAccessibility")
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
viewBinding = ActivityCreatePrBinding.inflate(getLayoutInflater());
setContentView(viewBinding.getRoot());
loginUid = tinyDB.getString("loginUid");
String repoFullName = tinyDB.getString("repoFullName");
String[] parts = repoFullName.split("/");
repoOwner = parts[0];
repoName = parts[1];
instanceToken = "token " + tinyDB.getString(loginUid + "-token");
// require gitea 1.12 or higher
if(new Version(tinyDB.getString("giteaVersion")).higherOrEqual("1.12.0")) {
resultLimit = Constants.resultLimitNewGiteaInstances;
}
viewBinding.prBody.setOnTouchListener((touchView, motionEvent) -> {
touchView.getParent().requestDisallowInterceptTouchEvent(true);
if ((motionEvent.getAction() & MotionEvent.ACTION_UP) != 0 && (motionEvent.getActionMasked() & MotionEvent.ACTION_UP) != 0) {
touchView.getParent().requestDisallowInterceptTouchEvent(false);
}
return false;
});
labelsAdapter = new LabelsListAdapter(labelsList, CreatePullRequestActivity.this, labelsIds);
ImageView closeActivity = findViewById(R.id.close);
initCloseListener();
closeActivity.setOnClickListener(onClickListener);
viewBinding.prDueDate.setOnClickListener(dueDate ->
setDueDate()
);
disableProcessButton();
getMilestones(repoOwner, repoName, resultLimit);
getBranches(repoOwner, repoName);
viewBinding.prLabels.setOnClickListener(prLabels -> showLabels());
viewBinding.createPr.setOnClickListener(createPr -> processPullRequest());
}
private void processPullRequest() {
String prTitle = String.valueOf(viewBinding.prTitle.getText());
String prDescription = String.valueOf(viewBinding.prBody.getText());
String mergeInto = viewBinding.mergeIntoBranchSpinner.getText().toString();
String pullFrom = viewBinding.pullFromBranchSpinner.getText().toString();
String dueDate = String.valueOf(viewBinding.prDueDate.getText());
assignees.add("");
if (labelsIds.size() == 0) {
labelsIds.add(0);
}
if (dueDate.matches("")) {
dueDate = null;
}
else {
dueDate = AppUtil.customDateCombine(AppUtil.customDateFormat(dueDate));
}
if(prTitle.matches("")) {
Toasty.error(ctx, getString(R.string.titleError));
}
else if(mergeInto.matches("")) {
Toasty.error(ctx, getString(R.string.mergeIntoError));
}
else if(pullFrom.matches("")) {
Toasty.error(ctx, getString(R.string.pullFromError));
}
else if(pullFrom.equals(mergeInto)) {
Toasty.error(ctx, getString(R.string.sameBranchesError));
}
else {
createPullRequest(prTitle, prDescription, mergeInto, pullFrom, milestoneId, dueDate, assignees);
}
}
private void createPullRequest(String prTitle, String prDescription, String mergeInto, String pullFrom, int milestoneId, String dueDate, List<String> assignees) {
CreatePullRequest createPullRequest = new CreatePullRequest(prTitle, prDescription, loginUid, mergeInto, pullFrom, milestoneId, dueDate, assignees, labelsIds);
Call<Void> transferCall = RetrofitClient
.getApiInterface(appCtx)
.createPullRequest(instanceToken, repoOwner, repoName, createPullRequest);
transferCall.enqueue(new Callback<Void>() {
@Override
public void onResponse(@NonNull Call<Void> call, @NonNull retrofit2.Response<Void> response) {
disableProcessButton();
if (response.code() == 201) {
Toasty.success(ctx, getString(R.string.prCreateSuccess));
finish();
}
else if (response.code() == 409 && response.message().equals("Conflict")) {
enableProcessButton();
Toasty.error(ctx, getString(R.string.prAlreadyExists));
}
else if (response.code() == 404) {
enableProcessButton();
Toasty.error(ctx, getString(R.string.apiNotFound));
}
else {
enableProcessButton();
Toasty.error(ctx, getString(R.string.genericError));
}
}
@Override
public void onFailure(@NonNull Call<Void> call, @NonNull Throwable t) {
enableProcessButton();
Toasty.error(ctx, getString(R.string.genericServerResponseError));
}
});
}
@Override
public void labelsInterface(List<String> data) {
labelsSetter = String.valueOf(data);
viewBinding.prLabels.setText(labelsSetter.replace("]", "").replace("[", ""));
}
@Override
public void labelsIdsInterface(List<Integer> data) {
labelsIds = data;
}
private void showLabels() {
dialogLabels = new Dialog(ctx, R.style.ThemeOverlay_MaterialComponents_Dialog_Alert);
if (dialogLabels.getWindow() != null) {
dialogLabels.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
}
labelsBinding = CustomLabelsSelectionDialogBinding.inflate(LayoutInflater.from(ctx));
View view = labelsBinding.getRoot();
dialogLabels.setContentView(view);
labelsBinding.cancel.setOnClickListener(editProperties -> dialogLabels.dismiss());
dialogLabels.show();
LabelsActions.getRepositoryLabels(ctx, repoOwner, repoName, labelsList, dialogLabels, labelsAdapter, labelsBinding);
}
private void getBranches(String repoOwner, String repoName) {
Call<List<Branches>> call = RetrofitClient
.getApiInterface(ctx)
.getBranches(Authorization.get(ctx), repoOwner, repoName);
call.enqueue(new Callback<List<Branches>>() {
@Override
public void onResponse(@NonNull Call<List<Branches>> call, @NonNull retrofit2.Response<List<Branches>> response) {
if(response.isSuccessful()) {
if(response.code() == 200) {
List<Branches> branchesList_ = response.body();
assert branchesList_ != null;
if(branchesList_.size() > 0) {
for (int i = 0; i < branchesList_.size(); i++) {
Branches data = new Branches(branchesList_.get(i).getName());
branchesList.add(data);
}
}
ArrayAdapter<Branches> adapter = new ArrayAdapter<>(CreatePullRequestActivity.this,
R.layout.list_spinner_items, branchesList);
viewBinding.mergeIntoBranchSpinner.setAdapter(adapter);
viewBinding.pullFromBranchSpinner.setAdapter(adapter);
enableProcessButton();
}
}
}
@Override
public void onFailure(@NonNull Call<List<Branches>> call, @NonNull Throwable t) {
Toasty.error(ctx, getString(R.string.genericServerResponseError));
}
});
}
private void getMilestones(String repoOwner, String repoName, int resultLimit) {
String msState = "open";
Call<List<Milestones>> call = RetrofitClient
.getApiInterface(appCtx)
.getMilestones(Authorization.get(ctx), repoOwner, repoName, 1, resultLimit, msState);
call.enqueue(new Callback<List<Milestones>>() {
@Override
public void onResponse(@NonNull Call<List<Milestones>> call, @NonNull retrofit2.Response<List<Milestones>> response) {
if(response.code() == 200) {
List<Milestones> milestonesList_ = response.body();
milestonesList.add(new Milestones(0,getString(R.string.issueCreatedNoMilestone)));
assert milestonesList_ != null;
if(milestonesList_.size() > 0) {
for (int i = 0; i < milestonesList_.size(); i++) {
//Don't translate "open" is a enum
if(milestonesList_.get(i).getState().equals("open")) {
Milestones data = new Milestones(
milestonesList_.get(i).getId(),
milestonesList_.get(i).getTitle()
);
milestonesList.add(data);
}
}
}
ArrayAdapter<Milestones> adapter = new ArrayAdapter<>(CreatePullRequestActivity.this,
R.layout.list_spinner_items, milestonesList);
viewBinding.milestonesSpinner.setAdapter(adapter);
enableProcessButton();
viewBinding.milestonesSpinner.setOnItemClickListener ((parent, view, position, id) ->
milestoneId = milestonesList.get(position).getId()
);
}
}
@Override
public void onFailure(@NonNull Call<List<Milestones>> call, @NonNull Throwable t) {
Toasty.error(ctx, getString(R.string.genericServerResponseError));
}
});
}
private void setDueDate() {
final Calendar c = Calendar.getInstance();
int mYear = c.get(Calendar.YEAR);
final int mMonth = c.get(Calendar.MONTH);
final int mDay = c.get(Calendar.DAY_OF_MONTH);
DatePickerDialog datePickerDialog = new DatePickerDialog(this,
(view, year, monthOfYear, dayOfMonth) -> viewBinding.prDueDate.setText(getString(R.string.setDueDate, year, (monthOfYear + 1), dayOfMonth)), mYear, mMonth, mDay);
datePickerDialog.show();
}
private void initCloseListener() {
onClickListener = view -> finish();
}
private void disableProcessButton() {
viewBinding.createPr.setEnabled(false);
}
private void enableProcessButton() {
viewBinding.createPr.setEnabled(true);
}
}

View File

@ -1,32 +1,32 @@
package org.mian.gitnex.activities;
import androidx.annotation.NonNull;
import retrofit2.Call;
import retrofit2.Callback;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.PorterDuff;
import android.graphics.drawable.GradientDrawable;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.AdapterView;
import android.view.inputmethod.InputMethodManager;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.Spinner;
import androidx.annotation.NonNull;
import org.gitnex.tea4j.models.Branches;
import org.gitnex.tea4j.models.Releases;
import org.mian.gitnex.R;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.databinding.ActivityCreateReleaseBinding;
import org.mian.gitnex.helpers.AlertDialogs;
import org.mian.gitnex.helpers.AppUtil;
import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.models.Branches;
import org.mian.gitnex.models.Releases;
import org.mian.gitnex.util.AppUtil;
import org.mian.gitnex.util.TinyDB;
import java.util.ArrayList;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
/**
* Author M M Arif
@ -37,138 +37,128 @@ public class CreateReleaseActivity extends BaseActivity {
private View.OnClickListener onClickListener;
public ImageView closeActivity;
private EditText releaseTagName;
private Spinner releaseBranch;
private AutoCompleteTextView releaseBranch;
private EditText releaseTitle;
private EditText releaseContent;
private CheckBox releaseType;
private CheckBox releaseDraft;
private Button createNewRelease;
final Context ctx = this;
private String selectedBranch;
private String repoOwner;
private String repoName;
List<Branches> branchesList = new ArrayList<>();
@Override
protected int getLayoutResourceId(){
return R.layout.activity_create_release;
}
@SuppressLint("ClickableViewAccessibility")
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
boolean connToInternet = AppUtil.haveNetworkConnection(getApplicationContext());
ActivityCreateReleaseBinding activityCreateReleaseBinding = ActivityCreateReleaseBinding.inflate(getLayoutInflater());
setContentView(activityCreateReleaseBinding.getRoot());
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");
boolean connToInternet = AppUtil.hasNetworkConnection(appCtx);
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
String repoFullName = tinyDB.getString("repoFullName");
String[] parts = repoFullName.split("/");
final String repoOwner = parts[0];
final String repoName = parts[1];
repoOwner = parts[0];
repoName = parts[1];
closeActivity = findViewById(R.id.close);
releaseTagName = findViewById(R.id.releaseTagName);
releaseTitle = findViewById(R.id.releaseTitle);
releaseContent = findViewById(R.id.releaseContent);
releaseType = findViewById(R.id.releaseType);
releaseDraft = findViewById(R.id.releaseDraft);
closeActivity = activityCreateReleaseBinding.close;
releaseTagName = activityCreateReleaseBinding.releaseTagName;
releaseTitle = activityCreateReleaseBinding.releaseTitle;
releaseContent = activityCreateReleaseBinding.releaseContent;
releaseType = activityCreateReleaseBinding.releaseType;
releaseDraft = activityCreateReleaseBinding.releaseDraft;
releaseTitle.requestFocus();
assert imm != null;
imm.showSoftInput(releaseTitle, InputMethodManager.SHOW_IMPLICIT);
releaseContent.setOnTouchListener((touchView, motionEvent) -> {
touchView.getParent().requestDisallowInterceptTouchEvent(true);
if ((motionEvent.getAction() & MotionEvent.ACTION_UP) != 0 && (motionEvent.getActionMasked() & MotionEvent.ACTION_UP) != 0) {
touchView.getParent().requestDisallowInterceptTouchEvent(false);
}
return false;
});
initCloseListener();
closeActivity.setOnClickListener(onClickListener);
releaseBranch = findViewById(R.id.releaseBranch);
releaseBranch.getBackground().setColorFilter(getResources().getColor(R.color.white), PorterDuff.Mode.SRC_ATOP);
getBranches(instanceUrl, Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName);
releaseBranch.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
Branches branch = (Branches) parent.getSelectedItem();
}
releaseBranch = activityCreateReleaseBinding.releaseBranch;
getBranches(Authorization.get(ctx), repoOwner, repoName);
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
createNewRelease = findViewById(R.id.createNewRelease);
createNewRelease = activityCreateReleaseBinding.createNewRelease;
disableProcessButton();
if(!connToInternet) {
disableProcessButton();
} else {
}
else {
createNewRelease.setOnClickListener(createReleaseListener);
}
}
private View.OnClickListener createReleaseListener = new View.OnClickListener() {
public void onClick(View v) {
processNewRelease();
}
};
private final View.OnClickListener createReleaseListener = v -> processNewRelease();
private void processNewRelease() {
boolean connToInternet = AppUtil.haveNetworkConnection(getApplicationContext());
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];
boolean connToInternet = AppUtil.hasNetworkConnection(appCtx);
String newReleaseTagName = releaseTagName.getText().toString();
String newReleaseTitle = releaseTitle.getText().toString();
String newReleaseContent = releaseContent.getText().toString();
String newReleaseBranch = releaseBranch.getSelectedItem().toString();
String checkBranch = selectedBranch;
boolean newReleaseType = releaseType.isChecked();
boolean newReleaseDraft = releaseDraft.isChecked();
if(!connToInternet) {
Toasty.info(getApplicationContext(), getResources().getString(R.string.checkNetConnection));
Toasty.error(ctx, getResources().getString(R.string.checkNetConnection));
return;
}
if(newReleaseTitle.equals("")) {
Toasty.error(ctx, getString(R.string.titleErrorEmpty));
return;
}
if(newReleaseTagName.equals("")) {
Toasty.info(getApplicationContext(), getString(R.string.tagNameErrorEmpty));
Toasty.error(ctx, getString(R.string.tagNameErrorEmpty));
return;
}
if(newReleaseTitle.equals("")) {
if(checkBranch == null) {
Toasty.info(getApplicationContext(), getString(R.string.titleErrorEmpty));
return;
}
Toasty.error(ctx, getString(R.string.selectBranchError));
return;
}
disableProcessButton();
createNewReleaseFunc(instanceUrl, Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName, newReleaseTagName, newReleaseTitle, newReleaseContent, newReleaseBranch, newReleaseType, newReleaseDraft);
createNewReleaseFunc(Authorization.get(ctx), repoOwner, repoName, newReleaseTagName, newReleaseTitle, newReleaseContent, selectedBranch, newReleaseType, newReleaseDraft);
}
private void createNewReleaseFunc(final String instanceUrl, final String token, String repoOwner, String repoName, String newReleaseTagName, String newReleaseTitle, String newReleaseContent, String newReleaseBranch, boolean newReleaseType, boolean newReleaseDraft) {
private void createNewReleaseFunc(final String token, String repoOwner, String repoName, String newReleaseTagName, String newReleaseTitle, String newReleaseContent, String selectedBranch, boolean newReleaseType, boolean newReleaseDraft) {
Releases createReleaseJson = new Releases(newReleaseContent, newReleaseDraft, newReleaseTitle, newReleaseType, newReleaseTagName, newReleaseBranch);
Releases createReleaseJson = new Releases(newReleaseContent, newReleaseDraft, newReleaseTitle, newReleaseType, newReleaseTagName, selectedBranch);
Call<Releases> call;
call = RetrofitClient
.getInstance(instanceUrl, getApplicationContext())
.getApiInterface()
.getApiInterface(ctx)
.createNewRelease(token, repoOwner, repoName, createReleaseJson);
call.enqueue(new Callback<Releases>() {
@ -178,12 +168,10 @@ public class CreateReleaseActivity extends BaseActivity {
if (response.code() == 201) {
TinyDB tinyDb = new TinyDB(getApplicationContext());
tinyDb.putBoolean("updateReleases", true);
Toasty.info(getApplicationContext(), getString(R.string.releaseCreatedText));
tinyDB.putBoolean("updateReleases", true);
Toasty.success(ctx, getString(R.string.releaseCreatedText));
enableProcessButton();
finish();
}
else if(response.code() == 401) {
@ -192,31 +180,27 @@ public class CreateReleaseActivity extends BaseActivity {
ctx.getResources().getString(R.string.alertDialogTokenRevokedMessage),
ctx.getResources().getString(R.string.alertDialogTokenRevokedCopyNegativeButton),
ctx.getResources().getString(R.string.alertDialogTokenRevokedCopyPositiveButton));
}
else if(response.code() == 403) {
enableProcessButton();
Toasty.info(ctx, ctx.getString(R.string.authorizeError));
Toasty.error(ctx, ctx.getString(R.string.authorizeError));
}
else if(response.code() == 404) {
enableProcessButton();
Toasty.info(ctx, ctx.getString(R.string.apiNotFound));
Toasty.warning(ctx, ctx.getString(R.string.apiNotFound));
}
else {
enableProcessButton();
Toasty.info(ctx, ctx.getString(R.string.genericError));
Toasty.error(ctx, ctx.getString(R.string.genericError));
}
}
@Override
public void onFailure(@NonNull Call<Releases> call, @NonNull Throwable t) {
Log.e("onFailure", t.toString());
enableProcessButton();
}
@ -224,11 +208,10 @@ public class CreateReleaseActivity extends BaseActivity {
}
private void getBranches(String instanceUrl, String instanceToken, final String repoOwner, final String repoName) {
private void getBranches(String instanceToken, final String repoOwner, final String repoName) {
Call<List<Branches>> call = RetrofitClient
.getInstance(instanceUrl, getApplicationContext())
.getApiInterface()
.getApiInterface(ctx)
.getBranches(instanceToken, repoOwner, repoName);
call.enqueue(new Callback<List<Branches>>() {
@ -237,29 +220,27 @@ public class CreateReleaseActivity extends BaseActivity {
public void onResponse(@NonNull Call<List<Branches>> call, @NonNull retrofit2.Response<List<Branches>> response) {
if(response.isSuccessful()) {
if(response.code() == 200) {
List<Branches> branchesList_ = response.body();
assert branchesList_ != null;
if(branchesList_.size() > 0) {
for (int i = 0; i < branchesList_.size(); i++) {
Branches data = new Branches(
branchesList_.get(i).getName()
);
branchesList.add(data);
}
branchesList.addAll(branchesList_);
}
ArrayAdapter<Branches> adapter = new ArrayAdapter<>(getApplicationContext(),
R.layout.spinner_item, branchesList);
ArrayAdapter<Branches> adapter = new ArrayAdapter<>(CreateReleaseActivity.this,
R.layout.list_spinner_items, branchesList);
adapter.setDropDownViewResource(R.layout.spinner_dropdown_item);
releaseBranch.setAdapter(adapter);
enableProcessButton();
releaseBranch.setOnItemClickListener ((parent, view, position, id) ->
selectedBranch = branchesList.get(position).getName()
);
}
}
else if(response.code() == 401) {
@ -268,13 +249,13 @@ public class CreateReleaseActivity extends BaseActivity {
getResources().getString(R.string.alertDialogTokenRevokedMessage),
getResources().getString(R.string.alertDialogTokenRevokedCopyNegativeButton),
getResources().getString(R.string.alertDialogTokenRevokedCopyPositiveButton));
}
}
@Override
public void onFailure(@NonNull Call<List<Branches>> call, @NonNull Throwable t) {
Log.e("onFailure", t.toString());
}
});
@ -282,32 +263,18 @@ public class CreateReleaseActivity extends BaseActivity {
}
private void initCloseListener() {
onClickListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
finish();
}
};
onClickListener = view -> finish();
}
private void disableProcessButton() {
createNewRelease.setEnabled(false);
GradientDrawable shape = new GradientDrawable();
shape.setCornerRadius( 8 );
shape.setColor(getResources().getColor(R.color.hintColor));
createNewRelease.setBackground(shape);
}
private void enableProcessButton() {
createNewRelease.setEnabled(true);
GradientDrawable shape = new GradientDrawable();
shape.setCornerRadius( 8 );
shape.setColor(getResources().getColor(R.color.btnBackground));
createNewRelease.setBackground(shape);
}
}

View File

@ -0,0 +1,303 @@
package org.mian.gitnex.activities;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.ImageView;
import androidx.annotation.NonNull;
import org.gitnex.tea4j.models.OrgOwner;
import org.gitnex.tea4j.models.OrganizationRepository;
import org.mian.gitnex.R;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.databinding.ActivityCreateRepoBinding;
import org.mian.gitnex.helpers.AlertDialogs;
import org.mian.gitnex.helpers.AppUtil;
import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.helpers.TinyDB;
import org.mian.gitnex.helpers.Toasty;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;
import retrofit2.Call;
import retrofit2.Callback;
/**
* Author M M Arif
*/
public class CreateRepoActivity extends BaseActivity {
public ImageView closeActivity;
private View.OnClickListener onClickListener;
private AutoCompleteTextView spinner;
private Button createRepo;
private EditText repoName;
private EditText repoDesc;
private CheckBox repoAccess;
private String loginUid;
private String userLogin;
private String selectedOwner;
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
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityCreateRepoBinding activityCreateRepoBinding = ActivityCreateRepoBinding.inflate(getLayoutInflater());
setContentView(activityCreateRepoBinding.getRoot());
boolean connToInternet = AppUtil.hasNetworkConnection(ctx);
loginUid = tinyDB.getString("loginUid");
userLogin = tinyDB.getString("userLogin");
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
closeActivity = activityCreateRepoBinding.close;
repoName = activityCreateRepoBinding.newRepoName;
repoDesc = activityCreateRepoBinding.newRepoDescription;
repoAccess = activityCreateRepoBinding.newRepoPrivate;
repoName.requestFocus();
assert imm != null;
imm.showSoftInput(repoName, InputMethodManager.SHOW_IMPLICIT);
initCloseListener();
closeActivity.setOnClickListener(onClickListener);
spinner = activityCreateRepoBinding.ownerSpinner;
getOrganizations(Authorization.get(ctx), userLogin);
createRepo = activityCreateRepoBinding.createNewRepoButton;
disableProcessButton();
if(!connToInternet) {
disableProcessButton();
}
else {
createRepo.setOnClickListener(createRepoListener);
}
}
private final View.OnClickListener createRepoListener = v -> processNewRepo();
private void processNewRepo() {
boolean connToInternet = AppUtil.hasNetworkConnection(appCtx);
String newRepoName = repoName.getText().toString();
String newRepoDesc = repoDesc.getText().toString();
boolean newRepoAccess = repoAccess.isChecked();
if(!connToInternet) {
Toasty.error(ctx, getResources().getString(R.string.checkNetConnection));
return;
}
if(!newRepoDesc.equals("")) {
if (newRepoDesc.length() > 255) {
Toasty.warning(ctx, getString(R.string.repoDescError));
return;
}
}
if(newRepoName.equals("")) {
Toasty.error(ctx, getString(R.string.repoNameErrorEmpty));
}
else if(!AppUtil.checkStrings(newRepoName)) {
Toasty.warning(ctx, getString(R.string.repoNameErrorInvalid));
}
else if (reservedRepoNames.contains(newRepoName)) {
Toasty.warning(ctx, getString(R.string.repoNameErrorReservedName));
}
else if (reservedRepoPatterns.matcher(newRepoName).find()) {
Toasty.warning(ctx, getString(R.string.repoNameErrorReservedPatterns));
}
else if(selectedOwner == null) {
Toasty.error(ctx, getString(R.string.repoOwnerError));
}
else {
disableProcessButton();
createNewRepository(Authorization.get(ctx), loginUid, newRepoName, newRepoDesc, selectedOwner, newRepoAccess);
}
}
private void createNewRepository(final String token, String loginUid, String repoName, String repoDesc, String selectedOwner, boolean isPrivate) {
OrganizationRepository createRepository = new OrganizationRepository(true, repoDesc, null, null, repoName, isPrivate, "Default");
Call<OrganizationRepository> call;
if(selectedOwner.equals(loginUid)) {
call = RetrofitClient
.getApiInterface(ctx)
.createNewUserRepository(token, createRepository);
}
else {
call = RetrofitClient
.getApiInterface(ctx)
.createNewUserOrgRepository(token, selectedOwner, createRepository);
}
call.enqueue(new Callback<OrganizationRepository>() {
@Override
public void onResponse(@NonNull Call<OrganizationRepository> call, @NonNull retrofit2.Response<OrganizationRepository> response) {
if(response.code() == 201) {
TinyDB tinyDb = TinyDB.getInstance(appCtx);
tinyDb.putBoolean("repoCreated", true);
Toasty.success(ctx, getString(R.string.repoCreated));
enableProcessButton();
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() == 409) {
enableProcessButton();
Toasty.warning(ctx, getString(R.string.repoExistsError));
}
else {
enableProcessButton();
Toasty.error(ctx, getString(R.string.repoCreatedError));
}
}
@Override
public void onFailure(@NonNull Call<OrganizationRepository> call, @NonNull Throwable t) {
Log.e("onFailure", t.toString());
enableProcessButton();
}
});
}
private void getOrganizations(String instanceToken, final String userLogin) {
Call<List<OrgOwner>> call = RetrofitClient
.getApiInterface(ctx)
.getOrgOwners(instanceToken, 1, 50);
call.enqueue(new Callback<List<OrgOwner>>() {
@Override
public void onResponse(@NonNull Call<List<OrgOwner>> call, @NonNull retrofit2.Response<List<OrgOwner>> response) {
if(response.code() == 200) {
int organizationId = 0;
List<OrgOwner> organizationsList_ = response.body();
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(organizationsList_.get(i).getUsername());
organizationsList.add(data);
}
}
ArrayAdapter<OrgOwner> adapter = new ArrayAdapter<>(CreateRepoActivity.this, R.layout.list_spinner_items, organizationsList);
spinner.setAdapter(adapter);
spinner.setOnItemClickListener ((parent, view, position, id) -> selectedOwner = organizationsList.get(position).getUsername());
if(tinyDB.getBoolean("organizationAction") & organizationId != 0) {
int selectOwnerById = organizationId;
new Handler(Looper.getMainLooper()).postDelayed(() -> {
spinner.setText(organizationsList.get(selectOwnerById).getUsername(), false);
selectedOwner = organizationsList.get(selectOwnerById).getUsername();
}, 500);
tinyDB.putBoolean("organizationAction", false);
}
enableProcessButton();
}
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));
}
}
@Override
public void onFailure(@NonNull Call<List<OrgOwner>> call, @NonNull Throwable t) {
Log.e("onFailure", t.toString());
enableProcessButton();
}
});
}
private void initCloseListener() {
onClickListener = view -> finish();
}
private void disableProcessButton() {
createRepo.setEnabled(false);
}
private void enableProcessButton() {
createRepo.setEnabled(true);
}
}

View File

@ -1,29 +1,31 @@
package org.mian.gitnex.activities;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import retrofit2.Call;
import retrofit2.Callback;
import android.content.Context;
import android.content.DialogInterface;
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.Button;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.core.content.res.ResourcesCompat;
import org.gitnex.tea4j.models.Teams;
import org.mian.gitnex.R;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.databinding.ActivityCreateTeamByOrgBinding;
import org.mian.gitnex.helpers.AlertDialogs;
import org.mian.gitnex.helpers.AppUtil;
import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.helpers.TinyDB;
import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.models.Teams;
import org.mian.gitnex.util.AppUtil;
import org.mian.gitnex.util.TinyDB;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import android.util.Log;
import retrofit2.Call;
import retrofit2.Callback;
/**
* Author M M Arif
@ -31,7 +33,6 @@ import android.util.Log;
public class CreateTeamByOrgActivity extends BaseActivity implements View.OnClickListener {
final Context ctx = CreateTeamByOrgActivity.this;
private View.OnClickListener onClickListener;
private TextView teamName;
private TextView teamDesc;
@ -40,15 +41,10 @@ public class CreateTeamByOrgActivity extends BaseActivity implements View.OnClic
private TextView teamAccessControls;
private TextView teamAccessControlsArray;
private Button createTeamButton;
private String[] permissionList = {"Read", "Write", "Admin"};
private final String[] permissionList = {"Read", "Write", "Admin"};
public int permissionSelectedChoice = -1;
@Override
protected int getLayoutResourceId(){
return R.layout.activity_create_team_by_org;
}
private String[] accessControlsList = new String[] {
private final String[] accessControlsList = new String[] {
"Code",
"Issues",
"Pull Request",
@ -60,7 +56,7 @@ public class CreateTeamByOrgActivity extends BaseActivity implements View.OnClic
private List<String> pushAccessList;
private boolean[] selectedAccessControlsTrueFalse = new boolean[]{
private final boolean[] selectedAccessControlsTrueFalse = new boolean[]{
false,
false,
false,
@ -72,150 +68,141 @@ public class CreateTeamByOrgActivity extends BaseActivity implements View.OnClic
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
boolean connToInternet = AppUtil.haveNetworkConnection(getApplicationContext());
ActivityCreateTeamByOrgBinding activityCreateTeamByOrgBinding = ActivityCreateTeamByOrgBinding.inflate(getLayoutInflater());
setContentView(activityCreateTeamByOrgBinding.getRoot());
ImageView closeActivity = findViewById(R.id.close);
teamName = findViewById(R.id.teamName);
teamDesc = findViewById(R.id.teamDesc);
teamPermission = findViewById(R.id.teamPermission);
teamPermissionDetail = findViewById(R.id.teamPermissionDetail);
teamAccessControls = findViewById(R.id.teamAccessControls);
teamAccessControlsArray = findViewById(R.id.teamAccessControlsArray);
createTeamButton = findViewById(R.id.createTeamButton);
boolean connToInternet = AppUtil.hasNetworkConnection(appCtx);
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
ImageView closeActivity = activityCreateTeamByOrgBinding.close;
teamName = activityCreateTeamByOrgBinding.teamName;
teamDesc = activityCreateTeamByOrgBinding.teamDesc;
teamPermission = activityCreateTeamByOrgBinding.teamPermission;
teamPermissionDetail = activityCreateTeamByOrgBinding.teamPermissionDetail;
teamAccessControls = activityCreateTeamByOrgBinding.teamAccessControls;
teamAccessControlsArray = activityCreateTeamByOrgBinding.teamAccessControlsArray;
createTeamButton = activityCreateTeamByOrgBinding.createTeamButton;
teamName.requestFocus();
assert imm != null;
imm.showSoftInput(teamName, InputMethodManager.SHOW_IMPLICIT);
initCloseListener();
closeActivity.setOnClickListener(onClickListener);
teamPermission.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
teamPermission.setOnClickListener(view -> {
AlertDialog.Builder pBuilder = new AlertDialog.Builder(ctx);
AlertDialog.Builder pBuilder = new AlertDialog.Builder(ctx);
pBuilder.setTitle(R.string.newTeamPermission);
if(permissionSelectedChoice != -1) {
pBuilder.setCancelable(true);
}
else {
pBuilder.setCancelable(false);
}
pBuilder.setSingleChoiceItems(permissionList, permissionSelectedChoice, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
pBuilder.setTitle(R.string.newTeamPermission);
pBuilder.setCancelable(permissionSelectedChoice != -1);
permissionSelectedChoice = i;
teamPermission.setText(permissionList[i]);
pBuilder.setSingleChoiceItems(permissionList, permissionSelectedChoice, (dialogInterface, i) -> {
if(permissionList[i].equals("Read")) {
teamPermissionDetail.setVisibility(View.VISIBLE);
teamPermissionDetail.setText(R.string.newTeamPermissionRead);
permissionSelectedChoice = i;
teamPermission.setText(permissionList[i]);
switch(permissionList[i]) {
case "Read":
teamPermissionDetail.setVisibility(View.VISIBLE);
teamPermissionDetail.setText(R.string.newTeamPermissionRead);
break;
case "Write":
teamPermissionDetail.setVisibility(View.VISIBLE);
teamPermissionDetail.setText(R.string.newTeamPermissionWrite);
break;
case "Admin":
teamPermissionDetail.setVisibility(View.VISIBLE);
teamPermissionDetail.setText(R.string.newTeamPermissionAdmin);
break;
default:
teamPermissionDetail.setVisibility(View.GONE);
break;
}
dialogInterface.dismiss();
});
AlertDialog pDialog = pBuilder.create();
pDialog.show();
});
teamAccessControls.setOnClickListener(v -> {
teamAccessControls.setText("");
teamAccessControlsArray.setText("");
pushAccessList = Arrays.asList(accessControlsList);
AlertDialog.Builder aDialogBuilder = new AlertDialog.Builder(ctx);
aDialogBuilder.setMultiChoiceItems(accessControlsList, selectedAccessControlsTrueFalse, (dialog, which, isChecked) -> {
})
.setCancelable(false)
.setTitle(R.string.newTeamAccessControls)
.setPositiveButton(R.string.okButton, (dialog, which) -> {
int selectedVal = 0;
while(selectedVal < selectedAccessControlsTrueFalse.length)
{
boolean value = selectedAccessControlsTrueFalse[selectedVal];
String repoCode = "";
if(selectedVal == 0) {
repoCode = "repo.code";
}
else if(permissionList[i].equals("Write")) {
teamPermissionDetail.setVisibility(View.VISIBLE);
teamPermissionDetail.setText(R.string.newTeamPermissionWrite);
if(selectedVal == 1) {
repoCode = "repo.issues";
}
else if(permissionList[i].equals("Admin")) {
teamPermissionDetail.setVisibility(View.VISIBLE);
teamPermissionDetail.setText(R.string.newTeamPermissionAdmin);
if(selectedVal == 2) {
repoCode = "repo.pulls";
}
else {
teamPermissionDetail.setVisibility(View.GONE);
if(selectedVal == 3) {
repoCode = "repo.releases";
}
if(selectedVal == 4) {
repoCode = "repo.wiki";
}
if(selectedVal == 5) {
repoCode = "repo.ext_wiki";
}
if(selectedVal == 6) {
repoCode = "repo.ext_issues";
}
dialogInterface.dismiss();
if(value){
teamAccessControls.setText(getString(R.string.newTeamPermissionValues, teamAccessControls.getText(), pushAccessList.get(selectedVal)));
teamAccessControlsArray.setText(getString(R.string.newTeamPermissionValuesFinal, teamAccessControlsArray.getText(), repoCode));
}
selectedVal++;
}
String data = String.valueOf(teamAccessControls.getText());
if(!data.equals("")) {
teamAccessControls.setText(data.substring(0, data.length() - 2));
}
String dataArray = String.valueOf(teamAccessControlsArray.getText());
if(!dataArray.equals("")) {
teamAccessControlsArray.setText(dataArray.substring(0, dataArray.length() - 2));
}
});
AlertDialog pDialog = pBuilder.create();
pDialog.show();
}
});
teamAccessControls.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
teamAccessControls.setText("");
teamAccessControlsArray.setText("");
pushAccessList = Arrays.asList(accessControlsList);
AlertDialog.Builder aDialogBuilder = new AlertDialog.Builder(ctx);
aDialogBuilder.setMultiChoiceItems(accessControlsList, selectedAccessControlsTrueFalse, new DialogInterface.OnMultiChoiceClickListener() {
@Override
public void onClick(DialogInterface dialog, int which, boolean isChecked) {
}
})
.setCancelable(false)
.setTitle(R.string.newTeamAccessControls)
.setPositiveButton(R.string.okButton, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
int selectedVal = 0;
while(selectedVal < selectedAccessControlsTrueFalse.length)
{
boolean value = selectedAccessControlsTrueFalse[selectedVal];
String repoCode = "";
if(selectedVal == 0) {
repoCode = "repo.code";
}
if(selectedVal == 1) {
repoCode = "repo.issues";
}
if(selectedVal == 2) {
repoCode = "repo.pulls";
}
if(selectedVal == 3) {
repoCode = "repo.releases";
}
if(selectedVal == 4) {
repoCode = "repo.wiki";
}
if(selectedVal == 5) {
repoCode = "repo.ext_wiki";
}
if(selectedVal == 6) {
repoCode = "repo.ext_issues";
}
if(value){
teamAccessControls.setText(getString(R.string.newTeamPermissionValues, teamAccessControls.getText(), pushAccessList.get(selectedVal)));
teamAccessControlsArray.setText(getString(R.string.newTeamPermissionValuesFinal, teamAccessControlsArray.getText(), repoCode));
}
selectedVal++;
}
String data = String.valueOf(teamAccessControls.getText());
if(!data.equals("")) {
teamAccessControls.setText(data.substring(0, data.length() - 2));
}
String dataArray = String.valueOf(teamAccessControlsArray.getText());
if(!dataArray.equals("")) {
teamAccessControlsArray.setText(dataArray.substring(0, dataArray.length() - 2));
}
//Log.i("orgName", String.valueOf(teamAccessControlsArray.getText()));
}
});
AlertDialog aDialog = aDialogBuilder.create();
aDialog.show();
}
AlertDialog aDialog = aDialogBuilder.create();
aDialog.show();
});
createTeamButton.setEnabled(false);
@ -223,30 +210,26 @@ public class CreateTeamByOrgActivity extends BaseActivity implements View.OnClic
if(!connToInternet) {
createTeamButton.setEnabled(false);
GradientDrawable shape = new GradientDrawable();
shape.setCornerRadius( 8 );
shape.setColor(getResources().getColor(R.color.hintColor));
GradientDrawable shape = new GradientDrawable();
shape.setCornerRadius(8);
shape.setColor(ResourcesCompat.getColor(getResources(), R.color.hintColor, null));
createTeamButton.setBackground(shape);
} else {
}
else {
createTeamButton.setEnabled(true);
createTeamButton.setOnClickListener(this);
}
}
private void processCreateTeam() {
AppUtil appUtil = new AppUtil();
final TinyDB tinyDb = new TinyDB(getApplicationContext());
final String instanceUrl = tinyDb.getString("instanceUrl");
final TinyDB tinyDb = TinyDB.getInstance(appCtx);
final String loginUid = tinyDb.getString("loginUid");
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
final String orgName = tinyDb.getString("orgName");;
boolean connToInternet = AppUtil.haveNetworkConnection(getApplicationContext());
boolean connToInternet = AppUtil.hasNetworkConnection(appCtx);
String newTeamName = teamName.getText().toString();
String newTeamDesc = teamDesc.getText().toString();
String newTeamPermission = teamPermission.getText().toString().toLowerCase();
@ -254,66 +237,62 @@ public class CreateTeamByOrgActivity extends BaseActivity implements View.OnClic
if(!connToInternet) {
Toasty.info(getApplicationContext(), getResources().getString(R.string.checkNetConnection));
Toasty.error(ctx, getResources().getString(R.string.checkNetConnection));
return;
}
if (newTeamName.equals("")) {
Toasty.info(getApplicationContext(), getString(R.string.teamNameEmpty));
Toasty.error(ctx, getString(R.string.teamNameEmpty));
return;
}
if(!appUtil.checkStringsWithAlphaNumericDashDotUnderscore(newTeamName)) {
if(!AppUtil.checkStringsWithAlphaNumericDashDotUnderscore(newTeamName)) {
Toasty.info(getApplicationContext(), getString(R.string.teamNameError));
Toasty.warning(ctx, getString(R.string.teamNameError));
return;
}
if(!newTeamDesc.equals("")) {
if(!appUtil.checkStrings(newTeamDesc)) {
Toasty.info(getApplicationContext(), getString(R.string.teamDescError));
if(!AppUtil.checkStrings(newTeamDesc)) {
Toasty.warning(ctx, getString(R.string.teamDescError));
return;
}
if(newTeamDesc.length() > 100) {
Toasty.info(getApplicationContext(), getString(R.string.teamDescLimit));
Toasty.warning(ctx, getString(R.string.teamDescLimit));
return;
}
}
if (newTeamPermission.equals("")) {
Toasty.info(getApplicationContext(), getString(R.string.teamPermissionEmpty));
Toasty.error(ctx, getString(R.string.teamPermissionEmpty));
return;
}
List<String> newTeamAccessControls_ = new ArrayList<>(Arrays.asList(newTeamAccessControls.split(",")));
for (int i = 0; i < newTeamAccessControls_.size(); i++) {
newTeamAccessControls_.set(i, newTeamAccessControls_.get(i).trim());
}
createNewTeamCall(instanceUrl, instanceToken, orgName, newTeamName, newTeamDesc, newTeamPermission, newTeamAccessControls_, loginUid);
createNewTeamCall(instanceToken, orgName, newTeamName, newTeamDesc, newTeamPermission, newTeamAccessControls_, loginUid);
}
private void createNewTeamCall(final String instanceUrl, final String instanceToken, String orgName, String newTeamName, String newTeamDesc, String newTeamPermission, List<String> newTeamAccessControls, String loginUid) {
private void createNewTeamCall(final String instanceToken, String orgName, String newTeamName, String newTeamDesc, String newTeamPermission, List<String> newTeamAccessControls, String loginUid) {
Teams createNewTeamJson = new Teams(newTeamName, newTeamDesc, newTeamPermission, newTeamAccessControls);
Call<Teams> call3;
call3 = RetrofitClient
.getInstance(instanceUrl, getApplicationContext())
.getApiInterface()
.createTeamsByOrg(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), orgName, createNewTeamJson);
.getApiInterface(ctx)
.createTeamsByOrg(Authorization.get(ctx), orgName, createNewTeamJson);
call3.enqueue(new Callback<Teams>() {
@ -321,21 +300,19 @@ public class CreateTeamByOrgActivity extends BaseActivity implements View.OnClic
public void onResponse(@NonNull Call<Teams> call, @NonNull retrofit2.Response<Teams> response2) {
if(response2.isSuccessful()) {
if(response2.code() == 201) {
TinyDB tinyDb = new TinyDB(getApplicationContext());
TinyDB tinyDb = TinyDB.getInstance(appCtx);
tinyDb.putBoolean("resumeTeams", true);
Toasty.info(getApplicationContext(), getString(R.string.teamCreated));
Toasty.success(ctx, getString(R.string.teamCreated));
finish();
}
}
else if(response2.code() == 404) {
Toasty.info(getApplicationContext(), getString(R.string.apiNotFound));
Toasty.warning(ctx, getString(R.string.apiNotFound));
}
else if(response2.code() == 401) {
@ -343,14 +320,11 @@ public class CreateTeamByOrgActivity extends BaseActivity implements View.OnClic
getResources().getString(R.string.alertDialogTokenRevokedMessage),
getResources().getString(R.string.alertDialogTokenRevokedCopyNegativeButton),
getResources().getString(R.string.alertDialogTokenRevokedCopyPositiveButton));
}
else {
Toasty.info(getApplicationContext(), getString(R.string.teamCreatedError));
Toasty.error(ctx, getString(R.string.teamCreatedError));
}
}
@Override
@ -363,19 +337,16 @@ public class CreateTeamByOrgActivity extends BaseActivity implements View.OnClic
@Override
public void onClick(View v) {
if(v == createTeamButton) {
processCreateTeam();
}
}
private void initCloseListener() {
onClickListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
finish();
}
};
onClickListener = view -> finish();
}
}

View File

@ -1,66 +0,0 @@
package org.mian.gitnex.activities;
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.view.View;
import android.widget.ImageView;
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
*/
public class CreditsActivity extends BaseActivity {
private View.OnClickListener onClickListener;
@Override
protected int getLayoutResourceId(){
return R.layout.activity_credits;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ImageView closeActivity = findViewById(R.id.close);
initCloseListener();
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() {
onClickListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
finish();
}
};
}
}

View File

@ -0,0 +1,699 @@
package org.mian.gitnex.activities;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.view.View;
import androidx.annotation.NonNull;
import org.apache.commons.lang3.StringUtils;
import org.gitnex.tea4j.models.Files;
import org.gitnex.tea4j.models.Organization;
import org.gitnex.tea4j.models.PullRequests;
import org.gitnex.tea4j.models.UserInfo;
import org.gitnex.tea4j.models.UserRepositories;
import org.jetbrains.annotations.NotNull;
import org.mian.gitnex.R;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.database.api.BaseApi;
import org.mian.gitnex.database.api.RepositoriesApi;
import org.mian.gitnex.database.api.UserAccountsApi;
import org.mian.gitnex.database.models.Repository;
import org.mian.gitnex.database.models.UserAccount;
import org.mian.gitnex.databinding.ActivityDeeplinksBinding;
import org.mian.gitnex.helpers.AppUtil;
import org.mian.gitnex.helpers.TinyDB;
import org.mian.gitnex.helpers.UrlHelper;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import io.mikael.urlbuilder.UrlBuilder;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
/**
* Author M M Arif
*/
public class DeepLinksActivity extends BaseActivity {
private ActivityDeeplinksBinding viewBinding;
private String currentInstance;
private String instanceToken;
private boolean accountFound = false;
private Intent mainIntent;
private Intent issueIntent;
private Intent repoIntent;
private Intent orgIntent;
private Intent userIntent;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
viewBinding = ActivityDeeplinksBinding.inflate(getLayoutInflater());
setContentView(viewBinding.getRoot());
mainIntent = new Intent(ctx, MainActivity.class);
issueIntent = new Intent(ctx, IssueDetailActivity.class);
repoIntent = new Intent(ctx, RepoDetailActivity.class);
orgIntent = new Intent(ctx, OrganizationDetailActivity.class);
userIntent = new Intent(ctx, ProfileActivity.class);
Intent intent = getIntent();
Uri data = intent.getData();
assert data != null;
// check for login
if(!tinyDB.getBoolean("loggedInMode")) {
Intent loginIntent = new Intent(ctx, LoginActivity.class);
loginIntent.putExtra("instanceUrl", data.getHost());
ctx.startActivity(loginIntent);
finish();
}
// check for the links(URI) to be in the db
UserAccountsApi userAccountsApi = BaseApi.getInstance(ctx, UserAccountsApi.class);
List<UserAccount> userAccounts = userAccountsApi.usersAccounts();
for(UserAccount userAccount : userAccounts) {
String hostUri = userAccount.getInstanceUrl();
currentInstance = userAccount.getInstanceUrl();
instanceToken = userAccount.getToken();
if(hostUri.toLowerCase().contains(Objects.requireNonNull(data.getHost().toLowerCase()))) {
accountFound = true;
AppUtil.switchToAccount(ctx, userAccount);
break;
}
}
if(accountFound) {
// redirect to proper fragment/activity, if no action is there, show options where user to want to go like repos, profile, notifications etc
if(data.getPathSegments().size() == 1) {
if(data.getLastPathSegment().equals("notifications")) { // notifications
mainIntent.putExtra("launchFragmentByLinkHandler", "notification");
ctx.startActivity(mainIntent);
finish();
}
else if(data.getLastPathSegment().equals("explore")) { // explore
mainIntent.putExtra("launchFragmentByLinkHandler", "explore");
ctx.startActivity(mainIntent);
finish();
}
else if(data.getLastPathSegment().equals(tinyDB.getString("userLogin"))) { // your user profile
mainIntent.putExtra("launchFragmentByLinkHandler", "profile");
ctx.startActivity(mainIntent);
finish();
}
else if(data.getLastPathSegment().equals("admin")) {
mainIntent.putExtra("launchFragmentByLinkHandler", "admin");
ctx.startActivity(mainIntent);
finish();
}
else {
new Handler(Looper.getMainLooper()).postDelayed(() ->
getUserOrOrg(currentInstance, instanceToken, data.getLastPathSegment()), 500);
}
}
else if(data.getPathSegments().size() == 2) {
if(data.getPathSegments().get(0).equals("explore")) { // specific explore tab
if(data.getPathSegments().get(1).equals("organizations")) { // orgs
mainIntent.putExtra("exploreOrgs", true);
}
mainIntent.putExtra("launchFragmentByLinkHandler", "explore");
ctx.startActivity(mainIntent);
finish();
}
else if(data.getPathSegments().get(0).equals("user") && data.getPathSegments().get(1).equals("login")) { // open login
Intent loginIntent = new Intent(ctx, AddNewAccountActivity.class);
loginIntent.putExtra("instanceUrl", data.getHost());
loginIntent.putExtra("instanceProtocol", data.getScheme());
ctx.startActivity(loginIntent);
finish();
}
else if(data.getPathSegments().get(0).equals("admin")) {
mainIntent.putExtra("launchFragmentByLinkHandler", "admin");
mainIntent.putExtra("giteaAdminAction", data.getLastPathSegment());
ctx.startActivity(mainIntent);
finish();
}
else if(!data.getPathSegments().get(0).equals("") & !data.getLastPathSegment().equals("")) { // go to repo
new Handler(Looper.getMainLooper()).postDelayed(() ->
goToRepoSection(currentInstance, instanceToken, data.getPathSegments().get(0), data.getLastPathSegment(), "repo"), 500);
}
else { // no action, show options
showNoActionButtons();
}
}
else if(data.getPathSegments().size() >= 3) {
if(data.getPathSegments().get(2).equals("issues")) { // issue
if(!Objects.requireNonNull(data.getLastPathSegment()).contains("issues") & StringUtils.isNumeric(data.getLastPathSegment())) {
issueIntent.putExtra("issueNumber", data.getLastPathSegment());
issueIntent.putExtra("openedFromLink", "true");
String[] urlSplitted = data.toString().split("#");
if (urlSplitted.length == 2) {
issueIntent.putExtra("issueComment", urlSplitted[1]);
}
tinyDB.putString("issueNumber", data.getLastPathSegment());
tinyDB.putString("issueType", "Issue");
tinyDB.putString("repoFullName", data.getPathSegments().get(0) + "/" + data.getPathSegments().get(1));
final String repoOwner = data.getPathSegments().get(0);
final String repoName = data.getPathSegments().get(1);
int currentActiveAccountId = tinyDB.getInt("currentActiveAccountId");
RepositoriesApi repositoryData = BaseApi.getInstance(ctx, RepositoriesApi.class);
Integer count = repositoryData.checkRepository(currentActiveAccountId, repoOwner, repoName);
if(count == 0) {
long id = repositoryData.insertRepository(currentActiveAccountId, repoOwner, repoName);
tinyDB.putLong("repositoryId", id);
}
else {
Repository dataRepo = repositoryData.getRepository(currentActiveAccountId, repoOwner, repoName);
tinyDB.putLong("repositoryId", dataRepo.getRepositoryId());
}
ctx.startActivity(issueIntent);
finish();
}
else if(Objects.requireNonNull(data.getLastPathSegment()).contains("issues")) {
new Handler(Looper.getMainLooper()).postDelayed(() ->
goToRepoSection(currentInstance, instanceToken, data.getPathSegments().get(0), data.getPathSegments().get(1), "issue"), 500);
}
else if(data.getLastPathSegment().equals("new")) {
new Handler(Looper.getMainLooper()).postDelayed(() ->
goToRepoSection(currentInstance, instanceToken, data.getPathSegments().get(0), data.getPathSegments().get(1), "issueNew"), 500);
}
else {
ctx.startActivity(mainIntent);
finish();
}
}
else if(data.getPathSegments().get(2).equals("pulls")) { // pr
if(!Objects.requireNonNull(data.getLastPathSegment()).contains("pulls") & StringUtils.isNumeric(data.getLastPathSegment())) {
new Handler(Looper.getMainLooper()).postDelayed(() -> {
String[] urlSplitted = data.toString().split("#");
if (urlSplitted.length == 2) {
issueIntent.putExtra("issueComment", urlSplitted[1]);
}
getPullRequest(currentInstance, instanceToken, data.getPathSegments().get(0), data.getPathSegments().get(1), Integer.parseInt(data.getLastPathSegment()));
}, 500);
}
else if(Objects.requireNonNull(data.getLastPathSegment()).contains("pulls")) {
new Handler(Looper.getMainLooper()).postDelayed(() ->
goToRepoSection(currentInstance, instanceToken, data.getPathSegments().get(0), data.getPathSegments().get(1), "pull"), 500);
}
else if(data.getLastPathSegment().equals("files")) { // pr diff
new Handler(Looper.getMainLooper()).postDelayed(() -> {
issueIntent.putExtra("openPrDiff", "true");
getPullRequest(currentInstance, instanceToken, data.getPathSegments().get(0), data.getPathSegments().get(1), Integer.parseInt(data.getPathSegments().get(3)));
}, 500);
}
else {
ctx.startActivity(mainIntent);
finish();
}
}
else if(data.getPathSegments().get(2).equals("compare")) { // new pull request
new Handler(Looper.getMainLooper()).postDelayed(() ->
goToRepoSection(currentInstance, instanceToken, data.getPathSegments().get(0), data.getPathSegments().get(1), "pullNew"), 500);
}
else if(data.getPathSegments().get(2).equals("commit")) { // commits (no API yet to properly implement)
new Handler(Looper.getMainLooper()).postDelayed(() ->
goToRepoSection(currentInstance, instanceToken, data.getPathSegments().get(0), data.getPathSegments().get(1), "pull"), 500);
}
else if(data.getPathSegments().get(2).equals("commits")) { // commits list
String branch = data.getLastPathSegment();
repoIntent.putExtra("branchName", branch);
new Handler(Looper.getMainLooper()).postDelayed(() ->
goToRepoSection(currentInstance, instanceToken, data.getPathSegments().get(0), data.getPathSegments().get(1), "commitsList"), 500);
}
else if(data.getPathSegments().get(2).equals("milestones") && data.getLastPathSegment().equals("new")) { // new milestone
new Handler(Looper.getMainLooper()).postDelayed(() ->
goToRepoSection(currentInstance, instanceToken, data.getPathSegments().get(0), data.getPathSegments().get(1), "milestonesNew"), 500);
}
else if(data.getPathSegments().get(2).equals("milestones")) { // milestones
new Handler(Looper.getMainLooper()).postDelayed(() ->
goToRepoSection(currentInstance, instanceToken, data.getPathSegments().get(0), data.getPathSegments().get(1), "milestones"), 500);
}
else if(data.getPathSegments().get(2).equals("milestone")) { // milestone
repoIntent.putExtra("milestoneId", data.getLastPathSegment());
new Handler(Looper.getMainLooper()).postDelayed(() ->
goToRepoSection(currentInstance, instanceToken, data.getPathSegments().get(0), data.getPathSegments().get(1), "milestones"), 500);
}
else if(data.getPathSegments().get(2).equals("releases") && data.getLastPathSegment().equals("new")) { // new release
new Handler(Looper.getMainLooper()).postDelayed(() ->
goToRepoSection(currentInstance, instanceToken, data.getPathSegments().get(0), data.getPathSegments().get(1), "newRelease"), 500);
}
else if(data.getPathSegments().get(2).equals("releases")) { // releases
if(data.getPathSegments().size() == 5) {
if(data.getPathSegments().get(2).equals("releases") && data.getPathSegments().get(3).equals("tag")) {
repoIntent.putExtra("releaseTagName", data.getLastPathSegment());
}
}
new Handler(Looper.getMainLooper()).postDelayed(
() -> goToRepoSection(currentInstance, instanceToken, data.getPathSegments().get(0), data.getPathSegments().get(1),
"releases"), 500);
}
else if(data.getPathSegments().get(2).equals("labels")) { // labels
new Handler(Looper.getMainLooper()).postDelayed(() ->
goToRepoSection(currentInstance, instanceToken, data.getPathSegments().get(0), data.getPathSegments().get(1), "labels"), 500);
}
else if(data.getPathSegments().get(2).equals("settings")) { // repo settings
new Handler(Looper.getMainLooper()).postDelayed(() ->
goToRepoSection(currentInstance, instanceToken, data.getPathSegments().get(0), data.getPathSegments().get(1), "settings"), 500);
}
else if(data.getLastPathSegment().equals("branches")) { // branches list
new Handler(Looper.getMainLooper()).postDelayed(() ->
goToRepoSection(currentInstance, instanceToken, data.getPathSegments().get(0), data.getPathSegments().get(1), "branchesList"), 500);
}
else if(data.getPathSegments().size() == 5 && data.getPathSegments().get(2).equals("src") && data.getPathSegments().get(3).equals("branch")) { // branch
repoIntent.putExtra("selectedBranch", data.getLastPathSegment());
new Handler(Looper.getMainLooper()).postDelayed(() ->
goToRepoSection(currentInstance, instanceToken, data.getPathSegments().get(0), data.getPathSegments().get(1), "branch"), 500);
}
else if(data.getPathSegments().get(2).equals("src") && data.getPathSegments().get(3).equals("branch")) { // file/dir
StringBuilder filePath = new StringBuilder();
ArrayList<String> segments = new ArrayList<>(data.getPathSegments());
segments.subList(0, 5).clear();
for (String item : segments) {
filePath.append(item);
filePath.append("/");
}
filePath.deleteCharAt(filePath.toString().length() - 1);
new Handler(Looper.getMainLooper()).postDelayed(() ->
getFile(currentInstance, instanceToken, data.getPathSegments().get(0),
data.getPathSegments().get(1), filePath.toString(), data.getPathSegments().get(4)), 500);
}
else { // no action, show options
showNoActionButtons();
}
}
else {
startActivity(mainIntent);
finish();
}
}
else {
viewBinding.progressBar.setVisibility(View.GONE);
viewBinding.addNewAccountFrame.setVisibility(View.VISIBLE);
viewBinding.noActionFrame.setVisibility(View.GONE);
viewBinding.addAccountText.setText(String.format(getResources().getString(R.string.accountDoesNotExist), data.getHost()));
viewBinding.addNewAccount.setOnClickListener(addNewAccount -> {
Intent accountIntent = new Intent(ctx, AddNewAccountActivity.class);
accountIntent.putExtra("instanceUrl", data.getHost());
startActivity(accountIntent);
finish();
});
viewBinding.openInBrowser.setOnClickListener(addNewAccount -> {
Integer port = data.getPort() >= 0 ? data.getPort() : null;
URI host = UrlBuilder.fromString(UrlHelper.fixScheme(data.getHost(), "https"))
.withPort(port)
.toUri();
Intent intentBrowser = new Intent();
intentBrowser.setAction(Intent.ACTION_VIEW);
intentBrowser.addCategory(Intent.CATEGORY_BROWSABLE);
intentBrowser.setData(Uri.parse(String.valueOf(host)));
startActivity(intentBrowser);
finish();
});
viewBinding.launchApp.setOnClickListener(launchApp -> {
startActivity(mainIntent);
finish();
});
}
}
private void getPullRequest(String url, String token, String repoOwner, String repoName, int index) {
Call<PullRequests> call = RetrofitClient
.getApiInterface(ctx, url)
.getPullRequestByIndex(token, repoOwner, repoName, index);
call.enqueue(new Callback<PullRequests>() {
@Override
public void onResponse(@NonNull Call<PullRequests> call, @NonNull retrofit2.Response<PullRequests> response) {
PullRequests prInfo = response.body();
if (response.code() == 200) {
assert prInfo != null;
issueIntent.putExtra("issueNumber", index);
issueIntent.putExtra("prMergeable", prInfo.isMergeable());
issueIntent.putExtra("openedFromLink", "true");
if(prInfo.getHead() != null) {
issueIntent.putExtra("prHeadBranch", prInfo.getHead().getRef());
tinyDB.putString("prHeadBranch", prInfo.getHead().getRef());
if(prInfo.getHead().getRepo() != null) {
tinyDB.putString("prIsFork", String.valueOf(prInfo.getHead().getRepo().isFork()));
tinyDB.putString("prForkFullName", prInfo.getHead().getRepo().getFull_name());
}
else {
// pull was done from a deleted fork
tinyDB.putString("prIsFork", "true");
tinyDB.putString("prForkFullName", ctx.getString(R.string.prDeletedFork));
}
}
tinyDB.putString("issueNumber", String.valueOf(index));
tinyDB.putString("prMergeable", String.valueOf(prInfo.isMergeable()));
tinyDB.putString("issueType", "Pull");
tinyDB.putString("repoFullName", repoOwner + "/" + repoName);
int currentActiveAccountId = tinyDB.getInt("currentActiveAccountId");
RepositoriesApi repositoryData = BaseApi.getInstance(ctx, RepositoriesApi.class);
Integer count = repositoryData.checkRepository(currentActiveAccountId, repoOwner, repoName);
if(count == 0) {
long id = repositoryData.insertRepository(currentActiveAccountId, repoOwner, repoName);
tinyDB.putLong("repositoryId", id);
}
else {
Repository dataRepo = repositoryData.getRepository(currentActiveAccountId, repoOwner, repoName);
tinyDB.putLong("repositoryId", dataRepo.getRepositoryId());
}
ctx.startActivity(issueIntent);
finish();
}
else {
ctx.startActivity(issueIntent);
finish();
Log.e("onFailure-links-pr", String.valueOf(response.code()));
}
}
@Override
public void onFailure(@NonNull Call<PullRequests> call, @NonNull Throwable t) {
ctx.startActivity(issueIntent);
finish();
Log.e("onFailure-links-pr", t.toString());
}
});
}
private void goToRepoSection(String url, String token, String repoOwner, String repoName, String type) {
Call<UserRepositories> call = RetrofitClient
.getApiInterface(ctx, url)
.getUserRepository(token, repoOwner, repoName);
call.enqueue(new Callback<UserRepositories>() {
@Override
public void onResponse(@NonNull Call<UserRepositories> call, @NonNull retrofit2.Response<UserRepositories> response) {
UserRepositories repoInfo = response.body();
if (response.code() == 200) {
assert repoInfo != null;
repoIntent.putExtra("repoFullName", repoInfo.getFullName());
repoIntent.putExtra("goToSection", "yes");
repoIntent.putExtra("goToSectionType", type);
tinyDB.putString("repoFullName", repoInfo.getFullName());
if(repoInfo.getPrivateFlag()) {
tinyDB.putString("repoType", getResources().getString(R.string.strPrivate));
}
else {
tinyDB.putString("repoType", getResources().getString(R.string.strPublic));
}
tinyDB.putBoolean("isRepoAdmin", repoInfo.getPermissions().isAdmin());
tinyDB.putString("repoBranch", repoInfo.getDefault_branch());
int currentActiveAccountId = tinyDB.getInt("currentActiveAccountId");
RepositoriesApi repositoryData = BaseApi.getInstance(ctx, RepositoriesApi.class);
Integer count = repositoryData.checkRepository(currentActiveAccountId, repoOwner, repoName);
if(count == 0) {
long id = repositoryData.insertRepository(currentActiveAccountId, repoOwner, repoName);
tinyDB.putLong("repositoryId", id);
}
else {
Repository data = repositoryData.getRepository(currentActiveAccountId, repoOwner, repoName);
tinyDB.putLong("repositoryId", data.getRepositoryId());
}
ctx.startActivity(repoIntent);
finish();
}
else {
ctx.startActivity(mainIntent);
finish();
Log.e("onFailure-goToRepo", String.valueOf(response.code()));
}
}
@Override
public void onFailure(@NonNull Call<UserRepositories> call, @NonNull Throwable t) {
ctx.startActivity(mainIntent);
finish();
Log.e("onFailure-goToRepo", t.toString());
}
});
}
private void getUserOrOrg(String url, String instanceToken, String userOrgName) {
Call<Organization> call = RetrofitClient.getApiInterface(ctx, url).getOrganization(instanceToken, userOrgName);
call.enqueue(new Callback<Organization>() {
@Override
public void onResponse(@NotNull Call<Organization> call, @NotNull Response<Organization> response) {
if(response.code() == 404) { // org doesn't exist or it's a user user
Log.d("getUserOrOrg-404", String.valueOf(response.code()));
getUser(url, instanceToken, userOrgName);
}
else if(response.code() == 200) { // org
assert response.body() != null;
orgIntent.putExtra("orgName", response.body().getUsername());
TinyDB tinyDb = TinyDB.getInstance(ctx);
tinyDb.putString("orgName", response.body().getUsername());
tinyDb.putString("organizationId", String.valueOf(response.body().getId()));
tinyDb.putBoolean("organizationAction", true);
ctx.startActivity(orgIntent);
finish();
}
else {
Log.e("getUserOrOrg-code", String.valueOf(response.code()));
ctx.startActivity(mainIntent);
finish();
}
}
@Override
public void onFailure(@NotNull Call<Organization> call, @NotNull Throwable t) {
Log.e("onFailure-getUserOrOrg", t.toString());
}
});
}
private void getUser(String url, String instanceToken, String userName) {
Call<UserInfo> call = RetrofitClient.getApiInterface(ctx, url).getUserProfile(instanceToken, userName);
call.enqueue(new Callback<UserInfo>() {
@Override
public void onResponse(@NotNull Call<UserInfo> call, @NotNull Response<UserInfo> response) {
if(response.code() == 200) {
assert response.body() != null;
userIntent.putExtra("username", response.body().getLogin());
ctx.startActivity(userIntent);
}
else {
Log.e("getUser-code", String.valueOf(response.code()));
ctx.startActivity(mainIntent);
}
finish();
}
@Override
public void onFailure(@NotNull Call<UserInfo> call, @NotNull Throwable t) {
Log.e("onFailure-getUser", t.toString());
ctx.startActivity(mainIntent);
finish();
}
});
}
private void getFile(String url, String instanceToken, String owner, String repo, String filePath, String branch) {
Call<Files> call = RetrofitClient.getApiInterface(ctx, url).getSingleFileContents(instanceToken, owner, repo, filePath, branch);
call.enqueue(new Callback<Files>() {
@Override
public void onResponse(@NotNull Call<Files> call, @NotNull Response<Files> response) {
if(response.code() == 200) {
// check if file and open file/dir
Files file = response.body();
assert file != null;
if(file.getType().equals("file")) {
repoIntent.putExtra("file", file);
repoIntent.putExtra("branch", branch);
goToRepoSection(url, instanceToken, owner, repo, "file");
}
}
else {
Log.e("getFile-onFailure", String.valueOf(response.code()));
ctx.startActivity(mainIntent);
finish();
}
}
@Override
public void onFailure(@NotNull Call<Files> call, @NotNull Throwable t) {
Log.e("getFile-onFailure", t.toString());
// maybe it's a directory
getDir(url, instanceToken, owner, repo, filePath, branch);
}
});
}
private void getDir(String url, String instanceToken, String owner, String repo, String filePath, String branch) {
repoIntent.putExtra("branch", branch);
repoIntent.putExtra("dir", filePath);
goToRepoSection(url, instanceToken, owner, repo, "dir");
}
private void showNoActionButtons() {
viewBinding.progressBar.setVisibility(View.GONE);
if(tinyDB.getInt("defaultScreenId") == 1) { // repos
mainIntent.putExtra("launchFragmentByLinkHandler", "repos");
ctx.startActivity(mainIntent);
finish();
}
else if(tinyDB.getInt("defaultScreenId") == 2) { // org
mainIntent.putExtra("launchFragmentByLinkHandler", "org");
ctx.startActivity(mainIntent);
finish();
}
else if(tinyDB.getInt("defaultScreenId") == 3) { // notifications
mainIntent.putExtra("launchFragmentByLinkHandler", "notification");
ctx.startActivity(mainIntent);
finish();
}
else if(tinyDB.getInt("defaultScreenId") == 4) { // explore
mainIntent.putExtra("launchFragmentByLinkHandler", "explore");
ctx.startActivity(mainIntent);
finish();
}
else if(tinyDB.getInt("defaultScreenId") == 0) { // show options
viewBinding.noActionFrame.setVisibility(View.VISIBLE);
viewBinding.addNewAccountFrame.setVisibility(View.GONE);
viewBinding.repository.setOnClickListener(repository -> {
tinyDB.putInt("defaultScreenId", 1);
mainIntent.putExtra("launchFragmentByLinkHandler", "repos");
ctx.startActivity(mainIntent);
finish();
});
viewBinding.organization.setOnClickListener(organization -> {
tinyDB.putInt("defaultScreenId", 2);
mainIntent.putExtra("launchFragmentByLinkHandler", "org");
ctx.startActivity(mainIntent);
finish();
});
viewBinding.notification.setOnClickListener(notification -> {
tinyDB.putInt("defaultScreenId", 3);
mainIntent.putExtra("launchFragmentByLinkHandler", "notification");
ctx.startActivity(mainIntent);
finish();
});
viewBinding.explore.setOnClickListener(explore -> {
tinyDB.putInt("defaultScreenId", 4);
mainIntent.putExtra("launchFragmentByLinkHandler", "explore");
ctx.startActivity(mainIntent);
finish();
});
viewBinding.launchApp2.setOnClickListener(launchApp2 -> {
tinyDB.putInt("defaultScreenId", 0);
ctx.startActivity(mainIntent);
finish();
});
}
}
}

View File

@ -1,44 +1,42 @@
package org.mian.gitnex.activities;
import androidx.annotation.NonNull;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import android.annotation.SuppressLint;
import android.app.DatePickerDialog;
import android.content.Context;
import android.graphics.PorterDuff;
import android.graphics.drawable.GradientDrawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
import android.widget.Button;
import android.widget.DatePicker;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.Spinner;
import android.widget.TextView;
import androidx.annotation.NonNull;
import com.google.gson.JsonElement;
import com.hendraanggrian.appcompat.socialview.Mention;
import com.hendraanggrian.appcompat.widget.MentionArrayAdapter;
import com.hendraanggrian.appcompat.widget.SocialAutoCompleteTextView;
import org.gitnex.tea4j.models.CreateIssue;
import org.gitnex.tea4j.models.Issues;
import org.gitnex.tea4j.models.Milestones;
import org.mian.gitnex.R;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.databinding.ActivityEditIssueBinding;
import org.mian.gitnex.helpers.AlertDialogs;
import org.mian.gitnex.helpers.AppUtil;
import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.helpers.Constants;
import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.models.Collaborators;
import org.mian.gitnex.models.CreateIssue;
import org.mian.gitnex.models.Issues;
import org.mian.gitnex.models.Milestones;
import org.mian.gitnex.util.AppUtil;
import org.mian.gitnex.util.TinyDB;
import org.mian.gitnex.helpers.Version;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
/**
* Author M M Arif
@ -46,55 +44,74 @@ import java.util.List;
public class EditIssueActivity extends BaseActivity implements View.OnClickListener {
final Context ctx = this;
private View.OnClickListener onClickListener;
private int resultLimit = Constants.resultLimitOldGiteaInstances;
private EditText editIssueTitle;
private SocialAutoCompleteTextView editIssueDescription;
private EditText editIssueDescription;
private TextView editIssueDueDate;
private Button editIssueButton;
private Spinner editIssueMilestoneSpinner;
private AutoCompleteTextView editIssueMilestoneSpinner;
private String msState = "open";
private int milestoneId;
List<Milestones> milestonesList = new ArrayList<>();
private ArrayAdapter<Mention> defaultMentionAdapter;
@Override
protected int getLayoutResourceId(){
return R.layout.activity_edit_issue;
}
private String loginUid;
private String instanceToken;
private String repoOwner;
private String repoName;
private int issueIndex;
@SuppressLint("ClickableViewAccessibility")
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final TinyDB tinyDb = new TinyDB(getApplicationContext());
ActivityEditIssueBinding activityEditIssueBinding = ActivityEditIssueBinding.inflate(getLayoutInflater());
setContentView(activityEditIssueBinding.getRoot());
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");
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
loginUid = tinyDB.getString("loginUid");
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 issueIndex = Integer.parseInt(tinyDb.getString("issueNumber"));
repoOwner = parts[0];
repoName = parts[1];
issueIndex = Integer.parseInt(tinyDB.getString("issueNumber"));
ImageView closeActivity = findViewById(R.id.close);
editIssueButton = findViewById(R.id.editIssueButton);
TextView toolbar_title = findViewById(R.id.toolbar_title);
editIssueTitle = findViewById(R.id.editIssueTitle);
editIssueDescription = findViewById(R.id.editIssueDescription);
editIssueDueDate = findViewById(R.id.editIssueDueDate);
ImageView closeActivity = activityEditIssueBinding.close;
editIssueButton = activityEditIssueBinding.editIssueButton;
TextView toolbar_title = activityEditIssueBinding.toolbarTitle;
editIssueTitle = activityEditIssueBinding.editIssueTitle;
editIssueDescription = activityEditIssueBinding.editIssueDescription;
editIssueDueDate = activityEditIssueBinding.editIssueDueDate;
defaultMentionAdapter = new MentionArrayAdapter<>(this);
loadCollaboratorsList();
// if gitea is 1.12 or higher use the new limit
if(new Version(tinyDB.getString("giteaVersion")).higherOrEqual("1.12.0")) {
resultLimit = Constants.resultLimitNewGiteaInstances;
}
editIssueTitle.requestFocus();
assert imm != null;
imm.showSoftInput(editIssueTitle, InputMethodManager.SHOW_IMPLICIT);
editIssueDescription.setOnTouchListener((touchView, motionEvent) -> {
touchView.getParent().requestDisallowInterceptTouchEvent(true);
if ((motionEvent.getAction() & MotionEvent.ACTION_UP) != 0 && (motionEvent.getActionMasked() & MotionEvent.ACTION_UP) != 0) {
touchView.getParent().requestDisallowInterceptTouchEvent(false);
}
return false;
});
editIssueMilestoneSpinner = findViewById(R.id.editIssueMilestoneSpinner);
editIssueMilestoneSpinner.getBackground().setColorFilter(getResources().getColor(R.color.white), PorterDuff.Mode.SRC_ATOP);
editIssueDescription.setMentionAdapter(defaultMentionAdapter);
initCloseListener();
closeActivity.setOnClickListener(onClickListener);
@ -102,97 +119,30 @@ public class EditIssueActivity extends BaseActivity implements View.OnClickListe
editIssueDueDate.setOnClickListener(this);
editIssueButton.setOnClickListener(this);
if(!tinyDb.getString("issueNumber").isEmpty()) {
if(!tinyDB.getString("issueNumber").isEmpty()) {
if(tinyDB.getString("issueType").equalsIgnoreCase("Pull")) {
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)));
}
}
disableProcessButton();
getIssue(instanceUrl, instanceToken, loginUid, repoOwner, repoName, issueIndex);
}
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());
}
});
getIssue(instanceToken, loginUid, repoOwner, repoName, issueIndex, resultLimit);
}
private void initCloseListener() {
onClickListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
finish();
}
};
onClickListener = view -> finish();
}
private void processEditIssue() {
boolean connToInternet = AppUtil.haveNetworkConnection(getApplicationContext());
TinyDB tinyDb = new TinyDB(getApplicationContext());
final String instanceUrl = tinyDb.getString("instanceUrl");
final String loginUid = tinyDb.getString("loginUid");
String repoFullName = tinyDb.getString("repoFullName");
String[] parts = repoFullName.split("/");
final String repoOwner = parts[0];
final String repoName = parts[1];
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
final int issueIndex = Integer.parseInt(tinyDb.getString("issueNumber"));
Milestones mModel = (Milestones) editIssueMilestoneSpinner.getSelectedItem();
int editIssueMilestoneId = mModel.getId();
boolean connToInternet = AppUtil.hasNetworkConnection(appCtx);
String editIssueTitleForm = editIssueTitle.getText().toString();
String editIssueDescriptionForm = editIssueDescription.getText().toString();
@ -200,47 +150,36 @@ public class EditIssueActivity extends BaseActivity implements View.OnClickListe
if(!connToInternet) {
Toasty.info(getApplicationContext(), getResources().getString(R.string.checkNetConnection));
Toasty.error(ctx, getResources().getString(R.string.checkNetConnection));
return;
}
if (editIssueTitleForm.equals("")) {
Toasty.info(getApplicationContext(), getString(R.string.issueTitleEmpty));
Toasty.error(ctx, getString(R.string.issueTitleEmpty));
return;
}
/*if (editIssueDescriptionForm.equals("")) {
Toasty.info(getApplicationContext(), getString(R.string.issueDescriptionEmpty));
return;
}*/
if (editIssueDueDateForm.equals("")) {
editIssueDueDateForm = null;
} else {
}
else {
editIssueDueDateForm = (AppUtil.customDateCombine(AppUtil.customDateFormat(editIssueDueDateForm)));
}
//Log.i("editIssueDueDateForm", String.valueOf(editIssueDueDateForm));
disableProcessButton();
editIssue(instanceUrl, instanceToken, repoOwner, repoName, issueIndex, loginUid, editIssueTitleForm, editIssueDescriptionForm, editIssueDueDateForm, editIssueMilestoneId);
editIssue(instanceToken, repoOwner, repoName, issueIndex, loginUid, editIssueTitleForm, editIssueDescriptionForm, editIssueDueDateForm, milestoneId);
}
private void editIssue(String instanceUrl, String instanceToken, String repoOwner, String repoName, int issueIndex, String loginUid, String title, String description, String dueDate, int editIssueMilestoneId) {
private void editIssue(String instanceToken, String repoOwner, String repoName, int issueIndex, String loginUid, String title, String description, String dueDate, int milestoneId) {
final TinyDB tinyDb = new TinyDB(getApplicationContext());
CreateIssue issueData = new CreateIssue(title, description, dueDate, editIssueMilestoneId);
CreateIssue issueData = new CreateIssue(title, description, dueDate, milestoneId);
Call<JsonElement> call = RetrofitClient
.getInstance(instanceUrl, getApplicationContext())
.getApiInterface()
.patchIssue(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName, issueIndex, issueData);
.getApiInterface(ctx)
.patchIssue(Authorization.get(ctx), repoOwner, repoName, issueIndex, issueData);
call.enqueue(new Callback<JsonElement>() {
@ -249,17 +188,18 @@ public class EditIssueActivity extends BaseActivity implements View.OnClickListe
if(response.code() == 201) {
if(tinyDb.getString("issueType").equals("pr")) {
Toasty.info(getApplicationContext(), getString(R.string.editPrSuccessMessage));
if(tinyDB.getString("issueType").equalsIgnoreCase("Pull")) {
Toasty.success(ctx, getString(R.string.editPrSuccessMessage));
}
else {
Toasty.info(getApplicationContext(), getString(R.string.editIssueSuccessMessage));
Toasty.success(ctx, getString(R.string.editIssueSuccessMessage));
}
tinyDb.putBoolean("issueEdited", true);
tinyDb.putBoolean("resumeIssues", true);
tinyDB.putBoolean("issueEdited", true);
tinyDB.putBoolean("resumeIssues", true);
finish();
}
else if(response.code() == 401) {
@ -268,19 +208,17 @@ public class EditIssueActivity extends BaseActivity implements View.OnClickListe
getResources().getString(R.string.alertDialogTokenRevokedMessage),
getResources().getString(R.string.alertDialogTokenRevokedCopyNegativeButton),
getResources().getString(R.string.alertDialogTokenRevokedCopyPositiveButton));
}
else {
enableProcessButton();
Toasty.info(getApplicationContext(), getString(R.string.genericError));
Toasty.error(ctx, getString(R.string.genericError));
}
}
@Override
public void onFailure(@NonNull Call<JsonElement> call, @NonNull Throwable t) {
Log.e("onFailure", t.toString());
enableProcessButton();
}
@ -288,7 +226,6 @@ public class EditIssueActivity extends BaseActivity implements View.OnClickListe
}
@Override
public void onClick(View v) {
@ -300,31 +237,21 @@ public class EditIssueActivity extends BaseActivity implements View.OnClickListe
final int mDay = c.get(Calendar.DAY_OF_MONTH);
DatePickerDialog datePickerDialog = new DatePickerDialog(this,
new DatePickerDialog.OnDateSetListener() {
@Override
public void onDateSet(DatePicker view, int year,
int monthOfYear, int dayOfMonth) {
editIssueDueDate.setText(getString(R.string.setDueDate, year, (monthOfYear + 1), dayOfMonth));
}
}, mYear, mMonth, mDay);
(view, year, monthOfYear, dayOfMonth) -> editIssueDueDate.setText(getString(R.string.setDueDate, year, (monthOfYear + 1), dayOfMonth)), mYear, mMonth, mDay);
datePickerDialog.show();
}
else if(v == editIssueButton) {
processEditIssue();
}
}
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 instanceToken, final String loginUid, final String repoOwner, final String repoName, int issueIndex, int resultLimit) {
Call<Issues> call = RetrofitClient
.getInstance(instanceUrl, getApplicationContext())
.getApiInterface()
.getIssueByIndex(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName, issueIndex);
.getApiInterface(ctx)
.getIssueByIndex(Authorization.get(ctx), repoOwner, repoName, issueIndex);
call.enqueue(new Callback<Issues>() {
@ -337,27 +264,27 @@ public class EditIssueActivity extends BaseActivity implements View.OnClickListe
editIssueTitle.setText(response.body().getTitle());
editIssueDescription.setText(response.body().getBody());
int msId = 0;
int currentMilestoneId = 0;
if(response.body().getMilestone() != null) {
msId = response.body().getMilestone().getId();
currentMilestoneId = response.body().getMilestone().getId();
}
// get milestones list
if(response.body().getId() > 0) {
Call<List<Milestones>> call_ = RetrofitClient
.getInstance(instanceUrl, getApplicationContext())
.getApiInterface()
.getMilestones(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName, msState);
.getApiInterface(ctx)
.getMilestones(Authorization.get(ctx), repoOwner, repoName, 1, resultLimit, msState);
final int finalMsId = msId;
int checkMilestoneId = currentMilestoneId;
call_.enqueue(new Callback<List<Milestones>>() {
call_.enqueue(new Callback<List<Milestones>>() {
@Override
public void onResponse(@NonNull Call<List<Milestones>> call, @NonNull retrofit2.Response<List<Milestones>> response_) {
int finalMsId1 = 0;
int getSelectedMilestoneId = 0;
if (response_.code() == 200) {
@ -365,39 +292,40 @@ public class EditIssueActivity extends BaseActivity implements View.OnClickListe
milestonesList.add(new Milestones(0, "No milestone"));
assert milestonesList_ != null;
if (milestonesList_.size() > 0) {
milestonesList.addAll(milestonesList_);
for (int i = 0; i < milestonesList_.size(); i++) {
Milestones data = new Milestones(
milestonesList_.get(i).getId(),
milestonesList_.get(i).getTitle()
);
milestonesList.add(data);
if(finalMsId == milestonesList_.get(i).getId()) {
finalMsId1 = i + 1;
if(checkMilestoneId == milestonesList_.get(i).getId()) {
getSelectedMilestoneId = i + 1;
}
}
}
ArrayAdapter<Milestones> adapter_ = new ArrayAdapter<>(getApplicationContext(),
R.layout.spinner_item, milestonesList);
ArrayAdapter<Milestones> adapter = new ArrayAdapter<>(EditIssueActivity.this,
R.layout.list_spinner_items, milestonesList);
adapter_.setDropDownViewResource(R.layout.spinner_dropdown_item);
editIssueMilestoneSpinner.setAdapter(adapter_);
editIssueMilestoneSpinner.setAdapter(adapter);
editIssueMilestoneSpinner.setOnItemClickListener ((parent, view, position, id) -> milestoneId = milestonesList.get(position).getId());
int finalMsId = getSelectedMilestoneId;
new Handler(Looper.getMainLooper()).postDelayed(() -> {
editIssueMilestoneSpinner.setText(milestonesList.get(finalMsId).getTitle(),false);
milestoneId = milestonesList.get(finalMsId).getId();
}, 500);
if(milestonesList_.size() > 0) {
editIssueMilestoneSpinner.setSelection(finalMsId1);
}
enableProcessButton();
}
}
@Override
public void onFailure(@NonNull Call<List<Milestones>> call, @NonNull Throwable t) {
Log.e("onFailure", t.toString());
}
});
@ -410,7 +338,6 @@ public class EditIssueActivity extends BaseActivity implements View.OnClickListe
@SuppressLint("SimpleDateFormat") DateFormat formatter = new SimpleDateFormat("yyyy-M-dd");
String dueDate = formatter.format(response.body().getDue_date());
editIssueDueDate.setText(dueDate);
}
//enableProcessButton();
@ -421,18 +348,16 @@ public class EditIssueActivity extends BaseActivity implements View.OnClickListe
getResources().getString(R.string.alertDialogTokenRevokedMessage),
getResources().getString(R.string.alertDialogTokenRevokedCopyNegativeButton),
getResources().getString(R.string.alertDialogTokenRevokedCopyPositiveButton));
}
else {
Toasty.info(getApplicationContext(), getString(R.string.genericError));
Toasty.error(ctx, getString(R.string.genericError));
}
}
@Override
public void onFailure(@NonNull Call<Issues> call, @NonNull Throwable t) {
Log.e("onFailure", t.toString());
}
});
@ -442,21 +367,11 @@ public class EditIssueActivity extends BaseActivity implements View.OnClickListe
private void disableProcessButton() {
editIssueButton.setEnabled(false);
GradientDrawable shape = new GradientDrawable();
shape.setCornerRadius( 8 );
shape.setColor(getResources().getColor(R.color.hintColor));
editIssueButton.setBackground(shape);
}
private void enableProcessButton() {
editIssueButton.setEnabled(true);
GradientDrawable shape = new GradientDrawable();
shape.setCornerRadius( 8 );
shape.setColor(getResources().getColor(R.color.btnBackground));
editIssueButton.setBackground(shape);
}
}

View File

@ -1,30 +1,28 @@
package org.mian.gitnex.activities;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import android.widget.ListView;
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.FilenameUtils;
import org.gitnex.tea4j.models.FileDiffView;
import org.mian.gitnex.R;
import org.mian.gitnex.adapters.FilesDiffAdapter;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.databinding.ActivityFileDiffBinding;
import org.mian.gitnex.helpers.AlertDialogs;
import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.helpers.ParseDiff;
import org.mian.gitnex.helpers.TinyDB;
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 org.mian.gitnex.helpers.Version;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
/**
* Author M M Arif
@ -32,188 +30,117 @@ import retrofit2.Callback;
public class FileDiffActivity extends BaseActivity {
private View.OnClickListener onClickListener;
private TextView toolbar_title;
private RecyclerView mRecyclerView;
private ProgressBar mProgressBar;
private View.OnClickListener onClickListener;
private TextView toolbarTitle;
private ListView mListView;
private ProgressBar mProgressBar;
@Override
protected int getLayoutResourceId(){
return R.layout.activity_file_diff;
}
@Override
public void onCreate(Bundle savedInstanceState) {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
super.onCreate(savedInstanceState);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
ActivityFileDiffBinding activityFileDiffBinding = ActivityFileDiffBinding.inflate(getLayoutInflater());
setContentView(activityFileDiffBinding.getRoot());
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");
Toolbar toolbar = activityFileDiffBinding.toolbar;
setSupportActionBar(toolbar);
ImageView closeActivity = findViewById(R.id.close);
toolbar_title = findViewById(R.id.toolbar_title);
mRecyclerView = findViewById(R.id.recyclerView);
mProgressBar = findViewById(R.id.progress_bar);
final TinyDB tinyDb = TinyDB.getInstance(appCtx);
String repoFullName = tinyDb.getString("repoFullName");
String[] parts = repoFullName.split("/");
final String repoOwner = parts[0];
final String repoName = parts[1];
mRecyclerView.setHasFixedSize(true);
mRecyclerView.setLayoutManager(new LinearLayoutManager(getApplicationContext()));
ImageView closeActivity = activityFileDiffBinding.close;
toolbarTitle = activityFileDiffBinding.toolbarTitle;
mListView = activityFileDiffBinding.listView;
mProgressBar = activityFileDiffBinding.progressBar;
toolbar_title.setText(R.string.processingText);
initCloseListener();
closeActivity.setOnClickListener(onClickListener);
mListView.setDivider(null);
mProgressBar.setVisibility(View.VISIBLE);
toolbarTitle.setText(R.string.processingText);
initCloseListener();
closeActivity.setOnClickListener(onClickListener);
String fileDiffName = tinyDb.getString("issueNumber")+".diff";
mProgressBar.setVisibility(View.VISIBLE);
getFileContents(tinyDb.getString("instanceUrlWithProtocol"), repoOwner, repoName, fileDiffName);
String pullIndex = tinyDb.getString("issueNumber");
}
boolean apiCall = !new Version(tinyDb.getString("giteaVersion")).less("1.13.0");
getPullDiffContent(repoOwner, repoName, pullIndex, apiCall);
private void getFileContents(String instanceUrl, String owner, String repo, String filename) {
}
Call<ResponseBody> call = RetrofitClient
.getInstance(instanceUrl, getApplicationContext())
.getApiInterface()
.getFileDiffContents(owner, repo, filename);
private void getPullDiffContent(String owner, String repo, String pullIndex, boolean apiCall) {
call.enqueue(new Callback<ResponseBody>() {
Thread thread = new Thread(() -> {
@Override
public void onResponse(@NonNull Call<ResponseBody> call, @NonNull retrofit2.Response<ResponseBody> response) {
Call<ResponseBody> call = apiCall ?
RetrofitClient.getApiInterface(ctx).getPullDiffContent(Authorization.get(ctx), owner, repo, pullIndex) :
RetrofitClient.getWebInterface(ctx).getPullDiffContent(Authorization.getWeb(ctx), owner, repo, pullIndex);
if (response.code() == 200) {
try {
try {
assert response.body() != null;
Response<ResponseBody> response = call.execute();
assert response.body() != null;
AppUtil appUtil = new AppUtil();
List<FileDiffView> fileContentsArray = new ArrayList<>();
switch(response.code()) {
String[] lines = response.body().string().split("diff");
case 200:
List<FileDiffView> fileDiffViews = ParseDiff.getFileDiffViewArray(response.body().string());
if(lines.length > 0) {
int filesCount = fileDiffViews.size();
for (int i = 1; i < lines.length; i++) {
String toolbarTitleText = (filesCount > 1) ?
getResources().getString(R.string.fileDiffViewHeader, Integer.toString(filesCount)) :
getResources().getString(R.string.fileDiffViewHeaderSingle, Integer.toString(filesCount));
if(lines[i].contains("@@ -")) {
FilesDiffAdapter adapter = new FilesDiffAdapter(ctx, getSupportFragmentManager(), fileDiffViews);
String[] level2nd = lines[i].split("@@ -"); // main content part of single diff view
runOnUiThread(() -> {
toolbarTitle.setText(toolbarTitleText);
mListView.setAdapter(adapter);
mProgressBar.setVisibility(View.GONE);
});
break;
String[] fileName_ = level2nd[0].split("\\+\\+\\+ b/"); // filename part
String fileNameFinal = fileName_[1];
case 401:
runOnUiThread(() -> AlertDialogs.authorizationTokenRevokedDialog(ctx,
getString(R.string.alertDialogTokenRevokedTitle),
getString(R.string.alertDialogTokenRevokedMessage),
getString(R.string.alertDialogTokenRevokedCopyNegativeButton),
getString(R.string.alertDialogTokenRevokedCopyPositiveButton)));
break;
String[] fileContents_ = level2nd[1].split("@@"); // file info / content part
String fileInfoFinal = fileContents_[0];
String fileContentsFinal = (fileContents_[1]);
case 403:
runOnUiThread(() -> Toasty.error(ctx, ctx.getString(R.string.authorizeError)));
break;
if(level2nd.length > 2) {
for (int j = 2; j < level2nd.length; j++) {
fileContentsFinal += (level2nd[j]);
}
}
case 404:
runOnUiThread(() -> Toasty.warning(ctx, ctx.getString(R.string.apiNotFound)));
break;
String fileExtension = FilenameUtils.getExtension(fileNameFinal);
default:
runOnUiThread(() -> Toasty.error(ctx, getString(R.string.labelGeneralError)));
String fileContentsFinalWithBlankLines = fileContentsFinal.replaceAll( ".*@@.*", "" );
String fileContentsFinalWithoutBlankLines = fileContentsFinal.replaceAll( ".*@@.*(\r?\n|\r)?", "" );
fileContentsFinalWithoutBlankLines = fileContentsFinalWithoutBlankLines.replaceAll( ".*\\ No newline at end of file.*(\r?\n|\r)?", "" );
}
} catch(IOException ignored) {}
fileContentsArray.add(new FileDiffView(fileNameFinal, appUtil.imageExtension(fileExtension), fileInfoFinal, fileContentsFinalWithoutBlankLines));
}
else {
});
String[] getFileName = lines[i].split("--git a/");
thread.start();
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);
private void initCloseListener() {
String fileExtension = FilenameUtils.getExtension(getFileNameFinal);
onClickListener = view -> {
if(appUtil.imageExtension(FilenameUtils.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();
}
};
}
getIntent().removeExtra("singleFileName");
finish();
};
}
}

View File

@ -1,52 +1,41 @@
package org.mian.gitnex.activities;
import android.app.Activity;
import android.app.NotificationManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.BitmapFactory;
import android.content.Intent;
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.Environment;
import android.text.method.ScrollingMovementMethod;
import android.util.Base64;
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.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.annotation.NonNull;
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.FilenameUtils;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.core.app.NotificationCompat;
import com.vdurmont.emoji.EmojiParser;
import org.apache.commons.io.FileUtils;
import org.gitnex.tea4j.models.Files;
import org.mian.gitnex.R;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.databinding.ActivityFileViewBinding;
import org.mian.gitnex.fragments.BottomSheetFileViewerFragment;
import org.mian.gitnex.helpers.AlertDialogs;
import org.mian.gitnex.helpers.AppUtil;
import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.helpers.Constants;
import org.mian.gitnex.helpers.Images;
import org.mian.gitnex.helpers.Markdown;
import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.models.Files;
import org.mian.gitnex.util.AppUtil;
import org.mian.gitnex.util.TinyDB;
import java.io.File;
import java.io.FileOutputStream;
import org.mian.gitnex.notifications.Notifications;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.Objects;
import java.io.OutputStream;
import java.util.Arrays;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
/**
* Author M M Arif
@ -54,340 +43,356 @@ import retrofit2.Callback;
public class FileViewActivity extends BaseActivity implements BottomSheetFileViewerFragment.BottomSheetListener {
private View.OnClickListener onClickListener;
private TextView singleFileContents;
private LinearLayout singleFileContentsFrame;
private HighlightJsView singleCodeContents;
private PhotoView imageView;
final Context ctx = this;
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;
private ActivityFileViewBinding binding;
private Files file;
@Override
protected int getLayoutResourceId(){
return R.layout.activity_file_view;
}
@Override
public void onCreate(Bundle savedInstanceState) {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
super.onCreate(savedInstanceState);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
binding = ActivityFileViewBinding.inflate(getLayoutInflater());
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");
setContentView(binding.getRoot());
setSupportActionBar(binding.toolbar);
ImageView closeActivity = findViewById(R.id.close);
singleFileContents = findViewById(R.id.singleFileContents);
singleCodeContents = findViewById(R.id.singleCodeContents);
imageView = findViewById(R.id.imageView);
mProgressBar = findViewById(R.id.progress_bar);
pdfView = findViewById(R.id.pdfView);
pdfViewFrame = findViewById(R.id.pdfViewFrame);
singleFileContentsFrame = findViewById(R.id.singleFileContentsFrame);
tinyDB.putBoolean("enableMarkdownInFileView", false);
String singleFileName = getIntent().getStringExtra("singleFileName");
file = (Files) getIntent().getSerializableExtra("file");
TextView toolbar_title = findViewById(R.id.toolbar_title);
toolbar_title.setMovementMethod(new ScrollingMovementMethod());
binding.close.setOnClickListener(view -> finish());
initCloseListener();
closeActivity.setOnClickListener(onClickListener);
tinyDb.putString("downloadFileContents", "");
binding.toolbarTitle.setMovementMethod(new ScrollingMovementMethod());
binding.toolbarTitle.setText(file.getPath());
try {
singleFileName = URLDecoder.decode(singleFileName, "UTF-8");
singleFileName = singleFileName.replaceAll("//", "/");
singleFileName = singleFileName.startsWith("/") ? singleFileName.substring(1) : singleFileName;
}
catch (UnsupportedEncodingException e) {
String repoFullName = tinyDB.getString("repoFullName");
String repoBranch = tinyDB.getString("repoBranch");
String[] parts = repoFullName.split("/");
String repoOwner = parts[0];
String repoName = parts[1];
assert singleFileName != null;
Log.i("singleFileName", singleFileName);
getSingleFileContents(repoOwner, repoName, file.getPath(), repoBranch);
}
toolbar_title.setText(singleFileName);
}
getSingleFileContents(instanceUrl, instanceToken, repoOwner, repoName, singleFileName);
}
@Override
public void onResume() {
private void getSingleFileContents(String instanceUrl, String token, final String owner, String repo, final String filename) {
super.onResume();
final TinyDB tinyDb = new TinyDB(getApplicationContext());
if(tinyDB.getBoolean("fileModified")) {
String repoFullName = tinyDB.getString("repoFullName");
String repoBranch = tinyDB.getString("repoBranch");
String[] parts = repoFullName.split("/");
String repoOwner = parts[0];
String repoName = parts[1];
Call<Files> call = RetrofitClient
.getInstance(instanceUrl, getApplicationContext())
.getApiInterface()
.getSingleFileContents(token, owner, repo, filename);
getSingleFileContents(repoOwner, repoName, file.getPath(), repoBranch);
tinyDB.putBoolean("fileModified", false);
}
}
call.enqueue(new Callback<Files>() {
private void getSingleFileContents(final String owner, String repo, final String filename, String ref) {
@Override
public void onResponse(@NonNull Call<Files> call, @NonNull retrofit2.Response<Files> response) {
Thread thread = new Thread(() -> {
if (response.code() == 200) {
Call<ResponseBody> call = RetrofitClient
.getWebInterface(ctx)
.getFileContents(Authorization.getWeb(ctx), owner, repo, ref, filename);
AppUtil appUtil = new AppUtil();
assert response.body() != null;
try {
if(!response.body().getContent().equals("")) {
Response<ResponseBody> response = call.execute();
String fileExtension = FilenameUtils.getExtension(filename);
mProgressBar.setVisibility(View.GONE);
if(response.code() == 200) {
// download file meta
tinyDb.putString("downloadFileName", filename);
tinyDb.putString("downloadFileContents", response.body().getContent());
ResponseBody responseBody = response.body();
if(appUtil.imageExtension(fileExtension)) { // file is image
if(responseBody != null) {
singleFileContentsFrame.setVisibility(View.GONE);
singleCodeContents.setVisibility(View.GONE);
pdfViewFrame.setVisibility(View.GONE);
imageView.setVisibility(View.VISIBLE);
runOnUiThread(() -> binding.progressBar.setVisibility(View.GONE));
String fileExtension = FileUtils.getExtension(filename);
imageData = Base64.decode(response.body().getContent(), Base64.DEFAULT);
Drawable imageDrawable = new BitmapDrawable(getResources(), BitmapFactory.decodeByteArray(imageData, 0, imageData.length));
imageView.setImageDrawable(imageDrawable);
boolean processable = false;
}
else if (appUtil.sourceCodeExtension(fileExtension)) { // file is sourcecode
switch(AppUtil.getFileType(fileExtension)) {
imageView.setVisibility(View.GONE);
singleFileContentsFrame.setVisibility(View.GONE);
pdfViewFrame.setVisibility(View.GONE);
singleCodeContents.setVisibility(View.VISIBLE);
case IMAGE:
singleCodeContents.setTheme(Theme.GRUVBOX_DARK);
singleCodeContents.setShowLineNumbers(true);
singleCodeContents.setSource(appUtil.decodeBase64(response.body().getContent()));
// See https://developer.android.com/guide/topics/media/media-formats#core
if(Arrays.asList("bmp", "gif", "jpg", "jpeg", "png", "webp", "heic", "heif").contains(fileExtension.toLowerCase())) {
}
else if (appUtil.pdfExtension(fileExtension)) { // file is pdf
processable = true;
imageView.setVisibility(View.GONE);
singleFileContentsFrame.setVisibility(View.GONE);
singleCodeContents.setVisibility(View.GONE);
pdfViewFrame.setVisibility(View.VISIBLE);
byte[] pictureBytes = responseBody.bytes();
pdfNightMode = tinyDb.getBoolean("enablePdfMode");
runOnUiThread(() -> {
binding.contents.setVisibility(View.GONE);
binding.markdownFrame.setVisibility(View.GONE);
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();
binding.photoView.setVisibility(View.VISIBLE);
binding.photoView.setImageBitmap(Images.scaleImage(pictureBytes, 1920));
});
}
break;
}
else if (appUtil.excludeFilesInFileViewerExtension(fileExtension)) { // files need to be excluded
case UNKNOWN:
case TEXT:
imageView.setVisibility(View.GONE);
singleCodeContents.setVisibility(View.GONE);
pdfViewFrame.setVisibility(View.GONE);
singleFileContentsFrame.setVisibility(View.VISIBLE);
if(file.getSize() > Constants.maximumFileViewerSize) {
break;
}
singleFileContents.setText(getResources().getString(R.string.excludeFilesInFileviewer));
singleFileContents.setGravity(Gravity.CENTER);
singleFileContents.setTypeface(null, Typeface.BOLD);
processable = true;
String text = responseBody.string();
}
else { // file type not known - plain text view
runOnUiThread(() -> {
binding.photoView.setVisibility(View.GONE);
imageView.setVisibility(View.GONE);
singleCodeContents.setVisibility(View.GONE);
pdfViewFrame.setVisibility(View.GONE);
singleFileContentsFrame.setVisibility(View.VISIBLE);
binding.contents.setContent(text, fileExtension);
singleFileContents.setText(appUtil.decodeBase64(response.body().getContent()));
if(tinyDB.getBoolean("enableMarkdownInFileView")) {
Markdown.render(ctx, EmojiParser.parseToUnicode(text), binding.markdown);
}
binding.contents.setVisibility(View.GONE);
binding.markdownFrame.setVisibility(View.VISIBLE);
} else {
binding.markdownFrame.setVisibility(View.GONE);
binding.contents.setVisibility(View.VISIBLE);
}
});
break;
}
else {
singleFileContents.setText("");
mProgressBar.setVisibility(View.GONE);
}
}
}
else if(response.code() == 401) {
if(!processable) { // While the file could still be non-binary,
// it's better we don't show it (to prevent any crashes and/or unwanted behavior) and let the user download it instead.
responseBody.close();
AlertDialogs.authorizationTokenRevokedDialog(ctx, getResources().getString(R.string.alertDialogTokenRevokedTitle),
getResources().getString(R.string.alertDialogTokenRevokedMessage),
getResources().getString(R.string.alertDialogTokenRevokedCopyNegativeButton),
getResources().getString(R.string.alertDialogTokenRevokedCopyPositiveButton));
runOnUiThread(() -> {
binding.photoView.setVisibility(View.GONE);
binding.contents.setVisibility(View.GONE);
}
else if(response.code() == 403) {
binding.markdownFrame.setVisibility(View.VISIBLE);
binding.markdown.setText(getString(R.string.excludeFilesInFileViewer));
binding.markdown.setGravity(Gravity.CENTER);
binding.markdown.setTypeface(null, Typeface.BOLD);
});
}
} else {
Toasty.info(ctx, ctx.getString(R.string.authorizeError));
runOnUiThread(() -> {
binding.markdown.setText("");
binding.progressBar.setVisibility(View.GONE);
});
}
} else {
}
else if(response.code() == 404) {
Toasty.info(ctx, ctx.getString(R.string.apiNotFound));
switch(response.code()) {
}
else {
Toasty.info(getApplicationContext(), getString(R.string.labelGeneralError));
}
case 401:
runOnUiThread(() -> AlertDialogs.authorizationTokenRevokedDialog(ctx,
getResources().getString(R.string.alertDialogTokenRevokedTitle),
getResources().getString(R.string.alertDialogTokenRevokedMessage),
getResources().getString(R.string.alertDialogTokenRevokedCopyNegativeButton),
getResources().getString(R.string.alertDialogTokenRevokedCopyPositiveButton)));
break;
}
@Override
public void onFailure(@NonNull Call<Files> call, @NonNull Throwable t) {
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() {
onClickListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
getIntent().removeExtra("singleFileName");
finish();
}
};
}
}
case 403:
runOnUiThread(() -> Toasty.error(ctx, ctx.getString(R.string.authorizeError)));
break;
case 404:
runOnUiThread(() -> Toasty.warning(ctx, ctx.getString(R.string.apiNotFound)));
break;
default:
runOnUiThread(() -> Toasty.error(ctx, getString(R.string.labelGeneralError)));
}
}
} catch(IOException ignored) {}
});
thread.start();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.generic_nav_dotted_menu, menu);
inflater.inflate(R.menu.files_view_menu, menu);
if(!FileUtils.getExtension(file.getName())
.equalsIgnoreCase("md")) {
menu.getItem(0)
.setVisible(false);
}
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if(id == android.R.id.home) {
finish();
return true;
} else if(id == R.id.genericMenu) {
BottomSheetFileViewerFragment bottomSheet = new BottomSheetFileViewerFragment();
bottomSheet.show(getSupportFragmentManager(), "fileViewerBottomSheet");
return true;
} else if(id == R.id.markdown) {
if(!tinyDB.getBoolean("enableMarkdownInFileView")) {
Markdown.render(ctx, EmojiParser.parseToUnicode(binding.contents.getContent()), binding.markdown);
binding.contents.setVisibility(View.GONE);
binding.markdownFrame.setVisibility(View.VISIBLE);
tinyDB.putBoolean("enableMarkdownInFileView", true);
} else {
binding.markdownFrame.setVisibility(View.GONE);
binding.contents.setVisibility(View.VISIBLE);
tinyDB.putBoolean("enableMarkdownInFileView", false);
}
return true;
} else {
return super.onOptionsItemSelected(item);
}
}
@Override
public void onButtonClicked(String text) {
if("downloadFile".equals(text)) {
requestFileDownload();
}
if("deleteFile".equals(text)) {
Intent intent = new Intent(ctx, CreateFileActivity.class);
intent.putExtra("fileAction", CreateFileActivity.FILE_ACTION_DELETE);
intent.putExtra("filePath", file.getPath());
intent.putExtra("fileSha", file.getSha());
ctx.startActivity(intent);
}
if("editFile".equals(text)) {
if(binding.contents.getContent() != null &&
!binding.contents.getContent().isEmpty()) {
Intent intent = new Intent(ctx, CreateFileActivity.class);
intent.putExtra("fileAction", CreateFileActivity.FILE_ACTION_EDIT);
intent.putExtra("filePath", file.getPath());
intent.putExtra("fileSha", file.getSha());
intent.putExtra("fileContents", binding.contents.getContent());
ctx.startActivity(intent);
} else {
Toasty.error(ctx, getString(R.string.fileTypeCannotBeEdited));
}
}
}
private void requestFileDownload() {
Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.putExtra(Intent.EXTRA_TITLE, file.getName());
intent.setType("*/*");
activityResultLauncher.launch(intent);
}
ActivityResultLauncher<Intent> activityResultLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> {
if (result.getResultCode() == Activity.RESULT_OK) {
assert result.getData() != null;
try {
OutputStream outputStream = getContentResolver().openOutputStream(result.getData().getData());
NotificationCompat.Builder builder = new NotificationCompat.Builder(ctx, ctx.getPackageName())
.setContentTitle(getString(R.string.fileViewerNotificationTitleStarted))
.setContentText(getString(R.string.fileViewerNotificationDescriptionStarted, file.getName()))
.setSmallIcon(R.drawable.gitnex_transparent)
.setPriority(NotificationCompat.PRIORITY_LOW)
.setChannelId(Constants.downloadNotificationChannelId)
.setProgress(100, 0, false)
.setOngoing(true);
int notificationId = Notifications.uniqueNotificationId(ctx);
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);;
notificationManager.notify(notificationId, builder.build());
String repoFullName = tinyDB.getString("repoFullName");
String repoBranch = tinyDB.getString("repoBranch");
String[] parts = repoFullName.split("/");
String repoOwner = parts[0];
String repoName = parts[1];
Thread thread = new Thread(() -> {
try {
Call<ResponseBody> call = RetrofitClient
.getWebInterface(ctx)
.getFileContents(Authorization.getWeb(ctx), repoOwner, repoName, repoBranch, file.getPath());
Response<ResponseBody> response = call.execute();
assert response.body() != null;
AppUtil.copyProgress(response.body().byteStream(), outputStream, file.getSize(), progress -> {
builder.setProgress(100, progress, false);
notificationManager.notify(notificationId, builder.build());
});
builder.setContentTitle(getString(R.string.fileViewerNotificationTitleFinished))
.setContentText(getString(R.string.fileViewerNotificationDescriptionFinished, file.getName()));
} catch(IOException ignored) {
builder.setContentTitle(getString(R.string.fileViewerNotificationTitleFailed))
.setContentText(getString(R.string.fileViewerNotificationDescriptionFailed, file.getName()));
} finally {
builder.setProgress(0,0,false)
.setOngoing(false);
notificationManager.notify(notificationId, builder.build());
}
});
thread.start();
} catch(IOException ignored) {}
}
});
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,32 +1,29 @@
package org.mian.gitnex.activities;
import androidx.annotation.NonNull;
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.ArrayAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import com.hendraanggrian.appcompat.socialview.Mention;
import com.hendraanggrian.appcompat.widget.MentionArrayAdapter;
import com.hendraanggrian.appcompat.widget.SocialAutoCompleteTextView;
import androidx.annotation.NonNull;
import com.google.gson.JsonElement;
import org.gitnex.tea4j.models.MergePullRequest;
import org.gitnex.tea4j.models.MergePullRequestSpinner;
import org.mian.gitnex.R;
import org.mian.gitnex.actions.PullRequestActions;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.databinding.ActivityMergePullRequestBinding;
import org.mian.gitnex.helpers.AlertDialogs;
import org.mian.gitnex.helpers.AppUtil;
import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.models.Collaborators;
import org.mian.gitnex.models.MergePullRequest;
import org.mian.gitnex.util.AppUtil;
import org.mian.gitnex.util.TinyDB;
import java.util.List;
import okhttp3.ResponseBody;
import org.mian.gitnex.helpers.Version;
import java.util.ArrayList;
import java.util.Objects;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
/**
* Author M M Arif
@ -34,228 +31,237 @@ import retrofit2.Response;
public class MergePullRequestActivity extends BaseActivity {
public ImageView closeActivity;
private View.OnClickListener onClickListener;
private View.OnClickListener onClickListener;
final Context ctx = this;
private String repoOwner;
private String repoName;
private int prIndex;
private SocialAutoCompleteTextView mergePR;
private ArrayAdapter<Mention> defaultMentionAdapter;
private Button mergeButton;
private ActivityMergePullRequestBinding viewBinding;
@Override
protected int getLayoutResourceId(){
return R.layout.activity_merge_pull_request;
}
private String Do;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@SuppressLint("SetTextI18n")
@Override
public void onCreate(Bundle savedInstanceState) {
boolean connToInternet = AppUtil.haveNetworkConnection(getApplicationContext());
TinyDB tinyDb = new TinyDB(getApplicationContext());
super.onCreate(savedInstanceState);
mergePR = findViewById(R.id.mergePR);
mergePR.setShowSoftInputOnFocus(true);
viewBinding = ActivityMergePullRequestBinding.inflate(getLayoutInflater());
setContentView(viewBinding.getRoot());
defaultMentionAdapter = new MentionArrayAdapter<>(this);
loadCollaboratorsList();
String repoFullName = tinyDB.getString("repoFullName");
String[] parts = repoFullName.split("/");
repoOwner = parts[0];
repoName = parts[1];
prIndex = Integer.parseInt(tinyDB.getString("issueNumber"));
mergePR.setMentionAdapter(defaultMentionAdapter);
boolean connToInternet = AppUtil.hasNetworkConnection(appCtx);
closeActivity = findViewById(R.id.close);
TextView toolbar_title = findViewById(R.id.toolbar_title);
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
if(!tinyDb.getString("issueTitle").isEmpty()) {
toolbar_title.setText(tinyDb.getString("issueTitle"));
}
viewBinding.mergeTitle.requestFocus();
assert imm != null;
imm.showSoftInput(viewBinding.mergeTitle, InputMethodManager.SHOW_IMPLICIT);
initCloseListener();
closeActivity.setOnClickListener(onClickListener);
setMergeAdapter();
mergeButton = findViewById(R.id.mergeButton);
if(!tinyDB.getString("issueTitle").isEmpty()) {
if(!connToInternet) {
viewBinding.toolbarTitle.setText(tinyDB.getString("issueTitle"));
viewBinding.mergeTitle.setText(tinyDB.getString("issueTitle") + " (#" + tinyDB.getString("issueNumber") + ")");
}
disableProcessButton();
initCloseListener();
viewBinding.close.setOnClickListener(onClickListener);
} else {
// if gitea version is greater/equal(1.12.0) than user installed version (installed.higherOrEqual(compareVer))
if(new Version(tinyDB.getString("giteaVersion")).higherOrEqual("1.12.0")) {
mergeButton.setOnClickListener(mergePullRequest);
viewBinding.deleteBranch.setVisibility(View.VISIBLE);
}
}
if(tinyDB.getString("prMergeable").equals("false")) {
}
disableProcessButton();
viewBinding.mergeInfoDisabledMessage.setVisibility(View.VISIBLE);
}
else {
public void loadCollaboratorsList() {
viewBinding.mergeInfoDisabledMessage.setVisibility(View.GONE);
}
final TinyDB tinyDb = new TinyDB(getApplicationContext());
if(tinyDB.getString("prIsFork").equals("true")) {
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];
viewBinding.deleteBranchForkInfo.setVisibility(View.VISIBLE);
}
else {
Call<List<Collaborators>> call = RetrofitClient
.getInstance(instanceUrl, getApplicationContext())
.getApiInterface()
.getCollaborators(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName);
viewBinding.deleteBranchForkInfo.setVisibility(View.GONE);
}
call.enqueue(new Callback<List<Collaborators>>() {
if(!connToInternet) {
@Override
public void onResponse(@NonNull Call<List<Collaborators>> call, @NonNull Response<List<Collaborators>> response) {
disableProcessButton();
}
else {
if (response.isSuccessful()) {
viewBinding.mergeButton.setOnClickListener(mergePullRequest);
}
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 {
private void setMergeAdapter() {
Log.i("onResponse", String.valueOf(response.code()));
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.4 due to a bug
if(new Version(tinyDB.getString("giteaVersion")).higher("1.11.4")) {
}
mergeList.add(new MergePullRequestSpinner("squash", getResources().getString(R.string.mergeOptionSquash)));
}
@Override
public void onFailure(@NonNull Call<List<Collaborators>> call, @NonNull Throwable t) {
Log.i("onFailure", t.toString());
}
ArrayAdapter<MergePullRequestSpinner> adapter = new ArrayAdapter<>(MergePullRequestActivity.this, R.layout.list_spinner_items, mergeList);
viewBinding.mergeSpinner.setAdapter(adapter);
});
}
viewBinding.mergeSpinner.setOnItemClickListener ((parent, view, position, id) -> {
private void initCloseListener() {
onClickListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
finish();
}
};
}
Do = mergeList.get(position).getId();
});
private View.OnClickListener mergePullRequest = new View.OnClickListener() {
public void onClick(View v) {
processMergePullRequest();
}
};
}
private void processMergePullRequest() {
private void initCloseListener() {
String mergePRDT = mergePR.getText().toString();
boolean connToInternet = AppUtil.haveNetworkConnection(getApplicationContext());
onClickListener = view -> finish();
}
if(!connToInternet) {
private final View.OnClickListener mergePullRequest = v -> processMergePullRequest();
Toasty.info(getApplicationContext(), getResources().getString(R.string.checkNetConnection));
return;
private void processMergePullRequest() {
}
String mergePRDesc = Objects.requireNonNull(viewBinding.mergeDescription.getText()).toString();
String mergePRTitle = Objects.requireNonNull(viewBinding.mergeTitle.getText()).toString();
boolean deleteBranch = viewBinding.deleteBranch.isChecked();
disableProcessButton();
String doWhat = "merge";
mergeFunction(doWhat, mergePRDT);
boolean connToInternet = AppUtil.hasNetworkConnection(appCtx);
}
if(!connToInternet) {
private void mergeFunction(String doWhat, String mergePRDT) {
Toasty.error(ctx, getResources().getString(R.string.checkNetConnection));
return;
}
final TinyDB tinyDb = new TinyDB(getApplicationContext());
if(Do == null) {
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"));
Toasty.error(ctx, getResources().getString(R.string.selectMergeStrategy));
}
else {
MergePullRequest mergePR = new MergePullRequest(doWhat, mergePRDT, null);
disableProcessButton();
mergeFunction(Do, mergePRDesc, mergePRTitle, deleteBranch);
}
}
Call<ResponseBody> call = RetrofitClient
.getInstance(instanceUrl, getApplicationContext())
.getApiInterface()
.mergePullRequest(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName, prIndex, mergePR);
private void mergeFunction(String Do, String mergePRDT, String mergeTitle, boolean deleteBranch) {
call.enqueue(new Callback<ResponseBody>() {
MergePullRequest mergePR = new MergePullRequest(Do, mergePRDT, mergeTitle);
@Override
public void onResponse(@NonNull Call<ResponseBody> call, @NonNull retrofit2.Response<ResponseBody> response) {
Call<Void> call = RetrofitClient.getApiInterface(ctx).mergePullRequest(Authorization.get(ctx), repoOwner, repoName, prIndex, mergePR);
if(response.code() == 200) {
call.enqueue(new Callback<Void>() {
Toasty.info(getApplicationContext(), getString(R.string.mergePRSuccessMsg));
tinyDb.putBoolean("prMerged", true);
tinyDb.putBoolean("resumePullRequests", true);
finish();
@Override
public void onResponse(@NonNull Call<Void> call, @NonNull retrofit2.Response<Void> response) {
}
else if(response.code() == 401) {
if(response.code() == 200) {
enableProcessButton();
AlertDialogs.authorizationTokenRevokedDialog(ctx, getResources().getString(R.string.alertDialogTokenRevokedTitle),
getResources().getString(R.string.alertDialogTokenRevokedMessage),
getResources().getString(R.string.alertDialogTokenRevokedCopyNegativeButton),
getResources().getString(R.string.alertDialogTokenRevokedCopyPositiveButton));
if(deleteBranch) {
}
else if(response.code() == 404) {
if(tinyDB.getString("prIsFork").equals("true")) {
enableProcessButton();
Toasty.info(getApplicationContext(), getString(R.string.mergePR404ErrorMsg));
String repoFullName = tinyDB.getString("prForkFullName");
String[] parts = repoFullName.split("/");
final String repoOwner = parts[0];
final String repoName = parts[1];
}
else {
PullRequestActions.deleteHeadBranch(ctx, repoOwner, repoName, tinyDB.getString("prHeadBranch"), false);
enableProcessButton();
Toasty.info(getApplicationContext(), getString(R.string.genericError));
Toasty.success(ctx, getString(R.string.mergePRSuccessMsg));
tinyDB.putBoolean("prMerged", true);
tinyDB.putBoolean("resumePullRequests", true);
finish();
}
else {
}
String repoFullName = tinyDB.getString("repoFullName");
String[] parts = repoFullName.split("/");
final String repoOwner = parts[0];
final String repoName = parts[1];
}
PullRequestActions.deleteHeadBranch(ctx, repoOwner, repoName, tinyDB.getString("prHeadBranch"), false);
@Override
public void onFailure(@NonNull Call<ResponseBody> call, @NonNull Throwable t) {
Log.e("onFailure", t.toString());
enableProcessButton();
}
Toasty.success(ctx, getString(R.string.mergePRSuccessMsg));
tinyDB.putBoolean("prMerged", true);
tinyDB.putBoolean("resumePullRequests", true);
finish();
}
});
}
else {
}
Toasty.success(ctx, getString(R.string.mergePRSuccessMsg));
tinyDB.putBoolean("prMerged", true);
tinyDB.putBoolean("resumePullRequests", true);
finish();
}
private void disableProcessButton() {
}
else if(response.code() == 401) {
mergeButton.setEnabled(false);
GradientDrawable shape = new GradientDrawable();
shape.setCornerRadius( 8 );
shape.setColor(getResources().getColor(R.color.hintColor));
mergeButton.setBackground(shape);
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.warning(ctx, getString(R.string.mergePR404ErrorMsg));
}
else if(response.code() == 405) {
private void enableProcessButton() {
enableProcessButton();
Toasty.warning(ctx, getString(R.string.mergeNotAllowed));;
}
else {
mergeButton.setEnabled(true);
GradientDrawable shape = new GradientDrawable();
shape.setCornerRadius( 8 );
shape.setColor(getResources().getColor(R.color.btnBackground));
mergeButton.setBackground(shape);
enableProcessButton();
Toasty.error(ctx, getString(R.string.genericError));
}
}
}
@Override
public void onFailure(@NonNull Call<Void> call, @NonNull Throwable t) {
Log.e("onFailure", t.toString());
enableProcessButton();
}
});
}
private void disableProcessButton() {
viewBinding.mergeButton.setEnabled(false);
}
private void enableProcessButton() {
viewBinding.mergeButton.setEnabled(true);
}
}

View File

@ -1,55 +1,60 @@
package org.mian.gitnex.activities;
import androidx.annotation.NonNull;
import retrofit2.Call;
import retrofit2.Callback;
import android.content.Context;
import android.graphics.drawable.GradientDrawable;
import android.os.Bundle;
import android.util.Log;
import android.util.Patterns;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import androidx.annotation.NonNull;
import com.google.gson.JsonElement;
import org.gitnex.tea4j.models.AddEmail;
import org.mian.gitnex.R;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.databinding.ActivityProfileEmailBinding;
import org.mian.gitnex.helpers.AlertDialogs;
import org.mian.gitnex.helpers.AppUtil;
import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.helpers.TinyDB;
import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.models.AddEmail;
import org.mian.gitnex.util.AppUtil;
import org.mian.gitnex.util.TinyDB;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
/**
* Author M M Arif
*/
public class ProfileEmailActivity extends BaseActivity {
public class MyProfileEmailActivity extends BaseActivity {
private View.OnClickListener onClickListener;
private EditText userEmail;
final Context ctx = this;
private Button addEmailButton;
@Override
protected int getLayoutResourceId(){
return R.layout.activity_profile_email;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
boolean connToInternet = AppUtil.haveNetworkConnection(getApplicationContext());
ActivityProfileEmailBinding activityProfileEmailBinding = ActivityProfileEmailBinding.inflate(getLayoutInflater());
setContentView(activityProfileEmailBinding.getRoot());
ImageView closeActivity = findViewById(R.id.close);
userEmail = findViewById(R.id.userEmail);
addEmailButton = findViewById(R.id.addEmailButton);
boolean connToInternet = AppUtil.hasNetworkConnection(appCtx);
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
ImageView closeActivity = activityProfileEmailBinding.close;
userEmail = activityProfileEmailBinding.userEmail;
addEmailButton = activityProfileEmailBinding.addEmailButton;
userEmail.requestFocus();
assert imm != null;
imm.showSoftInput(userEmail, InputMethodManager.SHOW_IMPLICIT);
initCloseListener();
closeActivity.setOnClickListener(onClickListener);
@ -57,68 +62,53 @@ public class ProfileEmailActivity extends BaseActivity {
if(!connToInternet) {
disableProcessButton();
} else {
addEmailButton.setOnClickListener(addEmailListener);
}
}
private View.OnClickListener addEmailListener = new View.OnClickListener() {
public void onClick(View v) {
processAddNewEmail();
}
};
private final View.OnClickListener addEmailListener = v -> processAddNewEmail();
private void processAddNewEmail() {
boolean connToInternet = AppUtil.haveNetworkConnection(getApplicationContext());
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");
boolean connToInternet = AppUtil.hasNetworkConnection(appCtx);
String newUserEmail = userEmail.getText().toString().trim();
if(!connToInternet) {
Toasty.info(getApplicationContext(), getResources().getString(R.string.checkNetConnection));
Toasty.error(ctx, getResources().getString(R.string.checkNetConnection));
return;
}
if(newUserEmail.equals("")) {
Toasty.info(getApplicationContext(), getString(R.string.emailErrorEmpty));
Toasty.error(ctx, getString(R.string.emailErrorEmpty));
return;
}
else if(!Patterns.EMAIL_ADDRESS.matcher(newUserEmail).matches()) {
Toasty.info(getApplicationContext(), getString(R.string.emailErrorInvalid));
Toasty.warning(ctx, getString(R.string.emailErrorInvalid));
return;
}
List<String> newEmailList = new ArrayList<>(Arrays.asList(newUserEmail.split(",")));
disableProcessButton();
addNewEmail(instanceUrl, Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), newEmailList);
addNewEmail(Authorization.get(ctx), newEmailList);
}
private void addNewEmail(final String instanceUrl, final String token, List<String> newUserEmail) {
private void addNewEmail(final String token, List<String> newUserEmail) {
AddEmail addEmailFunc = new AddEmail(newUserEmail);
final TinyDB tinyDb = new TinyDB(getApplicationContext());
final TinyDB tinyDb = TinyDB.getInstance(appCtx);
Call<JsonElement> call;
call = RetrofitClient
.getInstance(instanceUrl, getApplicationContext())
.getApiInterface()
.getApiInterface(appCtx)
.addNewEmail(token, addEmailFunc);
call.enqueue(new Callback<JsonElement>() {
@ -128,11 +118,10 @@ public class ProfileEmailActivity extends BaseActivity {
if(response.code() == 201) {
Toasty.info(getApplicationContext(), getString(R.string.emailAddedText));
Toasty.success(ctx, getString(R.string.emailAddedText));
tinyDb.putBoolean("emailsRefresh", true);
enableProcessButton();
finish();
}
else if(response.code() == 401) {
@ -141,37 +130,32 @@ public class ProfileEmailActivity extends BaseActivity {
getResources().getString(R.string.alertDialogTokenRevokedMessage),
getResources().getString(R.string.alertDialogTokenRevokedCopyNegativeButton),
getResources().getString(R.string.alertDialogTokenRevokedCopyPositiveButton));
}
else if(response.code() == 403) {
enableProcessButton();
Toasty.info(ctx, ctx.getString(R.string.authorizeError));
Toasty.error(ctx, ctx.getString(R.string.authorizeError));
}
else if(response.code() == 404) {
enableProcessButton();
Toasty.info(ctx, ctx.getString(R.string.apiNotFound));
Toasty.warning(ctx, ctx.getString(R.string.apiNotFound));
}
else if(response.code() == 422) {
enableProcessButton();
Toasty.info(ctx, ctx.getString(R.string.emailErrorInUse));
Toasty.warning(ctx, ctx.getString(R.string.emailErrorInUse));
}
else {
enableProcessButton();
Toasty.info(getApplicationContext(), getString(R.string.labelGeneralError));
Toasty.error(ctx, getString(R.string.labelGeneralError));
}
}
@Override
public void onFailure(@NonNull Call<JsonElement> call, @NonNull Throwable t) {
Log.e("onFailure", t.toString());
enableProcessButton();
}
@ -180,32 +164,18 @@ public class ProfileEmailActivity extends BaseActivity {
}
private void initCloseListener() {
onClickListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
finish();
}
};
onClickListener = view -> finish();
}
private void disableProcessButton() {
addEmailButton.setEnabled(false);
GradientDrawable shape = new GradientDrawable();
shape.setCornerRadius( 8 );
shape.setColor(getResources().getColor(R.color.hintColor));
addEmailButton.setBackground(shape);
}
private void enableProcessButton() {
addEmailButton.setEnabled(true);
GradientDrawable shape = new GradientDrawable();
shape.setCornerRadius( 8 );
shape.setColor(getResources().getColor(R.color.btnBackground));
addEmailButton.setBackground(shape);
}
}

View File

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

View File

@ -1,317 +0,0 @@
package org.mian.gitnex.activities;
import android.content.Context;
import android.graphics.PorterDuff;
import android.graphics.drawable.GradientDrawable;
import android.os.Bundle;
import androidx.annotation.NonNull;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.Spinner;
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.OrgOwner;
import org.mian.gitnex.models.OrganizationRepository;
import org.mian.gitnex.util.AppUtil;
import org.mian.gitnex.util.TinyDB;
import java.util.ArrayList;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
/**
* Author M M Arif
*/
public class NewRepoActivity extends BaseActivity {
public ImageView closeActivity;
private View.OnClickListener onClickListener;
private Spinner spinner;
private Button createRepo;
private EditText repoName;
private EditText repoDesc;
private CheckBox repoAccess;
final Context ctx = this;
List<OrgOwner> orgsList = new ArrayList<>();
@Override
protected int getLayoutResourceId(){
return R.layout.activity_new_repo;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
boolean connToInternet = AppUtil.haveNetworkConnection(getApplicationContext());
TinyDB tinyDb = new TinyDB(getApplicationContext());
final String instanceUrl = tinyDb.getString("instanceUrl");
final String loginUid = tinyDb.getString("loginUid");
final String userLogin = tinyDb.getString("userLogin");
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
closeActivity = findViewById(R.id.close);
repoName = findViewById(R.id.newRepoName);
repoDesc = findViewById(R.id.newRepoDescription);
repoAccess = findViewById(R.id.newRepoPrivate);
initCloseListener();
closeActivity.setOnClickListener(onClickListener);
spinner = findViewById(R.id.ownerSpinner);
spinner.getBackground().setColorFilter(getResources().getColor(R.color.white), PorterDuff.Mode.SRC_ATOP);
getOrgs(instanceUrl, Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), userLogin);
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
OrgOwner user = (OrgOwner) parent.getSelectedItem();
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
createRepo = findViewById(R.id.createNewRepoButton);
disableProcessButton();
if(!connToInternet) {
disableProcessButton();
}
else {
createRepo.setOnClickListener(createRepoListener);
}
}
private View.OnClickListener createRepoListener = new View.OnClickListener() {
public void onClick(View v) {
processNewRepo();
}
};
private void processNewRepo() {
boolean connToInternet = AppUtil.haveNetworkConnection(getApplicationContext());
AppUtil appUtil = new AppUtil();
TinyDB tinyDb = new TinyDB(getApplicationContext());
final String instanceUrl = tinyDb.getString("instanceUrl");
final String loginUid = tinyDb.getString("loginUid");
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
String newRepoName = repoName.getText().toString();
String newRepoDesc = repoDesc.getText().toString();
String repoOwner = spinner.getSelectedItem().toString();
boolean newRepoAccess = repoAccess.isChecked();
if(!connToInternet) {
Toasty.info(getApplicationContext(), getResources().getString(R.string.checkNetConnection));
return;
}
if(!newRepoDesc.equals("")) {
if (appUtil.charactersLength(newRepoDesc) > 255) {
Toasty.info(getApplicationContext(), getString(R.string.repoDescError));
return;
}
}
if(newRepoName.equals("")) {
Toasty.info(getApplicationContext(), getString(R.string.repoNameErrorEmpty));
}
else if(!appUtil.checkStrings(newRepoName)) {
Toasty.info(getApplicationContext(), getString(R.string.repoNameErrorInvalid));
}
else {
//Log.i("repoOwner", String.valueOf(repoOwner));
disableProcessButton();
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) {
OrganizationRepository createRepository = new OrganizationRepository(true, repoDesc, null, null, repoName, isPrivate, "Default");
Call<OrganizationRepository> call;
if(repoOwner.equals(loginUid)) {
call = RetrofitClient
.getInstance(instanceUrl, getApplicationContext())
.getApiInterface()
.createNewUserRepository(token, createRepository);
}
else {
call = RetrofitClient
.getInstance(instanceUrl, getApplicationContext())
.getApiInterface()
.createNewUserOrgRepository(token, repoOwner, createRepository);
}
call.enqueue(new Callback<OrganizationRepository>() {
@Override
public void onResponse(@NonNull Call<OrganizationRepository> call, @NonNull retrofit2.Response<OrganizationRepository> response) {
if(response.code() == 201) {
TinyDB tinyDb = new TinyDB(getApplicationContext());
tinyDb.putBoolean("repoCreated", true);
Toasty.info(getApplicationContext(), getString(R.string.repoCreated));
enableProcessButton();
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() == 409) {
enableProcessButton();
Toasty.info(getApplicationContext(), getString(R.string.repoExistsError));
}
else {
enableProcessButton();
Toasty.info(getApplicationContext(), getString(R.string.repoCreatedError));
}
}
@Override
public void onFailure(@NonNull Call<OrganizationRepository> call, @NonNull Throwable t) {
Log.e("onFailure", t.toString());
enableProcessButton();
}
});
}
private void getOrgs(String instanceUrl, String instanceToken, final String userLogin) {
Call<List<OrgOwner>> call = RetrofitClient
.getInstance(instanceUrl, getApplicationContext())
.getApiInterface()
.getOrgOwners(instanceToken);
call.enqueue(new Callback<List<OrgOwner>>() {
@Override
public void onResponse(@NonNull Call<List<OrgOwner>> call, @NonNull retrofit2.Response<List<OrgOwner>> response) {
if(response.isSuccessful()) {
if(response.code() == 200) {
List<OrgOwner> orgsList_ = response.body();
orgsList.add(new OrgOwner(userLogin));
assert orgsList_ != null;
if(orgsList_.size() > 0) {
for (int i = 0; i < orgsList_.size(); i++) {
OrgOwner data = new OrgOwner(
orgsList_.get(i).getUsername()
);
orgsList.add(data);
}
}
ArrayAdapter<OrgOwner> adapter = new ArrayAdapter<>(getApplicationContext(),
R.layout.spinner_item, orgsList);
adapter.setDropDownViewResource(R.layout.spinner_dropdown_item);
spinner.setAdapter(adapter);
enableProcessButton();
}
}
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));
}
}
@Override
public void onFailure(@NonNull Call<List<OrgOwner>> call, @NonNull Throwable t) {
Log.e("onFailure", t.toString());
enableProcessButton();
}
});
}
private void initCloseListener() {
onClickListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
finish();
}
};
}
private void disableProcessButton() {
createRepo.setEnabled(false);
GradientDrawable shape = new GradientDrawable();
shape.setCornerRadius( 8 );
shape.setColor(getResources().getColor(R.color.hintColor));
createRepo.setBackground(shape);
}
private void enableProcessButton() {
createRepo.setEnabled(true);
GradientDrawable shape = new GradientDrawable();
shape.setCornerRadius( 8 );
shape.setColor(getResources().getColor(R.color.btnBackground));
createRepo.setBackground(shape);
}
}

View File

@ -1,10 +1,17 @@
package org.mian.gitnex.activities;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import org.mian.gitnex.util.TinyDB;
import org.mian.gitnex.R;
import org.mian.gitnex.helpers.PathsHelper;
import org.mian.gitnex.helpers.TinyDB;
import org.mian.gitnex.helpers.Toasty;
import java.net.URI;
import java.net.URISyntaxException;
import io.mikael.urlbuilder.UrlBuilder;
/**
* Author M M Arif
@ -12,24 +19,37 @@ import org.mian.gitnex.util.TinyDB;
public class OpenRepoInBrowserActivity extends AppCompatActivity {
private Context appCtx;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
super.onCreate(savedInstanceState);
TinyDB tinyDb = new TinyDB(getApplicationContext());
String instanceUrlWithProtocol = "https://" + tinyDb.getString("instanceUrlRaw");
if (!tinyDb.getString("instanceUrlWithProtocol").isEmpty()) {
instanceUrlWithProtocol = tinyDb.getString("instanceUrlWithProtocol");
}
appCtx = getApplicationContext();
TinyDB tinyDb = TinyDB.getInstance(appCtx);
String repoFullNameBrowser = getIntent().getStringExtra("repoFullNameBrowser");
Uri url = Uri.parse(instanceUrlWithProtocol + "/" + repoFullNameBrowser);
Intent i = new Intent(Intent.ACTION_VIEW, url);
startActivity(i);
finish();
try {
URI instanceUrl = new URI(UrlBuilder.fromString(tinyDb.getString("instanceUrl"))
.withPath("/")
.toString());
String browserPath = PathsHelper.join(instanceUrl.getPath(), getIntent().getStringExtra("repoFullNameBrowser"));
String browserUrl = UrlBuilder.fromUri(instanceUrl)
.withPath(browserPath)
.toString();
Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse(browserUrl));
startActivity(i);
finish();
}
catch(URISyntaxException e) {
Toasty.error(appCtx, getString(R.string.genericError));
}
}
}

View File

@ -1,106 +0,0 @@
package org.mian.gitnex.activities;
import androidx.annotation.Nullable;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import android.os.Bundle;
import android.view.View;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.TextView;
import org.mian.gitnex.R;
import org.mian.gitnex.adapters.TeamMembersByOrgAdapter;
import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.models.UserInfo;
import org.mian.gitnex.util.TinyDB;
import org.mian.gitnex.viewmodels.TeamMembersByOrgViewModel;
import java.util.List;
import java.util.Objects;
/**
* Author M M Arif
*/
public class OrgTeamMembersActivity extends BaseActivity {
private TextView noDataMembers;
private View.OnClickListener onClickListener;
private TeamMembersByOrgAdapter adapter;
private GridView mGridView;
@Override
protected int getLayoutResourceId(){
return R.layout.activity_org_team_members;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TinyDB tinyDb = new TinyDB(getApplicationContext());
final String instanceUrl = tinyDb.getString("instanceUrl");
final String loginUid = tinyDb.getString("loginUid");
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
ImageView closeActivity = findViewById(R.id.close);
TextView toolbarTitle = findViewById(R.id.toolbar_title);
noDataMembers = findViewById(R.id.noDataMembers);
mGridView = findViewById(R.id.gridView);
initCloseListener();
closeActivity.setOnClickListener(onClickListener);
if(getIntent().getStringExtra("teamTitle") != null && !Objects.requireNonNull(getIntent().getStringExtra("teamTitle")).equals("")) {
toolbarTitle.setText(getIntent().getStringExtra("teamTitle"));
}
else {
toolbarTitle.setText(R.string.orgTeamMembers);
}
String teamId;
if(getIntent().getStringExtra("teamId") != null && !Objects.requireNonNull(getIntent().getStringExtra("teamId")).equals("")){
teamId = getIntent().getStringExtra("teamId");
}
else {
teamId = "0";
}
getIntent().getStringExtra("teamId");
//Log.i("teamId", getIntent().getStringExtra("teamId"));
assert teamId != null;
fetchDataAsync(instanceUrl, Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), Integer.valueOf(teamId));
}
private void fetchDataAsync(String instanceUrl, String instanceToken, int teamId) {
TeamMembersByOrgViewModel teamMembersModel = new ViewModelProvider(this).get(TeamMembersByOrgViewModel.class);
teamMembersModel.getMembersByOrgList(instanceUrl, instanceToken, teamId, getApplicationContext()).observe(this, new Observer<List<UserInfo>>() {
@Override
public void onChanged(@Nullable List<UserInfo> teamMembersListMain) {
adapter = new TeamMembersByOrgAdapter(getApplicationContext(), teamMembersListMain);
if(adapter.getCount() > 0) {
mGridView.setAdapter(adapter);
noDataMembers.setVisibility(View.GONE);
}
else {
adapter.notifyDataSetChanged();
mGridView.setAdapter(adapter);
noDataMembers.setVisibility(View.VISIBLE);
}
}
});
}
private void initCloseListener() {
onClickListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
finish();
}
};
}
}

View File

@ -1,12 +1,8 @@
package org.mian.gitnex.activities;
import com.google.android.material.tabs.TabLayout;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.Toolbar;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;
import androidx.viewpager.widget.ViewPager;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent;
import android.graphics.Typeface;
import android.os.Bundle;
@ -16,41 +12,47 @@ import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.Toolbar;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;
import androidx.viewpager.widget.ViewPager;
import com.google.android.material.tabs.TabLayout;
import org.mian.gitnex.R;
import org.mian.gitnex.fragments.BottomSheetOrganizationFragment;
import org.mian.gitnex.fragments.MembersByOrgFragment;
import org.mian.gitnex.fragments.OrgBottomSheetFragment;
import org.mian.gitnex.fragments.OrganizationInfoFragment;
import org.mian.gitnex.fragments.OrganizationLabelsFragment;
import org.mian.gitnex.fragments.RepositoriesByOrgFragment;
import org.mian.gitnex.fragments.TeamsByOrgFragment;
import org.mian.gitnex.util.TinyDB;
import org.mian.gitnex.helpers.Toasty;
import java.util.Objects;
import io.mikael.urlbuilder.UrlBuilder;
/**
* Author M M Arif
*/
public class OrgDetailActivity extends BaseActivity implements OrgBottomSheetFragment.BottomSheetListener {
@Override
protected int getLayoutResourceId(){
return R.layout.activity_org_detail;
}
public class OrganizationDetailActivity extends BaseActivity implements BottomSheetOrganizationFragment.BottomSheetListener {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TinyDB tinyDb = new TinyDB(getApplicationContext());
String orgName = tinyDb.getString("orgName");
setContentView(R.layout.activity_org_detail);
String orgName = tinyDB.getString("orgName");
Toolbar toolbar = findViewById(R.id.toolbar);
TextView toolbarTitle = toolbar.findViewById(R.id.toolbar_title);
TextView toolbarTitle = findViewById(R.id.toolbar_title);
setSupportActionBar(toolbar);
Objects.requireNonNull(getSupportActionBar()).setTitle(orgName);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
OrgDetailActivity.SectionsPagerAdapter mSectionsPagerAdapter = new OrgDetailActivity.SectionsPagerAdapter(getSupportFragmentManager());
OrganizationDetailActivity.SectionsPagerAdapter mSectionsPagerAdapter = new OrganizationDetailActivity.SectionsPagerAdapter(getSupportFragmentManager());
ViewPager mViewPager = findViewById(R.id.container);
mViewPager.setAdapter(mSectionsPagerAdapter);
@ -58,25 +60,21 @@ public class OrgDetailActivity extends BaseActivity implements OrgBottomSheetFra
TabLayout tabLayout = findViewById(R.id.tabs);
Typeface myTypeface;
if(tinyDb.getInt("customFontId") == 0) {
myTypeface = Typeface.createFromAsset(Objects.requireNonNull(getApplicationContext()).getAssets(), "fonts/roboto.ttf");
switch(tinyDB.getInt("customFontId", -1)) {
}
else if (tinyDb.getInt("customFontId") == 1) {
case 0:
myTypeface = Typeface.createFromAsset(Objects.requireNonNull(getApplicationContext()).getAssets(), "fonts/manroperegular.ttf");
myTypeface = Typeface.createFromAsset(ctx.getAssets(), "fonts/roboto.ttf");
break;
case 2:
}
else if (tinyDb.getInt("customFontId") == 2) {
myTypeface = Typeface.createFromAsset(Objects.requireNonNull(getApplicationContext()).getAssets(), "fonts/sourcecodeproregular.ttf");
}
else {
myTypeface = Typeface.createFromAsset(Objects.requireNonNull(getApplicationContext()).getAssets(), "fonts/roboto.ttf");
myTypeface = Typeface.createFromAsset(ctx.getAssets(), "fonts/sourcecodeproregular.ttf");
break;
default:
myTypeface = Typeface.createFromAsset(ctx.getAssets(), "fonts/manroperegular.ttf");
break;
}
toolbarTitle.setTypeface(myTypeface);
@ -84,12 +82,18 @@ public class OrgDetailActivity extends BaseActivity implements OrgBottomSheetFra
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);
}
}
@ -97,12 +101,12 @@ public class OrgDetailActivity extends BaseActivity implements OrgBottomSheetFra
mViewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
tabLayout.addOnTabSelectedListener(new TabLayout.ViewPagerOnTabSelectedListener(mViewPager));
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.repo_dotted_menu, menu);
return true;
@ -113,69 +117,102 @@ public class OrgDetailActivity extends BaseActivity implements OrgBottomSheetFra
int id = item.getItemId();
switch (id) {
case android.R.id.home:
finish();
return true;
case R.id.repoMenu:
OrgBottomSheetFragment bottomSheet = new OrgBottomSheetFragment();
bottomSheet.show(getSupportFragmentManager(), "orgBottomSheet");
return true;
default:
return super.onOptionsItemSelected(item);
}
if(id == android.R.id.home) {
finish();
return true;
}
else if(id == R.id.repoMenu) {
BottomSheetOrganizationFragment bottomSheet = new BottomSheetOrganizationFragment();
bottomSheet.show(getSupportFragmentManager(), "orgBottomSheet");
return true;
}
else {
return super.onOptionsItemSelected(item);
}
}
@Override
public void onButtonClicked(String text) {
switch (text) {
case "team":
startActivity(new Intent(OrgDetailActivity.this, CreateTeamByOrgActivity.class));
break;
}
//Log.i("clicked", text);
case "repository":
tinyDB.putBoolean("organizationAction", true);
startActivity(new Intent(OrganizationDetailActivity.this, CreateRepoActivity.class));
break;
case "label":
Intent intent = new Intent(ctx, CreateLabelActivity.class);
intent.putExtra("orgName", getIntent().getStringExtra("orgName"));
intent.putExtra("type", "org");
ctx.startActivity(intent);
break;
case "team":
startActivity(new Intent(OrganizationDetailActivity.this, CreateTeamByOrgActivity.class));
break;
case "copyOrgUrl":
String url = UrlBuilder.fromString(tinyDB.getString("instanceUrl"))
.withPath("/")
.toString();
ClipboardManager clipboard = (ClipboardManager) Objects.requireNonNull(ctx).getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText("orgUrl", url + tinyDB.getString("orgName"));
assert clipboard != null;
clipboard.setPrimaryClip(clip);
Toasty.info(ctx, ctx.getString(R.string.copyIssueUrlToastMsg));
break;
}
}
public class SectionsPagerAdapter extends FragmentPagerAdapter {
SectionsPagerAdapter(FragmentManager fm) {
super(fm);
super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
}
@NonNull
@Override
public Fragment getItem(int position) {
TinyDB tinyDb = new TinyDB(getApplicationContext());
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");
}
else {
orgName = tinyDb.getString("orgName");
orgName = tinyDB.getString("orgName");
}
Fragment fragment = null;
switch (position) {
case 0: // info
return OrganizationInfoFragment.newInstance(orgName);
case 1: // repos
return RepositoriesByOrgFragment.newInstance(orgName);
case 2: // teams
return RepositoriesByOrgFragment.newInstance(orgName);
case 2: // labels
return OrganizationLabelsFragment.newInstance(orgName);
case 3: // teams
return TeamsByOrgFragment.newInstance(orgName);
case 3: // members
case 4: // members
return MembersByOrgFragment.newInstance(orgName);
}
return fragment;
}
@Override
public int getCount() {
return 4;
return 5;
}
}
}

View File

@ -0,0 +1,161 @@
package org.mian.gitnex.activities;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.appcompat.widget.Toolbar;
import androidx.lifecycle.ViewModelProvider;
import org.mian.gitnex.R;
import org.mian.gitnex.adapters.TeamMembersByOrgAdapter;
import org.mian.gitnex.databinding.ActivityOrgTeamMembersBinding;
import org.mian.gitnex.fragments.BottomSheetOrganizationTeamsFragment;
import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.helpers.TinyDB;
import org.mian.gitnex.viewmodels.TeamMembersByOrgViewModel;
import java.util.Objects;
/**
* Author M M Arif
*/
public class OrganizationTeamMembersActivity extends BaseActivity implements BottomSheetOrganizationTeamsFragment.BottomSheetListener {
private TextView noDataMembers;
private View.OnClickListener onClickListener;
private TeamMembersByOrgAdapter adapter;
private GridView mGridView;
private ProgressBar progressBar;
private String teamId;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityOrgTeamMembersBinding activityOrgTeamMembersBinding = ActivityOrgTeamMembersBinding.inflate(getLayoutInflater());
setContentView(activityOrgTeamMembersBinding.getRoot());
Toolbar toolbar = activityOrgTeamMembersBinding.toolbar;
setSupportActionBar(toolbar);
ImageView closeActivity = activityOrgTeamMembersBinding.close;
TextView toolbarTitle = activityOrgTeamMembersBinding.toolbarTitle;
noDataMembers = activityOrgTeamMembersBinding.noDataMembers;
mGridView = activityOrgTeamMembersBinding.gridView;
progressBar = activityOrgTeamMembersBinding.progressBar;
initCloseListener();
closeActivity.setOnClickListener(onClickListener);
if(getIntent().getStringExtra("teamTitle") != null && !Objects.requireNonNull(getIntent().getStringExtra("teamTitle")).equals("")) {
toolbarTitle.setText(getIntent().getStringExtra("teamTitle"));
}
else {
toolbarTitle.setText(R.string.orgTeamMembers);
}
if(getIntent().getStringExtra("teamId") != null && !Objects.requireNonNull(getIntent().getStringExtra("teamId")).equals("")){
teamId = getIntent().getStringExtra("teamId");
}
else {
teamId = "0";
}
assert teamId != null;
fetchDataAsync(Authorization.get(ctx), Integer.parseInt(teamId));
}
@Override
public void onResume() {
super.onResume();
TinyDB tinyDb = TinyDB.getInstance(appCtx);
if(tinyDb.getBoolean("teamActionFlag")) {
fetchDataAsync(Authorization.get(ctx), Integer.parseInt(teamId));
tinyDb.putBoolean("teamActionFlag", false);
}
}
private void fetchDataAsync(String instanceToken, int teamId) {
TeamMembersByOrgViewModel teamMembersModel = new ViewModelProvider(this).get(TeamMembersByOrgViewModel.class);
teamMembersModel.getMembersByOrgList(instanceToken, teamId, ctx).observe(this, teamMembersListMain -> {
adapter = new TeamMembersByOrgAdapter(ctx, teamMembersListMain);
if(adapter.getCount() > 0) {
mGridView.setAdapter(adapter);
noDataMembers.setVisibility(View.GONE);
}
else {
adapter.notifyDataSetChanged();
mGridView.setAdapter(adapter);
noDataMembers.setVisibility(View.VISIBLE);
}
progressBar.setVisibility(View.GONE);
});
}
@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();
if(id == android.R.id.home) {
finish();
return true;
}
else if(id == R.id.genericMenu) {
BottomSheetOrganizationTeamsFragment bottomSheet = new BottomSheetOrganizationTeamsFragment();
bottomSheet.show(getSupportFragmentManager(), "orgTeamsBottomSheet");
return true;
}
else {
return super.onOptionsItemSelected(item);
}
}
@Override
public void onButtonClicked(String text) {
if("newMember".equals(text)) {
Intent intent = new Intent(OrganizationTeamMembersActivity.this, AddNewTeamMemberActivity.class);
intent.putExtra("teamId", teamId);
startActivity(intent);
}
}
private void initCloseListener() {
onClickListener = view -> finish();
}
}

View File

@ -0,0 +1,242 @@
package org.mian.gitnex.activities;
import android.content.Intent;
import android.graphics.Typeface;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.Toolbar;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.viewpager2.adapter.FragmentStateAdapter;
import androidx.viewpager2.widget.ViewPager2;
import com.google.android.material.tabs.TabLayout;
import com.google.android.material.tabs.TabLayoutMediator;
import com.google.gson.JsonElement;
import org.mian.gitnex.R;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.fragments.BottomSheetUserProfileFragment;
import org.mian.gitnex.fragments.profile.DetailFragment;
import org.mian.gitnex.fragments.profile.FollowersFragment;
import org.mian.gitnex.fragments.profile.FollowingFragment;
import org.mian.gitnex.fragments.profile.OrganizationsFragment;
import org.mian.gitnex.fragments.profile.RepositoriesFragment;
import org.mian.gitnex.fragments.profile.StarredRepositoriesFragment;
import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.helpers.Toasty;
import java.util.Objects;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
/**
* Author M M Arif
*/
public class ProfileActivity extends BaseActivity implements BottomSheetUserProfileFragment.BottomSheetListener {
private String username;
private boolean following;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_profile);
Intent profileIntent = getIntent();
Typeface myTypeface;
Toolbar toolbar = findViewById(R.id.toolbar);
TextView toolbarTitle = findViewById(R.id.toolbarTitle);
if(profileIntent.getStringExtra("username") != null && !Objects.equals(profileIntent.getStringExtra("username"), "")) {
username = profileIntent.getStringExtra("username");
}
else {
Toasty.warning(ctx, ctx.getResources().getString(R.string.userInvalidUserName));
finish();
}
setSupportActionBar(toolbar);
Objects.requireNonNull(getSupportActionBar()).setTitle(username);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
ViewPager2 viewPager = findViewById(R.id.profileContainer);
viewPager.setOffscreenPageLimit(1);
TabLayout tabLayout = findViewById(R.id.tabs);
switch(tinyDB.getInt("customFontId", -1)) {
case 0:
myTypeface = Typeface.createFromAsset(ctx.getAssets(), "fonts/roboto.ttf");
break;
case 2:
myTypeface = Typeface.createFromAsset(ctx.getAssets(), "fonts/sourcecodeproregular.ttf");
break;
default:
myTypeface = Typeface.createFromAsset(ctx.getAssets(), "fonts/manroperegular.ttf");
break;
}
toolbarTitle.setTypeface(myTypeface);
toolbarTitle.setText(username);
viewPager.setAdapter(new ViewPagerAdapter(this));
String[] tabTitles = {ctx.getResources().getString(R.string.tabTextInfo), ctx.getResources().getString(R.string.navRepos), ctx.getResources().getString(R.string.navStarredRepos), ctx.getResources().getString(R.string.navOrg), ctx.getResources().getString(R.string.profileTabFollowers), ctx.getResources().getString(R.string.profileTabFollowing)};
new TabLayoutMediator(tabLayout, viewPager, (tab, position) -> tab.setText(tabTitles[position])).attach();
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);
}
}
if(!username.equals(tinyDB.getString("userLogin"))) {
checkFollowStatus();
}
}
}
@Override
public void onButtonClicked(String text) {
if(text.equals("follow")) {
followUnfollow();
}
}
private void checkFollowStatus() {
RetrofitClient.getApiInterface(this).checkFollowing(Authorization.get(this), username).enqueue(new Callback<JsonElement>() {
@Override
public void onResponse(@NonNull Call<JsonElement> call, @NonNull Response<JsonElement> response) {
if(response.code() == 204) {
following = true;
}
else if(response.code() == 404) {
following = false;
}
else {
following = false;
}
}
@Override
public void onFailure(@NonNull Call<JsonElement> call, @NonNull Throwable t) {
following = false;
}
});
}
private void followUnfollow() {
Call<JsonElement> call;
if (following) {
call = RetrofitClient.getApiInterface(this).unfollowUser(Authorization.get(this), username);
}
else {
call = RetrofitClient.getApiInterface(this).followUser(Authorization.get(this), username);
}
call.enqueue(new Callback<JsonElement>() {
@Override
public void onResponse(@NonNull Call<JsonElement> call, @NonNull Response<JsonElement> response) {
if (response.isSuccessful()) {
following = !following;
if (following) {
Toasty.success(ProfileActivity.this, String.format(getString(R.string.nowFollowUser), username));
}
else {
Toasty.success(ProfileActivity.this, String.format(getString(R.string.unfollowedUser), username));
}
} else {
if (following) {
Toasty.error(ProfileActivity.this, getString(R.string.unfollowingFailed));
}
else {
Toasty.error(ProfileActivity.this, getString(R.string.followingFailed));
}
}
}
@Override
public void onFailure(@NonNull Call<JsonElement> call, @NonNull Throwable t) {
if (following) {
Toasty.error(ProfileActivity.this, getString(R.string.unfollowingFailed));
}
else {
Toasty.error(ProfileActivity.this, getString(R.string.followingFailed));
}
}
});
}
public class ViewPagerAdapter extends FragmentStateAdapter {
public ViewPagerAdapter(@NonNull FragmentActivity fa) { super(fa); }
@NonNull
@Override
public Fragment createFragment(int position) {
switch(position) {
case 0: // detail
return DetailFragment.newInstance(username);
case 1: // repos
return RepositoriesFragment.newInstance(username);
case 2: // starred repos
return StarredRepositoriesFragment.newInstance(username);
case 3: // organizations
return OrganizationsFragment.newInstance(username);
case 4: // followers
return FollowersFragment.newInstance(username);
case 5: // following
return FollowingFragment.newInstance(username);
}
return null;
}
@Override
public int getItemCount() {
return 6;
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if(id == android.R.id.home) {
finish();
return true;
}
else if(id == R.id.genericMenu) {
new BottomSheetUserProfileFragment(following).show(getSupportFragmentManager(), "userProfileBottomSheet");
return true;
}
else {
return super.onOptionsItemSelected(item);
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
if(!username.equals(tinyDB.getString("userLogin"))) {
getMenuInflater().inflate(R.menu.generic_nav_dotted_menu, menu);
}
return super.onCreateOptionsMenu(menu);
}
}

View File

@ -1,283 +0,0 @@
package org.mian.gitnex.activities;
import androidx.annotation.NonNull;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import android.content.Context;
import android.graphics.drawable.GradientDrawable;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
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.actions.IssueActions;
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.Collaborators;
import org.mian.gitnex.models.Issues;
import org.mian.gitnex.util.AppUtil;
import org.mian.gitnex.util.TinyDB;
import java.util.List;
/**
* Author M M Arif
*/
public class ReplyToIssueActivity extends BaseActivity {
public ImageView closeActivity;
private View.OnClickListener onClickListener;
final Context ctx = this;
private SocialAutoCompleteTextView addComment;
private ArrayAdapter<Mention> defaultMentionAdapter;
private Button replyButton;
@Override
protected int getLayoutResourceId(){
return R.layout.activity_reply_to_issue;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
boolean connToInternet = AppUtil.haveNetworkConnection(getApplicationContext());
TinyDB tinyDb = new TinyDB(getApplicationContext());
addComment = findViewById(R.id.addComment);
addComment.setShowSoftInputOnFocus(true);
defaultMentionAdapter = new MentionArrayAdapter<>(this);
loadCollaboratorsList();
addComment.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"));
}
initCloseListener();
closeActivity.setOnClickListener(onClickListener);
replyButton = findViewById(R.id.replyButton);
if(getIntent().getStringExtra("commentAction") != null && getIntent().getStringExtra("commentAction").equals("edit")) {
addComment.setText(getIntent().getStringExtra("commentBody"));
final String commentId = getIntent().getStringExtra("commentId");
toolbar_title.setText(getResources().getString(R.string.editCommentTitle));
replyButton.setText(getResources().getString(R.string.editCommentButtonText));
replyButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
disableProcessButton();
IssueActions.editIssueComment(ctx, Integer.valueOf(commentId), addComment.getText().toString());
}
});
return;
}
if(!connToInternet) {
disableProcessButton();
} else {
replyButton.setOnClickListener(replyToIssue);
}
}
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.getMessage());
}
});
}
private void initCloseListener() {
onClickListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
finish();
}
};
}
private View.OnClickListener replyToIssue = new View.OnClickListener() {
public void onClick(View v) {
processNewCommentReply();
}
};
private void processNewCommentReply() {
String newReplyDT = addComment.getText().toString();
boolean connToInternet = AppUtil.haveNetworkConnection(getApplicationContext());
if(!connToInternet) {
Toasty.info(getApplicationContext(), getResources().getString(R.string.checkNetConnection));
return;
}
if(newReplyDT.equals("")) {
Toasty.info(getApplicationContext(), getString(R.string.commentEmptyError));
}
else {
disableProcessButton();
replyComment(newReplyDT);
}
}
private void replyComment(String newReplyDT) {
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 issueIndex = Integer.parseInt(tinyDb.getString("issueNumber"));
Issues issueComment = new Issues(newReplyDT);
Call<Issues> call = RetrofitClient
.getInstance(instanceUrl, getApplicationContext())
.getApiInterface()
.replyCommentToIssue(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName, issueIndex, issueComment);
call.enqueue(new Callback<Issues>() {
@Override
public void onResponse(@NonNull Call<Issues> call, @NonNull retrofit2.Response<Issues> response) {
if(response.code() == 201) {
Toasty.info(getApplicationContext(), getString(R.string.commentSuccess));
tinyDb.putBoolean("commentPosted", true);
tinyDb.putBoolean("resumeIssues", 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 {
enableProcessButton();
Toasty.info(getApplicationContext(), getString(R.string.commentError));
}
}
@Override
public void onFailure(@NonNull Call<Issues> call, @NonNull Throwable t) {
Log.e("onFailure", t.toString());
enableProcessButton();
}
});
}
private void disableProcessButton() {
replyButton.setEnabled(false);
GradientDrawable shape = new GradientDrawable();
shape.setCornerRadius( 8 );
shape.setColor(getResources().getColor(R.color.hintColor));
replyButton.setBackground(shape);
}
private void enableProcessButton() {
replyButton.setEnabled(true);
GradientDrawable shape = new GradientDrawable();
shape.setCornerRadius( 8 );
shape.setColor(getResources().getColor(R.color.btnBackground));
replyButton.setBackground(shape);
}
}

View File

@ -0,0 +1,278 @@
package org.mian.gitnex.activities;
import android.annotation.SuppressLint;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
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.appcompat.widget.SearchView;
import androidx.appcompat.widget.Toolbar;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import org.gitnex.tea4j.models.UserRepositories;
import org.mian.gitnex.R;
import org.mian.gitnex.adapters.RepoForksAdapter;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.databinding.ActivityRepoForksBinding;
import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.helpers.Constants;
import org.mian.gitnex.helpers.TinyDB;
import org.mian.gitnex.helpers.Version;
import java.util.ArrayList;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
/**
* Author M M Arif
*/
public class RepoForksActivity extends BaseActivity {
private View.OnClickListener onClickListener;
private TextView noData;
private ProgressBar progressBar;
private final String TAG = "RepositoryForks";
private int resultLimit = Constants.resultLimitOldGiteaInstances;
private int pageSize = 1;
private RecyclerView recyclerView;
private List<UserRepositories> forksList;
private RepoForksAdapter adapter;
private ProgressBar progressLoadMore;
@SuppressLint("DefaultLocale")
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityRepoForksBinding activityRepoForksBinding = ActivityRepoForksBinding.inflate(getLayoutInflater());
setContentView(activityRepoForksBinding.getRoot());
Toolbar toolbar = activityRepoForksBinding.toolbar;
setSupportActionBar(toolbar);
TinyDB tinyDb = TinyDB.getInstance(appCtx);
String repoFullNameForForks = getIntent().getStringExtra("repoFullNameForForks");
assert repoFullNameForForks != null;
String[] parts = repoFullNameForForks.split("/");
final String repoOwner = parts[0];
final String repoName = parts[1];
TextView toolbar_title = activityRepoForksBinding.toolbarTitle;
toolbar_title.setMovementMethod(new ScrollingMovementMethod());
toolbar_title.setText(String.format("%s : %s", ctx.getResources().getString(R.string.infoTabRepoForksCount), repoName));
ImageView closeActivity = activityRepoForksBinding.close;
noData = activityRepoForksBinding.noData;
progressLoadMore = activityRepoForksBinding.progressLoadMore;
progressBar = activityRepoForksBinding.progressBar;
SwipeRefreshLayout swipeRefresh = activityRepoForksBinding.pullToRefresh;
initCloseListener();
closeActivity.setOnClickListener(onClickListener);
// if gitea is 1.12 or higher use the new limit (resultLimitNewGiteaInstances)
if(new Version(tinyDb.getString("giteaVersion")).higherOrEqual("1.12")) {
resultLimit = Constants.resultLimitNewGiteaInstances;
}
recyclerView = activityRepoForksBinding.recyclerView;
forksList = new ArrayList<>();
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(),
DividerItemDecoration.VERTICAL);
recyclerView.addItemDecoration(dividerItemDecoration);
swipeRefresh.setOnRefreshListener(() -> new Handler(Looper.getMainLooper()).postDelayed(() -> {
swipeRefresh.setRefreshing(false);
loadInitial(Authorization.get(ctx), repoOwner, repoName, pageSize, resultLimit);
adapter.notifyDataChanged();
}, 200));
adapter = new RepoForksAdapter(ctx, forksList);
adapter.setLoadMoreListener(() -> recyclerView.post(() -> {
if(forksList.size() == resultLimit || pageSize == resultLimit) {
int page = (forksList.size() + resultLimit) / resultLimit;
loadMore(Authorization.get(ctx), repoOwner, repoName, page, resultLimit);
}
}));
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(ctx));
recyclerView.setAdapter(adapter);
loadInitial(Authorization.get(ctx), repoOwner, repoName, pageSize, resultLimit);
}
private void loadInitial(String instanceToken, String repoOwner, String repoName, int pageSize, int resultLimit) {
Call<List<UserRepositories>> call = RetrofitClient
.getApiInterface(ctx)
.getRepositoryForks(instanceToken, repoOwner, repoName, pageSize, resultLimit);
call.enqueue(new Callback<List<UserRepositories>>() {
@Override
public void onResponse(@NonNull Call<List<UserRepositories>> call, @NonNull Response<List<UserRepositories>> response) {
if(response.isSuccessful()) {
assert response.body() != null;
if(response.body().size() > 0) {
forksList.clear();
forksList.addAll(response.body());
adapter.notifyDataChanged();
noData.setVisibility(View.GONE);
}
else {
forksList.clear();
adapter.notifyDataChanged();
noData.setVisibility(View.VISIBLE);
}
progressBar.setVisibility(View.GONE);
}
else {
Log.e(TAG, String.valueOf(response.code()));
}
}
@Override
public void onFailure(@NonNull Call<List<UserRepositories>> call, @NonNull Throwable t) {
Log.e(TAG, t.toString());
}
});
}
private void loadMore(String instanceToken, String repoOwner, String repoName, int page, int resultLimit) {
progressLoadMore.setVisibility(View.VISIBLE);
Call<List<UserRepositories>> call = RetrofitClient
.getApiInterface(ctx)
.getRepositoryForks(instanceToken, repoOwner, repoName, page, resultLimit);
call.enqueue(new Callback<List<UserRepositories>>() {
@Override
public void onResponse(@NonNull Call<List<UserRepositories>> call, @NonNull Response<List<UserRepositories>> response) {
if(response.isSuccessful()) {
//remove loading view
forksList.remove(forksList.size() - 1);
List<UserRepositories> result = response.body();
assert result != null;
if(result.size() > 0) {
pageSize = result.size();
forksList.addAll(result);
}
else {
adapter.setMoreDataAvailable(false);
}
adapter.notifyDataChanged();
progressLoadMore.setVisibility(View.GONE);
}
else {
Log.e(TAG, String.valueOf(response.code()));
}
}
@Override
public void onFailure(@NonNull Call<List<UserRepositories>> call, @NonNull Throwable t) {
Log.e(TAG, t.toString());
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.search_menu, menu);
MenuItem searchItem = menu.findItem(R.id.action_search);
SearchView searchView = (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) {
filter(newText);
return true;
}
});
return super.onCreateOptionsMenu(menu);
}
private void filter(String text) {
List<UserRepositories> arr = new ArrayList<>();
for(UserRepositories d : forksList) {
if(d.getName().toLowerCase().contains(text) || d.getDescription().toLowerCase().contains(text)) {
arr.add(d);
}
}
adapter.updateList(arr);
}
private void initCloseListener() {
onClickListener = view -> {
getIntent().removeExtra("repoFullNameForForks");
finish();
};
}
}

View File

@ -1,21 +1,17 @@
package org.mian.gitnex.activities;
import android.os.Bundle;
import androidx.annotation.Nullable;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import android.view.View;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.lifecycle.ViewModelProvider;
import org.mian.gitnex.R;
import org.mian.gitnex.adapters.RepoStargazersAdapter;
import org.mian.gitnex.databinding.ActivityRepoStargazersBinding;
import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.models.UserInfo;
import org.mian.gitnex.util.TinyDB;
import org.mian.gitnex.viewmodels.RepoStargazersViewModel;
import java.util.List;
/**
* Author M M Arif
@ -29,25 +25,19 @@ public class RepoStargazersActivity extends BaseActivity {
private GridView mGridView;
private ProgressBar mProgressBar;
@Override
protected int getLayoutResourceId(){
return R.layout.activity_repo_stargazers;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
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");
super.onCreate(savedInstanceState);
ImageView closeActivity = findViewById(R.id.close);
TextView toolbarTitle = findViewById(R.id.toolbar_title);
noDataStargazers = findViewById(R.id.noDataStargazers);
mGridView = findViewById(R.id.gridView);
mProgressBar = findViewById(R.id.progress_bar);
ActivityRepoStargazersBinding activityRepoStargazersBinding = ActivityRepoStargazersBinding.inflate(getLayoutInflater());
setContentView(activityRepoStargazersBinding.getRoot());
ImageView closeActivity = activityRepoStargazersBinding.close;
TextView toolbarTitle = activityRepoStargazersBinding.toolbarTitle;
noDataStargazers = activityRepoStargazersBinding.noDataStargazers;
mGridView = activityRepoStargazersBinding.gridView;
mProgressBar = activityRepoStargazersBinding.progressBar;
String repoFullNameForStars = getIntent().getStringExtra("repoFullNameForStars");
String[] parts = repoFullNameForStars.split("/");
@ -59,40 +49,37 @@ public class RepoStargazersActivity extends BaseActivity {
toolbarTitle.setText(R.string.repoStargazersInMenu);
fetchDataAsync(instanceUrl, Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName);
fetchDataAsync(Authorization.get(ctx), repoOwner, repoName);
}
private void fetchDataAsync(String instanceUrl, String instanceToken, String repoOwner, String repoName) {
private void fetchDataAsync(String instanceToken, String repoOwner, String repoName) {
RepoStargazersViewModel repoStargazersModel = new ViewModelProvider(this).get(RepoStargazersViewModel.class);
repoStargazersModel.getRepoStargazers(instanceUrl, instanceToken, repoOwner, repoName, getApplicationContext()).observe(this, new Observer<List<UserInfo>>() {
@Override
public void onChanged(@Nullable List<UserInfo> stargazersListMain) {
adapter = new RepoStargazersAdapter(getApplicationContext(), stargazersListMain);
if(adapter.getCount() > 0) {
mGridView.setAdapter(adapter);
noDataStargazers.setVisibility(View.GONE);
}
else {
adapter.notifyDataSetChanged();
mGridView.setAdapter(adapter);
noDataStargazers.setVisibility(View.VISIBLE);
}
mProgressBar.setVisibility(View.GONE);
repoStargazersModel.getRepoStargazers(instanceToken, repoOwner, repoName, ctx).observe(this, stargazersListMain -> {
adapter = new RepoStargazersAdapter(ctx, stargazersListMain);
if(adapter.getCount() > 0) {
mGridView.setAdapter(adapter);
noDataStargazers.setVisibility(View.GONE);
}
else {
adapter.notifyDataSetChanged();
mGridView.setAdapter(adapter);
noDataStargazers.setVisibility(View.VISIBLE);
}
mProgressBar.setVisibility(View.GONE);
});
}
private void initCloseListener() {
onClickListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
finish();
}
};
onClickListener = view -> finish();
}
}

View File

@ -1,21 +1,17 @@
package org.mian.gitnex.activities;
import android.os.Bundle;
import androidx.annotation.Nullable;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import android.view.View;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.lifecycle.ViewModelProvider;
import org.mian.gitnex.R;
import org.mian.gitnex.adapters.RepoWatchersAdapter;
import org.mian.gitnex.databinding.ActivityRepoWatchersBinding;
import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.models.UserInfo;
import org.mian.gitnex.util.TinyDB;
import org.mian.gitnex.viewmodels.RepoWatchersViewModel;
import java.util.List;
/**
* Author M M Arif
@ -29,25 +25,19 @@ public class RepoWatchersActivity extends BaseActivity {
private GridView mGridView;
private ProgressBar mProgressBar;
@Override
protected int getLayoutResourceId(){
return R.layout.activity_repo_watchers;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
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");
ActivityRepoWatchersBinding activityRepoWatchersBinding = ActivityRepoWatchersBinding.inflate(getLayoutInflater());
setContentView(activityRepoWatchersBinding.getRoot());
ImageView closeActivity = findViewById(R.id.close);
TextView toolbarTitle = findViewById(R.id.toolbar_title);
noDataWatchers = findViewById(R.id.noDataWatchers);
mGridView = findViewById(R.id.gridView);
mProgressBar = findViewById(R.id.progress_bar);
ImageView closeActivity = activityRepoWatchersBinding.close;
TextView toolbarTitle = activityRepoWatchersBinding.toolbarTitle;
noDataWatchers = activityRepoWatchersBinding.noDataWatchers;
mGridView = activityRepoWatchersBinding.gridView;
mProgressBar = activityRepoWatchersBinding.progressBar;
String repoFullNameForWatchers = getIntent().getStringExtra("repoFullNameForWatchers");
String[] parts = repoFullNameForWatchers.split("/");
@ -59,40 +49,37 @@ public class RepoWatchersActivity extends BaseActivity {
toolbarTitle.setText(R.string.repoWatchersInMenu);
fetchDataAsync(instanceUrl, Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName);
fetchDataAsync(Authorization.get(ctx), repoOwner, repoName);
}
private void fetchDataAsync(String instanceUrl, String instanceToken, String repoOwner, String repoName) {
private void fetchDataAsync(String instanceToken, String repoOwner, String repoName) {
RepoWatchersViewModel repoWatchersModel = new ViewModelProvider(this).get(RepoWatchersViewModel.class);
repoWatchersModel.getRepoWatchers(instanceUrl, instanceToken, repoOwner, repoName, getApplicationContext()).observe(this, new Observer<List<UserInfo>>() {
@Override
public void onChanged(@Nullable List<UserInfo> watchersListMain) {
adapter = new RepoWatchersAdapter(getApplicationContext(), watchersListMain);
if(adapter.getCount() > 0) {
mGridView.setAdapter(adapter);
noDataWatchers.setVisibility(View.GONE);
}
else {
adapter.notifyDataSetChanged();
mGridView.setAdapter(adapter);
noDataWatchers.setVisibility(View.VISIBLE);
}
mProgressBar.setVisibility(View.GONE);
repoWatchersModel.getRepoWatchers(instanceToken, repoOwner, repoName, ctx).observe(this, watchersListMain -> {
adapter = new RepoWatchersAdapter(ctx, watchersListMain);
if(adapter.getCount() > 0) {
mGridView.setAdapter(adapter);
noDataWatchers.setVisibility(View.GONE);
}
else {
adapter.notifyDataSetChanged();
mGridView.setAdapter(adapter);
noDataWatchers.setVisibility(View.VISIBLE);
}
mProgressBar.setVisibility(View.GONE);
});
}
private void initCloseListener() {
onClickListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
finish();
}
};
onClickListener = view -> finish();
}
}

View File

@ -0,0 +1,414 @@
package org.mian.gitnex.activities;
import android.app.Dialog;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import androidx.annotation.NonNull;
import com.google.gson.JsonElement;
import org.gitnex.tea4j.models.RepositoryTransfer;
import org.gitnex.tea4j.models.UserRepositories;
import org.mian.gitnex.R;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.database.api.BaseApi;
import org.mian.gitnex.database.api.RepositoriesApi;
import org.mian.gitnex.databinding.ActivityRepositorySettingsBinding;
import org.mian.gitnex.databinding.CustomRepositoryDeleteDialogBinding;
import org.mian.gitnex.databinding.CustomRepositoryEditPropertiesDialogBinding;
import org.mian.gitnex.databinding.CustomRepositoryTransferDialogBinding;
import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.helpers.Version;
import retrofit2.Call;
import retrofit2.Callback;
/**
* Author M M Arif
*/
public class RepositorySettingsActivity extends BaseActivity {
private ActivityRepositorySettingsBinding viewBinding;
private CustomRepositoryEditPropertiesDialogBinding propBinding;
private CustomRepositoryDeleteDialogBinding deleteRepoBinding;
private CustomRepositoryTransferDialogBinding transferRepoBinding;
private Dialog dialogProp;
private Dialog dialogDeleteRepository;
private Dialog dialogTransferRepository;
private View.OnClickListener onClickListener;
private String loginUid;
private String instanceToken;
private String repositoryOwner;
private String repositoryName;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
viewBinding = ActivityRepositorySettingsBinding.inflate(getLayoutInflater());
setContentView(viewBinding.getRoot());
loginUid = tinyDB.getString("loginUid");
String repoFullName = tinyDB.getString("repoFullName");
String[] parts = repoFullName.split("/");
repositoryOwner = parts[0];
repositoryName = parts[1];
instanceToken = "token " + tinyDB.getString(loginUid + "-token");
ImageView closeActivity = findViewById(R.id.close);
initCloseListener();
closeActivity.setOnClickListener(onClickListener);
// require gitea 1.12 or higher
if(new Version(tinyDB.getString("giteaVersion")).higherOrEqual("1.12.0")) {
viewBinding.transferOwnerFrame.setVisibility(View.VISIBLE);
}
viewBinding.editProperties.setOnClickListener(editProperties -> showRepositoryProperties());
viewBinding.deleteRepository.setOnClickListener(deleteRepository -> showDeleteRepository());
viewBinding.transferOwnerFrame.setOnClickListener(transferRepositoryOwnership -> showTransferRepository());
}
private void showTransferRepository() {
dialogTransferRepository = new Dialog(ctx, R.style.ThemeOverlay_MaterialComponents_Dialog_Alert);
if (dialogTransferRepository.getWindow() != null) {
dialogTransferRepository.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
}
transferRepoBinding = CustomRepositoryTransferDialogBinding.inflate(LayoutInflater.from(ctx));
View view = transferRepoBinding.getRoot();
dialogTransferRepository.setContentView(view);
transferRepoBinding.cancel.setOnClickListener(editProperties -> dialogTransferRepository.dismiss());
transferRepoBinding.transfer.setOnClickListener(deleteRepo -> {
String newOwner = String.valueOf(transferRepoBinding.ownerNameForTransfer.getText());
String repoName = String.valueOf(transferRepoBinding.repoNameForTransfer.getText());
if(!repositoryName.equals(repoName)) {
Toasty.error(ctx, getString(R.string.repoSettingsDeleteError));
}
else if(newOwner.matches("")) {
Toasty.error(ctx, getString(R.string.repoTransferOwnerError));
}
else {
transferRepository(newOwner);
}
});
dialogTransferRepository.setCancelable(false);
dialogTransferRepository.show();
}
private void transferRepository(String newOwner) {
RepositoryTransfer repositoryTransfer = new RepositoryTransfer(newOwner);
Call<JsonElement> transferCall = RetrofitClient
.getApiInterface(ctx)
.transferRepository(instanceToken, repositoryOwner, repositoryName, repositoryTransfer);
transferCall.enqueue(new Callback<JsonElement>() {
@Override
public void onResponse(@NonNull Call<JsonElement> call, @NonNull retrofit2.Response<JsonElement> response) {
transferRepoBinding.transfer.setVisibility(View.GONE);
transferRepoBinding.processingRequest.setVisibility(View.VISIBLE);
if (response.code() == 202) {
dialogTransferRepository.dismiss();
Toasty.success(ctx, getString(R.string.repoTransferSuccess));
finish();
BaseApi.getInstance(ctx, RepositoriesApi.class).deleteRepository((int) tinyDB.getLong("repositoryId", 0));
Intent intent = new Intent(RepositorySettingsActivity.this, MainActivity.class);
RepositorySettingsActivity.this.startActivity(intent);
}
else if (response.code() == 404) {
transferRepoBinding.transfer.setVisibility(View.VISIBLE);
transferRepoBinding.processingRequest.setVisibility(View.GONE);
Toasty.error(ctx, getString(R.string.repoTransferError));
}
else {
transferRepoBinding.transfer.setVisibility(View.VISIBLE);
transferRepoBinding.processingRequest.setVisibility(View.GONE);
Toasty.error(ctx, getString(R.string.genericError));
}
}
@Override
public void onFailure(@NonNull Call<JsonElement> call, @NonNull Throwable t) {
transferRepoBinding.transfer.setVisibility(View.VISIBLE);
transferRepoBinding.processingRequest.setVisibility(View.GONE);
Toasty.error(ctx, getString(R.string.genericServerResponseError));
}
});
}
private void showDeleteRepository() {
dialogDeleteRepository = new Dialog(ctx, R.style.ThemeOverlay_MaterialComponents_Dialog_Alert);
if (dialogDeleteRepository.getWindow() != null) {
dialogDeleteRepository.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
}
deleteRepoBinding = CustomRepositoryDeleteDialogBinding.inflate(LayoutInflater.from(ctx));
View view = deleteRepoBinding.getRoot();
dialogDeleteRepository.setContentView(view);
deleteRepoBinding.cancel.setOnClickListener(editProperties -> dialogDeleteRepository.dismiss());
deleteRepoBinding.delete.setOnClickListener(deleteRepo -> {
if(!repositoryName.equals(String.valueOf(deleteRepoBinding.repoNameForDeletion.getText()))) {
Toasty.error(ctx, getString(R.string.repoSettingsDeleteError));
}
else {
deleteRepository();
}
});
dialogDeleteRepository.setCancelable(false);
dialogDeleteRepository.show();
}
private void deleteRepository() {
Call<JsonElement> deleteCall = RetrofitClient
.getApiInterface(ctx)
.deleteRepository(instanceToken, repositoryOwner, repositoryName);
deleteCall.enqueue(new Callback<JsonElement>() {
@Override
public void onResponse(@NonNull Call<JsonElement> call, @NonNull retrofit2.Response<JsonElement> response) {
deleteRepoBinding.delete.setVisibility(View.GONE);
deleteRepoBinding.processingRequest.setVisibility(View.VISIBLE);
if (response.code() == 204) {
dialogDeleteRepository.dismiss();
Toasty.success(ctx, getString(R.string.repoDeletionSuccess));
finish();
BaseApi.getInstance(ctx, RepositoriesApi.class).deleteRepository((int) tinyDB.getLong("repositoryId", 0));
Intent intent = new Intent(RepositorySettingsActivity.this, MainActivity.class);
RepositorySettingsActivity.this.startActivity(intent);
}
else {
deleteRepoBinding.delete.setVisibility(View.VISIBLE);
deleteRepoBinding.processingRequest.setVisibility(View.GONE);
Toasty.error(ctx, getString(R.string.genericError));
}
}
@Override
public void onFailure(@NonNull Call<JsonElement> call, @NonNull Throwable t) {
deleteRepoBinding.delete.setVisibility(View.VISIBLE);
deleteRepoBinding.processingRequest.setVisibility(View.GONE);
Toasty.error(ctx, getString(R.string.genericServerResponseError));
}
});
}
private void showRepositoryProperties() {
dialogProp = new Dialog(ctx, R.style.ThemeOverlay_MaterialComponents_Dialog_Alert);
if (dialogProp.getWindow() != null) {
dialogProp.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
}
propBinding = CustomRepositoryEditPropertiesDialogBinding.inflate(LayoutInflater.from(ctx));
View view = propBinding.getRoot();
dialogProp.setContentView(view);
propBinding.cancel.setOnClickListener(editProperties -> dialogProp.dismiss());
Call<UserRepositories> call = RetrofitClient
.getApiInterface(ctx)
.getUserRepository(instanceToken, repositoryOwner, repositoryName);
call.enqueue(new Callback<UserRepositories>() {
@Override
public void onResponse(@NonNull Call<UserRepositories> call, @NonNull retrofit2.Response<UserRepositories> response) {
UserRepositories repoInfo = response.body();
propBinding.progressBar.setVisibility(View.GONE);
propBinding.mainView.setVisibility(View.VISIBLE);
if (response.code() == 200) {
assert repoInfo != null;
propBinding.repoName.setText(repoInfo.getName());
propBinding.repoWebsite.setText(repoInfo.getWebsite());
propBinding.repoDescription.setText(repoInfo.getDescription());
propBinding.repoPrivate.setChecked(repoInfo.getPrivateFlag());
propBinding.repoAsTemplate.setChecked(repoInfo.isTemplate());
propBinding.repoEnableIssues.setChecked(repoInfo.getHas_issues());
propBinding.repoEnableIssues.setOnCheckedChangeListener((buttonView, isChecked) -> {
if (isChecked) {
propBinding.repoEnableTimer.setVisibility(View.VISIBLE);
}
else {
propBinding.repoEnableTimer.setVisibility(View.GONE);
}
});
if(repoInfo.getInternal_tracker() != null) {
propBinding.repoEnableTimer.setChecked(repoInfo.getInternal_tracker().isEnable_time_tracker());
}
else {
propBinding.repoEnableTimer.setVisibility(View.GONE);
}
propBinding.repoEnableWiki.setChecked(repoInfo.isHas_wiki());
propBinding.repoEnablePr.setChecked(repoInfo.isHas_pull_requests());
propBinding.repoEnableMerge.setChecked(repoInfo.isAllow_merge_commits());
propBinding.repoEnableRebase.setChecked(repoInfo.isAllow_rebase());
propBinding.repoEnableSquash.setChecked(repoInfo.isAllow_squash_merge());
propBinding.repoEnableForceMerge.setChecked(repoInfo.isAllow_rebase_explicit());
}
else {
Toasty.error(ctx, getString(R.string.genericError));
}
}
@Override
public void onFailure(@NonNull Call<UserRepositories> call, @NonNull Throwable t) {
Toasty.error(ctx, getString(R.string.genericServerResponseError));
}
});
propBinding.save.setOnClickListener(saveProperties -> saveRepositoryProperties(String.valueOf(propBinding.repoName.getText()),
String.valueOf(propBinding.repoWebsite.getText()),
String.valueOf(propBinding.repoDescription.getText()),
propBinding.repoPrivate.isChecked(), propBinding.repoAsTemplate.isChecked(),
propBinding.repoEnableIssues.isChecked(), propBinding.repoEnableWiki.isChecked(),
propBinding.repoEnablePr.isChecked(), propBinding.repoEnableTimer.isChecked(),
propBinding.repoEnableMerge.isChecked(), propBinding.repoEnableRebase.isChecked(),
propBinding.repoEnableSquash.isChecked(), propBinding.repoEnableForceMerge.isChecked()));
dialogProp.setCancelable(false);
dialogProp.show();
}
private void saveRepositoryProperties(String repoName, String repoWebsite, String repoDescription,
boolean repoPrivate, boolean repoAsTemplate, boolean repoEnableIssues, boolean repoEnableWiki,
boolean repoEnablePr, boolean repoEnableTimer, boolean repoEnableMerge, boolean repoEnableRebase,
boolean repoEnableSquash, boolean repoEnableForceMerge) {
UserRepositories.internalTimeTrackerObject repoPropsTimeTracker = new UserRepositories.internalTimeTrackerObject(repoEnableTimer);
UserRepositories repoProps;
if(!repoEnableIssues) {
repoProps = new UserRepositories(repoName, repoWebsite, repoDescription, repoPrivate, repoAsTemplate, repoEnableIssues, repoEnableWiki, repoEnablePr, repoEnableMerge,
repoEnableRebase, repoEnableSquash, repoEnableForceMerge);
}
else {
repoProps = new UserRepositories(repoName, repoWebsite, repoDescription, repoPrivate, repoAsTemplate, repoEnableIssues, repoEnableWiki, repoEnablePr, repoPropsTimeTracker, repoEnableMerge,
repoEnableRebase, repoEnableSquash, repoEnableForceMerge);
}
Call<UserRepositories> propsCall = RetrofitClient
.getApiInterface(ctx)
.updateRepositoryProperties(instanceToken, repositoryOwner, repositoryName, repoProps);
propsCall.enqueue(new Callback<UserRepositories>() {
@Override
public void onResponse(@NonNull Call<UserRepositories> call, @NonNull retrofit2.Response<UserRepositories> response) {
propBinding.save.setVisibility(View.GONE);
propBinding.processingRequest.setVisibility(View.VISIBLE);
if (response.code() == 200) {
tinyDB.putBoolean("hasIssues", repoEnableIssues);
tinyDB.putBoolean("hasPullRequests", repoEnablePr);
dialogProp.dismiss();
Toasty.success(ctx, getString(R.string.repoPropertiesSaveSuccess));
if(!repositoryName.equals(repoName)) {
finish();
BaseApi.getInstance(ctx, RepositoriesApi.class).updateRepositoryOwnerAndName(repositoryOwner, repoName, (int) tinyDB.getLong("repositoryId", 0));
Intent intent = new Intent(RepositorySettingsActivity.this, MainActivity.class);
RepositorySettingsActivity.this.startActivity(intent);
}
}
else {
propBinding.save.setVisibility(View.VISIBLE);
propBinding.processingRequest.setVisibility(View.GONE);
Toasty.error(ctx, getString(R.string.genericError));
}
}
@Override
public void onFailure(@NonNull Call<UserRepositories> call, @NonNull Throwable t) {
propBinding.save.setVisibility(View.VISIBLE);
propBinding.processingRequest.setVisibility(View.GONE);
Toasty.error(ctx, getString(R.string.genericServerResponseError));
}
});
}
private void initCloseListener() {
onClickListener = view -> finish();
}
}

View File

@ -0,0 +1,252 @@
package org.mian.gitnex.activities;
import android.app.Dialog;
import android.app.TimePickerDialog;
import android.os.Bundle;
import android.text.format.DateFormat;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TimePicker;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.DialogFragment;
import com.google.android.material.switchmaterial.SwitchMaterial;
import org.jetbrains.annotations.NotNull;
import org.mian.gitnex.R;
import org.mian.gitnex.databinding.ActivitySettingsAppearanceBinding;
import org.mian.gitnex.helpers.TinyDB;
import org.mian.gitnex.helpers.Toasty;
/**
* Author M M Arif
*/
public class SettingsAppearanceActivity extends BaseActivity {
private View.OnClickListener onClickListener;
private static String[] timeList;
private static int timeSelectedChoice = 0;
private static String[] customFontList;
private static int customFontSelectedChoice = 0;
private static String[] themeList;
private static int themeSelectedChoice = 0;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivitySettingsAppearanceBinding activitySettingsAppearanceBinding = ActivitySettingsAppearanceBinding.inflate(getLayoutInflater());
setContentView(activitySettingsAppearanceBinding.getRoot());
ImageView closeActivity = activitySettingsAppearanceBinding.close;
LinearLayout timeFrame = activitySettingsAppearanceBinding.timeFrame;
LinearLayout customFontFrame = activitySettingsAppearanceBinding.customFontFrame;
LinearLayout themeFrame = activitySettingsAppearanceBinding.themeSelectionFrame;
LinearLayout lightTimeFrame = activitySettingsAppearanceBinding.lightThemeTimeSelectionFrame;
LinearLayout darkTimeFrame = activitySettingsAppearanceBinding.darkThemeTimeSelectionFrame;
SwitchMaterial counterBadgesSwitch = activitySettingsAppearanceBinding.switchCounterBadge;
timeList = getResources().getStringArray(R.array.timeFormats);
customFontList = getResources().getStringArray(R.array.fonts);
themeList = getResources().getStringArray(R.array.themes);
initCloseListener();
closeActivity.setOnClickListener(onClickListener);
String lightMinute = String.valueOf(tinyDB.getInt("lightThemeTimeMinute"));
String lightHour = String.valueOf(tinyDB.getInt("lightThemeTimeHour"));
if(lightMinute.length() == 1) lightMinute = "0" + lightMinute;
if(lightHour.length() == 1) lightHour = "0" + lightHour;
String darkMinute = String.valueOf(tinyDB.getInt("darkThemeTimeMinute"));
String darkHour = String.valueOf(tinyDB.getInt("darkThemeTimeHour"));
if(darkMinute.length() == 1) darkMinute = "0" + darkMinute;
if(darkHour.length() == 1) darkHour = "0" + darkHour;
activitySettingsAppearanceBinding.lightThemeSelectedTime.setText(ctx.getResources().getString(R.string.settingsThemeTimeSelectedHint, lightHour,
lightMinute));
activitySettingsAppearanceBinding.darkThemeSelectedTime.setText(ctx.getResources().getString(R.string.settingsThemeTimeSelectedHint, darkHour,
darkMinute));
activitySettingsAppearanceBinding.tvDateTimeSelected.setText(tinyDB.getString("timeStr"));
activitySettingsAppearanceBinding.customFontSelected.setText(tinyDB.getString("customFontStr", "Manrope"));
activitySettingsAppearanceBinding.themeSelected.setText(tinyDB.getString("themeStr", "Dark"));
if(tinyDB.getString("themeStr").startsWith("Auto")) {
darkTimeFrame.setVisibility(View.VISIBLE);
lightTimeFrame.setVisibility(View.VISIBLE);
}
else {
darkTimeFrame.setVisibility(View.GONE);
lightTimeFrame.setVisibility(View.GONE);
}
timeSelectedChoice = tinyDB.getInt("timeId");
customFontSelectedChoice = tinyDB.getInt("customFontId", 1);
themeSelectedChoice = tinyDB.getInt("themeId");
counterBadgesSwitch.setChecked(tinyDB.getBoolean("enableCounterBadges"));
// counter badge switcher
counterBadgesSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> {
tinyDB.putBoolean("enableCounterBadges", isChecked);
Toasty.success(appCtx, getResources().getString(R.string.settingsSave));
});
// theme selection dialog
themeFrame.setOnClickListener(view -> {
AlertDialog.Builder tsBuilder = new AlertDialog.Builder(SettingsAppearanceActivity.this);
tsBuilder.setTitle(getResources().getString(R.string.themeSelectorDialogTitle));
tsBuilder.setCancelable(themeSelectedChoice != -1);
tsBuilder.setSingleChoiceItems(themeList, themeSelectedChoice, (dialogInterfaceTheme, i) -> {
themeSelectedChoice = i;
activitySettingsAppearanceBinding.themeSelected.setText(themeList[i]);
tinyDB.putString("themeStr", themeList[i]);
tinyDB.putInt("themeId", i);
tinyDB.putBoolean("refreshParent", true);
this.recreate();
this.overridePendingTransition(0, 0);
dialogInterfaceTheme.dismiss();
Toasty.success(appCtx, getResources().getString(R.string.settingsSave));
});
AlertDialog cfDialog = tsBuilder.create();
cfDialog.show();
});
lightTimeFrame.setOnClickListener(view -> {
LightTimePicker timePicker = new LightTimePicker();
timePicker.show(getSupportFragmentManager(), "timePicker");
});
darkTimeFrame.setOnClickListener(view -> {
DarkTimePicker timePicker = new DarkTimePicker();
timePicker.show(getSupportFragmentManager(), "timePicker");
});
// custom font dialog
customFontFrame.setOnClickListener(view -> {
AlertDialog.Builder cfBuilder = new AlertDialog.Builder(SettingsAppearanceActivity.this);
cfBuilder.setTitle(R.string.settingsCustomFontSelectorDialogTitle);
cfBuilder.setCancelable(customFontSelectedChoice != -1);
cfBuilder.setSingleChoiceItems(customFontList, customFontSelectedChoice, (dialogInterfaceCustomFont, i) -> {
customFontSelectedChoice = i;
activitySettingsAppearanceBinding.customFontSelected.setText(customFontList[i]);
tinyDB.putString("customFontStr", customFontList[i]);
tinyDB.putInt("customFontId", i);
tinyDB.putBoolean("refreshParent", true);
this.recreate();
this.overridePendingTransition(0, 0);
dialogInterfaceCustomFont.dismiss();
Toasty.success(appCtx, appCtx.getResources().getString(R.string.settingsSave));
});
AlertDialog cfDialog = cfBuilder.create();
cfDialog.show();
});
// time and date dialog
timeFrame.setOnClickListener(view -> {
AlertDialog.Builder tBuilder = new AlertDialog.Builder(SettingsAppearanceActivity.this);
tBuilder.setTitle(R.string.settingsTimeSelectorDialogTitle);
tBuilder.setCancelable(timeSelectedChoice != -1);
tBuilder.setSingleChoiceItems(timeList, timeSelectedChoice, (dialogInterfaceTime, i) -> {
timeSelectedChoice = i;
activitySettingsAppearanceBinding.tvDateTimeSelected.setText(timeList[i]);
tinyDB.putString("timeStr", timeList[i]);
tinyDB.putInt("timeId", i);
switch(i) {
case 0:
tinyDB.putString("dateFormat", "pretty");
break;
case 1:
tinyDB.putString("dateFormat", "normal");
break;
}
dialogInterfaceTime.dismiss();
Toasty.success(appCtx, getResources().getString(R.string.settingsSave));
});
AlertDialog tDialog = tBuilder.create();
tDialog.show();
});
}
private void initCloseListener() {
onClickListener = view -> finish();
}
public static class LightTimePicker extends DialogFragment implements TimePickerDialog.OnTimeSetListener {
TinyDB db = TinyDB.getInstance(getContext());
@NotNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
int hour = db.getInt("lightThemeTimeHour");
int minute = db.getInt("lightThemeTimeMinute");
return new TimePickerDialog(getActivity(), this, hour, minute, true);
}
@Override
public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
db.putInt("lightThemeTimeHour", hourOfDay);
db.putInt("lightThemeTimeMinute", minute);
db.putBoolean("refreshParent", true);
requireActivity().overridePendingTransition(0, 0);
this.dismiss();
Toasty.success(requireActivity().getApplicationContext(), requireContext().getResources().getString(R.string.settingsSave));
requireActivity().recreate();
}
}
public static class DarkTimePicker extends DialogFragment implements TimePickerDialog.OnTimeSetListener {
TinyDB db = TinyDB.getInstance(getContext());
@NotNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
int hour = db.getInt("darkThemeTimeHour");
int minute = db.getInt("darkThemeTimeMinute");
return new TimePickerDialog(getActivity(), this, hour, minute, true);
}
@Override
public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
db.putInt("darkThemeTimeHour", hourOfDay);
db.putInt("darkThemeTimeMinute", minute);
db.putBoolean("refreshParent", true);
requireActivity().overridePendingTransition(0, 0);
this.dismiss();
Toasty.success(requireActivity().getApplicationContext(), requireContext().getResources().getString(R.string.settingsSave));
requireActivity().recreate();
}
}
}

View File

@ -0,0 +1,44 @@
package org.mian.gitnex.activities;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
import org.mian.gitnex.R;
import org.mian.gitnex.databinding.ActivitySettingsDraftsBinding;
import org.mian.gitnex.helpers.Toasty;
/**
* Author M M Arif
*/
public class SettingsDraftsActivity extends BaseActivity {
private View.OnClickListener onClickListener;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivitySettingsDraftsBinding activitySettingsDraftsBinding = ActivitySettingsDraftsBinding.inflate(getLayoutInflater());
setContentView(activitySettingsDraftsBinding.getRoot());
ImageView closeActivity = activitySettingsDraftsBinding.close;
initCloseListener();
closeActivity.setOnClickListener(onClickListener);
activitySettingsDraftsBinding.commentsDeletionSwitch.setChecked(tinyDB.getBoolean("draftsCommentsDeletionEnabled"));
// delete comments on submit switcher
activitySettingsDraftsBinding.commentsDeletionSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> {
tinyDB.putBoolean("draftsCommentsDeletionEnabled", isChecked);
Toasty.success(appCtx, getResources().getString(R.string.settingsSave));
});
}
private void initCloseListener() { onClickListener = view -> finish(); }
}

View File

@ -0,0 +1,145 @@
package org.mian.gitnex.activities;
import android.os.Bundle;
import android.view.View;
import androidx.appcompat.app.AlertDialog;
import org.mian.gitnex.R;
import org.mian.gitnex.databinding.ActivitySettingsGeneralBinding;
import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.helpers.Version;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Author M M Arif
*/
public class SettingsGeneralActivity extends BaseActivity {
private ActivitySettingsGeneralBinding viewBinding;
private View.OnClickListener onClickListener;
private List<String> homeScreenList;
private static int homeScreenSelectedChoice = 0;
private List<String> linkHandlerDefaultScreen;
private static int defaultLinkHandlerScreenSelectedChoice = 0;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
viewBinding = ActivitySettingsGeneralBinding.inflate(getLayoutInflater());
setContentView(viewBinding.getRoot());
initCloseListener();
viewBinding.close.setOnClickListener(onClickListener);
// home screen
String[] appHomeDefaultScreen = getResources().getStringArray(R.array.appDefaultHomeScreen);
String[] appHomeDefaultScreenNew = getResources().getStringArray(R.array.appDefaultHomeScreenNew);
if(new Version(tinyDB.getString("giteaVersion")).higherOrEqual("1.12.3")) {
appHomeDefaultScreen = appHomeDefaultScreenNew;
}
homeScreenList = new ArrayList<>(Arrays.asList(appHomeDefaultScreen));
String[] homeScreenArray = new String[homeScreenList.size()];
homeScreenList.toArray(homeScreenArray);
if(homeScreenSelectedChoice == 0) {
homeScreenSelectedChoice = tinyDB.getInt("homeScreenId");
viewBinding.homeScreenSelected.setText(getResources().getString(R.string.pageTitleMyRepos));
}
if(homeScreenSelectedChoice == 1) {
viewBinding.homeScreenSelected.setText(getResources().getString(R.string.pageTitleStarredRepos));
}
else if(homeScreenSelectedChoice == 2) {
viewBinding.homeScreenSelected.setText(getResources().getString(R.string.pageTitleOrganizations));
}
else if(homeScreenSelectedChoice == 3) {
viewBinding.homeScreenSelected.setText(getResources().getString(R.string.pageTitleRepositories));
}
else if(homeScreenSelectedChoice == 4) {
viewBinding.homeScreenSelected.setText(getResources().getString(R.string.pageTitleProfile));
}
else if(homeScreenSelectedChoice == 5) {
viewBinding.homeScreenSelected.setText(getResources().getString(R.string.pageTitleExplore));
}
else if(homeScreenSelectedChoice == 6) {
viewBinding.homeScreenSelected.setText(getResources().getString(R.string.titleDrafts));
}
else if(homeScreenSelectedChoice == 7) {
viewBinding.homeScreenSelected.setText(getResources().getString(R.string.pageTitleNotifications));
}
viewBinding.homeScreenFrame.setOnClickListener(setDefaultHomeScreen -> {
AlertDialog.Builder hsBuilder = new AlertDialog.Builder(SettingsGeneralActivity.this);
hsBuilder.setTitle(R.string.settingsHomeScreenSelectorDialogTitle);
hsBuilder.setCancelable(homeScreenSelectedChoice != -1);
hsBuilder.setSingleChoiceItems(homeScreenArray, homeScreenSelectedChoice, (dialogInterfaceHomeScreen, i) -> {
homeScreenSelectedChoice = i;
viewBinding.homeScreenSelected.setText(homeScreenArray[i]);
tinyDB.putInt("homeScreenId", i);
dialogInterfaceHomeScreen.dismiss();
Toasty.success(appCtx, getResources().getString(R.string.settingsSave));
});
AlertDialog hsDialog = hsBuilder.create();
hsDialog.show();
});
// home screen
// link handler
String[] linkHandlerDefaultScreenList = getResources().getStringArray(R.array.linkHandlerDefaultScreen);
linkHandlerDefaultScreen = new ArrayList<>(Arrays.asList(linkHandlerDefaultScreenList));
String[] linksArray = new String[linkHandlerDefaultScreen.size()];
linkHandlerDefaultScreen.toArray(linksArray);
defaultLinkHandlerScreenSelectedChoice = tinyDB.getInt("defaultScreenId");
viewBinding.generalDeepLinkSelected.setText(linksArray[defaultLinkHandlerScreenSelectedChoice]);
viewBinding.setDefaultLinkHandler.setOnClickListener(setDefaultLinkHandler -> {
AlertDialog.Builder dlBuilder = new AlertDialog.Builder(SettingsGeneralActivity.this);
dlBuilder.setTitle(R.string.linkSelectorDialogTitle);
dlBuilder.setCancelable(defaultLinkHandlerScreenSelectedChoice != -1);
dlBuilder.setSingleChoiceItems(linksArray, defaultLinkHandlerScreenSelectedChoice, (dialogInterfaceHomeScreen, i) -> {
defaultLinkHandlerScreenSelectedChoice = i;
viewBinding.generalDeepLinkSelected.setText(linksArray[i]);
tinyDB.putInt("defaultScreenId", i);
dialogInterfaceHomeScreen.dismiss();
Toasty.success(appCtx, getResources().getString(R.string.settingsSave));
});
AlertDialog dlDialog = dlBuilder.create();
dlDialog.show();
});
// link handler
}
private void initCloseListener() { onClickListener = view -> finish(); }
}

View File

@ -0,0 +1,123 @@
package org.mian.gitnex.activities;
import android.graphics.Color;
import android.os.Bundle;
import android.view.View;
import android.widget.NumberPicker;
import androidx.appcompat.app.AlertDialog;
import com.pes.androidmaterialcolorpickerdialog.ColorPicker;
import org.mian.gitnex.R;
import org.mian.gitnex.databinding.ActivitySettingsNotificationsBinding;
import org.mian.gitnex.helpers.Constants;
import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.notifications.Notifications;
/**
* Template Author M M Arif
* Author opyale
*/
public class SettingsNotificationsActivity extends BaseActivity {
private ActivitySettingsNotificationsBinding viewBinding;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
viewBinding = ActivitySettingsNotificationsBinding.inflate(getLayoutInflater());
setContentView(viewBinding.getRoot());
View.OnClickListener onClickListener = viewClose -> finish();
viewBinding.close.setOnClickListener(onClickListener);
viewBinding.pollingDelaySelected.setText(String.format(getString(R.string.pollingDelaySelectedText), tinyDB.getInt("pollingDelayMinutes", Constants.defaultPollingDelay)));
viewBinding.chooseColorState.setCardBackgroundColor(tinyDB.getInt("notificationsLightColor", Color.GREEN));
viewBinding.enableNotificationsMode.setChecked(tinyDB.getBoolean("notificationsEnabled", true));
viewBinding.enableLightsMode.setChecked(tinyDB.getBoolean("notificationsEnableLights", true));
viewBinding.enableVibrationMode.setChecked(tinyDB.getBoolean("notificationsEnableVibration", true));
viewBinding.enableNotificationsMode.setOnCheckedChangeListener((buttonView, isChecked) -> {
tinyDB.putBoolean("notificationsEnabled", isChecked);
if(isChecked) {
Notifications.startWorker(ctx);
} else {
Notifications.stopWorker(ctx);
}
Toasty.info(appCtx, getResources().getString(R.string.settingsSave));
});
// polling delay
viewBinding.pollingDelayFrame.setOnClickListener(v -> {
NumberPicker numberPicker = new NumberPicker(ctx);
numberPicker.setMinValue(Constants.minimumPollingDelay);
numberPicker.setMaxValue(Constants.maximumPollingDelay);
numberPicker.setValue(tinyDB.getInt("pollingDelayMinutes", Constants.defaultPollingDelay));
numberPicker.setWrapSelectorWheel(true);
AlertDialog.Builder builder = new AlertDialog.Builder(ctx);
builder.setTitle(getString(R.string.pollingDelayDialogHeaderText));
builder.setMessage(getString(R.string.pollingDelayDialogDescriptionText));
builder.setCancelable(true);
builder.setPositiveButton(getString(R.string.okButton), (dialog, which) -> {
tinyDB.putInt("pollingDelayMinutes", numberPicker.getValue());
Notifications.stopWorker(ctx);
Notifications.startWorker(ctx);
viewBinding.pollingDelaySelected.setText(String.format(getString(R.string.pollingDelaySelectedText), numberPicker.getValue()));
Toasty.info(appCtx, getResources().getString(R.string.settingsSave));
});
builder.setNeutralButton(R.string.cancelButton, (dialog, which) -> dialog.dismiss());
builder.setView(numberPicker);
builder.create().show();
});
// lights switcher
viewBinding.enableLightsMode.setOnCheckedChangeListener((buttonView, isChecked) -> {
tinyDB.putBoolean("notificationsEnableLights", isChecked);
Toasty.info(appCtx, getResources().getString(R.string.settingsSave));
});
// lights color chooser
viewBinding.chooseColorFrame.setOnClickListener(v -> {
ColorPicker colorPicker = new ColorPicker(SettingsNotificationsActivity.this);
colorPicker.setColor(tinyDB.getInt("notificationsLightColor", Color.GREEN));
colorPicker.setCallback(color -> {
tinyDB.putInt("notificationsLightColor", color);
viewBinding.chooseColorState.setCardBackgroundColor(color);
colorPicker.dismiss();
Toasty.info(appCtx, getResources().getString(R.string.settingsSave));
});
colorPicker.show();
});
// vibration switcher
viewBinding.enableVibrationMode.setOnCheckedChangeListener((buttonView, isChecked) -> {
tinyDB.putBoolean("notificationsEnableVibration", isChecked);
Toasty.info(appCtx, getResources().getString(R.string.settingsSave));
});
}
}

View File

@ -0,0 +1,45 @@
package org.mian.gitnex.activities;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
import org.mian.gitnex.R;
import org.mian.gitnex.databinding.ActivitySettingsReportsBinding;
import org.mian.gitnex.helpers.Toasty;
/**
* Author M M Arif
*/
public class SettingsReportsActivity extends BaseActivity {
private View.OnClickListener onClickListener;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivitySettingsReportsBinding activitySettingsReportsBinding = ActivitySettingsReportsBinding.inflate(getLayoutInflater());
setContentView(activitySettingsReportsBinding.getRoot());
ImageView closeActivity = activitySettingsReportsBinding.close;
initCloseListener();
closeActivity.setOnClickListener(onClickListener);
activitySettingsReportsBinding.crashReportsSwitch.setChecked(tinyDB.getBoolean("crashReportingEnabled"));
// crash reports switcher
activitySettingsReportsBinding.crashReportsSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> {
tinyDB.putBoolean("crashReportingEnabled", isChecked);
Toasty.success(appCtx, getResources().getString(R.string.settingsSave));
});
}
private void initCloseListener() {
onClickListener = view -> finish();
}
}

View File

@ -0,0 +1,257 @@
package org.mian.gitnex.activities;
import android.app.KeyguardManager;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.appcompat.app.AlertDialog;
import androidx.biometric.BiometricManager;
import com.google.android.material.switchmaterial.SwitchMaterial;
import org.apache.commons.io.FileUtils;
import org.mian.gitnex.R;
import org.mian.gitnex.databinding.ActivitySettingsSecurityBinding;
import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.helpers.ssl.MemorizingTrustManager;
import java.io.File;
import java.io.IOException;
import static androidx.biometric.BiometricManager.Authenticators.BIOMETRIC_STRONG;
import static androidx.biometric.BiometricManager.Authenticators.DEVICE_CREDENTIAL;
/**
* Author M M Arif
*/
public class SettingsSecurityActivity extends BaseActivity {
private View.OnClickListener onClickListener;
private static String[] cacheSizeDataList;
private static int cacheSizeDataSelectedChoice = 0;
private static String[] cacheSizeImagesList;
private static int cacheSizeImagesSelectedChoice = 0;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivitySettingsSecurityBinding activitySettingsSecurityBinding = ActivitySettingsSecurityBinding.inflate(getLayoutInflater());
setContentView(activitySettingsSecurityBinding.getRoot());
ImageView closeActivity = activitySettingsSecurityBinding.close;
initCloseListener();
closeActivity.setOnClickListener(onClickListener);
TextView cacheSizeDataSelected = activitySettingsSecurityBinding.cacheSizeDataSelected; // setter for data cache size
TextView cacheSizeImagesSelected = activitySettingsSecurityBinding.cacheSizeImagesSelected; // setter for images cache size
TextView clearCacheSelected = activitySettingsSecurityBinding.clearCacheSelected; // setter for clear cache
LinearLayout certsFrame = activitySettingsSecurityBinding.certsFrame;
LinearLayout cacheSizeDataFrame = activitySettingsSecurityBinding.cacheSizeDataSelectionFrame;
LinearLayout cacheSizeImagesFrame = activitySettingsSecurityBinding.cacheSizeImagesSelectionFrame;
LinearLayout clearCacheFrame = activitySettingsSecurityBinding.clearCacheSelectionFrame;
SwitchMaterial switchBiometric = activitySettingsSecurityBinding.switchBiometric;
cacheSizeDataList = getResources().getStringArray(R.array.cacheSizeList);
cacheSizeImagesList = getResources().getStringArray(R.array.cacheSizeList);
if(!tinyDB.getString("cacheSizeStr").isEmpty()) {
cacheSizeDataSelected.setText(tinyDB.getString("cacheSizeStr"));
}
if(!tinyDB.getString("cacheSizeImagesStr").isEmpty()) {
cacheSizeImagesSelected.setText(tinyDB.getString("cacheSizeImagesStr"));
}
if(cacheSizeDataSelectedChoice == 0) {
cacheSizeDataSelectedChoice = tinyDB.getInt("cacheSizeId");
}
if(cacheSizeImagesSelectedChoice == 0) {
cacheSizeImagesSelectedChoice = tinyDB.getInt("cacheSizeImagesId");
}
switchBiometric.setChecked(tinyDB.getBoolean("biometricStatus"));
// biometric switcher
switchBiometric.setOnCheckedChangeListener((buttonView, isChecked) -> {
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if(isChecked) {
BiometricManager biometricManager = BiometricManager.from(ctx);
KeyguardManager keyguardManager = (KeyguardManager) ctx.getSystemService(Context.KEYGUARD_SERVICE);
if (!keyguardManager.isDeviceSecure()) {
switch(biometricManager.canAuthenticate(BIOMETRIC_STRONG | DEVICE_CREDENTIAL)) {
case BiometricManager.BIOMETRIC_SUCCESS:
tinyDB.putBoolean("biometricStatus", true);
Toasty.success(appCtx, getResources().getString(R.string.settingsSave));
break;
case BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE:
case BiometricManager.BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED:
case BiometricManager.BIOMETRIC_ERROR_UNSUPPORTED:
case BiometricManager.BIOMETRIC_STATUS_UNKNOWN:
tinyDB.putBoolean("biometricStatus", false);
switchBiometric.setChecked(false);
Toasty.error(appCtx, getResources().getString(R.string.biometricNotSupported));
break;
case BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE:
tinyDB.putBoolean("biometricStatus", false);
switchBiometric.setChecked(false);
Toasty.error(appCtx, getResources().getString(R.string.biometricNotAvailable));
break;
case BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED:
tinyDB.putBoolean("biometricStatus", false);
switchBiometric.setChecked(false);
Toasty.info(appCtx, getResources().getString(R.string.enrollBiometric));
break;
}
}
else {
tinyDB.putBoolean("biometricStatus", true);
Toasty.success(appCtx, getResources().getString(R.string.settingsSave));
}
}
else {
tinyDB.putBoolean("biometricStatus", false);
Toasty.success(appCtx, getResources().getString(R.string.settingsSave));
}
}
else {
tinyDB.putBoolean("biometricStatus", false);
Toasty.success(appCtx, getResources().getString(R.string.biometricNotSupported));
}
});
// clear cache setter
File cacheDir = appCtx.getCacheDir();
clearCacheSelected.setText(FileUtils.byteCountToDisplaySize((int) FileUtils.sizeOfDirectory(cacheDir)));
// clear cache
clearCacheFrame.setOnClickListener(v1 -> {
AlertDialog.Builder builder = new AlertDialog.Builder(SettingsSecurityActivity.this);
builder.setTitle(getResources().getString(R.string.clearCacheDialogHeader));
builder.setMessage(getResources().getString(R.string.clearCacheDialogMessage));
builder.setPositiveButton(R.string.menuDeleteText, (dialog, which) -> {
try {
FileUtils.deleteDirectory(cacheDir);
FileUtils.mkdir(cacheDir.getAbsolutePath());
this.recreate();
this.overridePendingTransition(0, 0);
}
catch (IOException e) {
Log.e("SettingsSecurity", e.toString());
}
});
builder.setNeutralButton(R.string.cancelButton, (dialog, which) -> dialog.dismiss());
builder.create().show();
});
// cache size images selection dialog
cacheSizeImagesFrame.setOnClickListener(view -> {
AlertDialog.Builder tsBuilder = new AlertDialog.Builder(SettingsSecurityActivity.this);
tsBuilder.setTitle(getResources().getString(R.string.cacheSizeImagesDialogHeader));
tsBuilder.setCancelable(cacheSizeImagesSelectedChoice != -1);
tsBuilder.setSingleChoiceItems(cacheSizeImagesList, cacheSizeImagesSelectedChoice, (dialogInterfaceTheme, i) -> {
cacheSizeImagesSelectedChoice = i;
cacheSizeImagesSelected.setText(cacheSizeImagesList[i]);
tinyDB.putString("cacheSizeImagesStr", cacheSizeImagesList[i]);
tinyDB.putInt("cacheSizeImagesId", i);
dialogInterfaceTheme.dismiss();
Toasty.success(appCtx, getResources().getString(R.string.settingsSave));
});
AlertDialog cfDialog = tsBuilder.create();
cfDialog.show();
});
// cache size data selection dialog
cacheSizeDataFrame.setOnClickListener(view -> {
AlertDialog.Builder tsBuilder = new AlertDialog.Builder(SettingsSecurityActivity.this);
tsBuilder.setTitle(getResources().getString(R.string.cacheSizeDataDialogHeader));
tsBuilder.setCancelable(cacheSizeDataSelectedChoice != -1);
tsBuilder.setSingleChoiceItems(cacheSizeDataList, cacheSizeDataSelectedChoice, (dialogInterfaceTheme, i) -> {
cacheSizeDataSelectedChoice = i;
cacheSizeDataSelected.setText(cacheSizeDataList[i]);
tinyDB.putString("cacheSizeStr", cacheSizeDataList[i]);
tinyDB.putInt("cacheSizeId", i);
dialogInterfaceTheme.dismiss();
Toasty.success(appCtx, getResources().getString(R.string.settingsSave));
});
AlertDialog cfDialog = tsBuilder.create();
cfDialog.show();
});
// certs deletion
certsFrame.setOnClickListener(v1 -> {
AlertDialog.Builder builder = new AlertDialog.Builder(SettingsSecurityActivity.this);
builder.setTitle(getResources().getString(R.string.settingsCertsPopupTitle));
builder.setMessage(getResources().getString(R.string.settingsCertsPopupMessage));
builder.setPositiveButton(R.string.menuDeleteText, (dialog, which) -> {
appCtx.getSharedPreferences(MemorizingTrustManager.KEYSTORE_NAME, Context.MODE_PRIVATE).edit().remove(MemorizingTrustManager.KEYSTORE_KEY).apply();
tinyDB.putBoolean("loggedInMode", false);
tinyDB.remove("basicAuthPassword");
tinyDB.putBoolean("basicAuthFlag", false);
Intent loginActivityIntent = new Intent().setClass(appCtx, LoginActivity.class);
loginActivityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
appCtx.startActivity(loginActivityIntent);
});
builder.setNeutralButton(R.string.cancelButton, (dialog, which) -> dialog.dismiss());
builder.create().show();
});
}
private void initCloseListener() {
onClickListener = view -> finish();
}
}

View File

@ -0,0 +1,106 @@
package org.mian.gitnex.activities;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.appcompat.app.AlertDialog;
import org.mian.gitnex.R;
import org.mian.gitnex.databinding.ActivitySettingsTranslationBinding;
import org.mian.gitnex.helpers.Toasty;
import java.util.LinkedHashMap;
import java.util.Locale;
import java.util.TreeMap;
/**
* Author M M Arif
*/
public class SettingsTranslationActivity extends BaseActivity {
private View.OnClickListener onClickListener;
private static int langSelectedChoice = 0;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LinkedHashMap<String, String> langs = new LinkedHashMap<>();
langs.put("", getString(R.string.settingsLanguageSystem));
for(String langCode : getResources().getStringArray(R.array.languages)) {
langs.put(langCode, getLanguageDisplayName(langCode));
}
ActivitySettingsTranslationBinding activitySettingsTranslationBinding = ActivitySettingsTranslationBinding.inflate(getLayoutInflater());
setContentView(activitySettingsTranslationBinding.getRoot());
ImageView closeActivity = activitySettingsTranslationBinding.close;
initCloseListener();
closeActivity.setOnClickListener(onClickListener);
final TextView tvLanguageSelected = activitySettingsTranslationBinding.tvLanguageSelected; // setter for en, fr
TextView helpTranslate = activitySettingsTranslationBinding.helpTranslate;
LinearLayout langFrame = activitySettingsTranslationBinding.langFrame;
helpTranslate.setOnClickListener(v12 -> {
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.addCategory(Intent.CATEGORY_BROWSABLE);
intent.setData(Uri.parse(getResources().getString(R.string.crowdInLink)));
startActivity(intent);
});
tvLanguageSelected.setText(tinyDB.getString("localeStr"));
langSelectedChoice = tinyDB.getInt("langId");
// language dialog
langFrame.setOnClickListener(view -> {
AlertDialog.Builder lBuilder = new AlertDialog.Builder(SettingsTranslationActivity.this);
lBuilder.setTitle(R.string.settingsLanguageSelectorDialogTitle);
lBuilder.setCancelable(langSelectedChoice != -1);
lBuilder.setSingleChoiceItems(langs.values().toArray(new String[0]), langSelectedChoice, (dialogInterface, i) -> {
String selectedLanguage = langs.keySet().toArray(new String[0])[i];
tinyDB.putString("localeStr", langs.get(selectedLanguage));
tinyDB.putInt("langId", i);
tinyDB.putString("locale", selectedLanguage);
tinyDB.putBoolean("refreshParent", true);
this.overridePendingTransition(0, 0);
dialogInterface.dismiss();
Toasty.success(appCtx, getResources().getString(R.string.settingsSave));
this.recreate();
});
lBuilder.setNeutralButton(getString(R.string.cancelButton), null);
AlertDialog lDialog = lBuilder.create();
lDialog.show();
});
}
private void initCloseListener() {
onClickListener = view -> finish();
}
private static String getLanguageDisplayName(String langCode) {
Locale english = new Locale("en");
Locale translated = new Locale(langCode);
return String.format("%s (%s)", translated.getDisplayName(translated), translated.getDisplayName(english));
}
}

View File

@ -1,66 +0,0 @@
package org.mian.gitnex.activities;
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.view.View;
import android.widget.ImageView;
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
*/
public class SponsorsActivity extends BaseActivity {
private View.OnClickListener onClickListener;
@Override
protected int getLayoutResourceId(){
return R.layout.activity_sponsors;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ImageView closeActivity = findViewById(R.id.close);
initCloseListener();
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() {
onClickListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
finish();
}
};
}
}

View File

@ -0,0 +1,171 @@
package org.mian.gitnex.adapters;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.recyclerview.widget.RecyclerView;
import com.google.gson.JsonElement;
import org.apache.commons.lang3.StringUtils;
import org.gitnex.tea4j.models.CronTasks;
import org.mian.gitnex.R;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.helpers.AlertDialogs;
import org.mian.gitnex.helpers.TimeHelper;
import org.mian.gitnex.helpers.TinyDB;
import org.mian.gitnex.helpers.Toasty;
import java.util.List;
import java.util.Locale;
import retrofit2.Call;
import retrofit2.Callback;
/**
* Author M M Arif
*/
public class AdminCronTasksAdapter extends RecyclerView.Adapter<AdminCronTasksAdapter.CronTasksViewHolder> {
private final List<CronTasks> tasksList;
private static TinyDB tinyDb;
static class CronTasksViewHolder extends RecyclerView.ViewHolder {
private CronTasks cronTasks;
private final TextView taskName;
private CronTasksViewHolder(View itemView) {
super(itemView);
Context ctx = itemView.getContext();
final Locale locale = ctx.getResources().getConfiguration().locale;
final String timeFormat = tinyDb.getString("dateFormat");
ImageView runTask = itemView.findViewById(R.id.runTask);
taskName = itemView.findViewById(R.id.taskName);
LinearLayout cronTasksInfo = itemView.findViewById(R.id.cronTasksInfo);
LinearLayout cronTasksRun = itemView.findViewById(R.id.cronTasksRun);
cronTasksInfo.setOnClickListener(taskInfo -> {
String nextRun = "";
String lastRun = "";
if(cronTasks.getNext() != null) {
nextRun = TimeHelper.formatTime(cronTasks.getNext(), locale, timeFormat, ctx);
}
if(cronTasks.getPrev() != null) {
lastRun = TimeHelper.formatTime(cronTasks.getPrev(), locale, timeFormat, ctx);
}
View view = LayoutInflater.from(ctx).inflate(R.layout.layout_cron_task_info, null);
TextView taskScheduleContent = view.findViewById(R.id.taskScheduleContent);
TextView nextRunContent = view.findViewById(R.id.nextRunContent);
TextView lastRunContent = view.findViewById(R.id.lastRunContent);
TextView execTimeContent = view.findViewById(R.id.execTimeContent);
taskScheduleContent.setText(cronTasks.getSchedule());
nextRunContent.setText(nextRun);
lastRunContent.setText(lastRun);
execTimeContent.setText(String.valueOf(cronTasks.getExec_times()));
AlertDialog.Builder alertDialog = new AlertDialog.Builder(ctx);
alertDialog.setTitle(StringUtils.capitalize(cronTasks.getName().replace("_", " ")));
alertDialog.setView(view);
alertDialog.setPositiveButton(ctx.getString(R.string.close), null);
alertDialog.create().show();
});
cronTasksRun.setOnClickListener(taskInfo -> {
runCronTask(ctx, cronTasks.getName());
});
}
}
public AdminCronTasksAdapter(Context ctx, List<CronTasks> tasksListMain) {
tinyDb = TinyDB.getInstance(ctx);
this.tasksList = tasksListMain;
}
@NonNull
@Override
public AdminCronTasksAdapter.CronTasksViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_admin_cron_tasks, parent, false);
return new AdminCronTasksAdapter.CronTasksViewHolder(v);
}
@Override
public void onBindViewHolder(@NonNull AdminCronTasksAdapter.CronTasksViewHolder holder, int position) {
CronTasks currentItem = tasksList.get(position);
holder.cronTasks = currentItem;
holder.taskName.setText(StringUtils.capitalize(currentItem.getName().replace("_", " ")));
}
private static void runCronTask(final Context ctx, final String taskName) {
final String loginUid = tinyDb.getString("loginUid");
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
Call<JsonElement> call = RetrofitClient
.getApiInterface(ctx)
.adminRunCronTask(instanceToken, taskName);
call.enqueue(new Callback<JsonElement>() {
@Override
public void onResponse(@NonNull Call<JsonElement> call, @NonNull retrofit2.Response<JsonElement> response) {
switch(response.code()) {
case 204:
Toasty.success(ctx, ctx.getString(R.string.adminCronTaskSuccessMsg, taskName));
break;
case 401:
AlertDialogs.authorizationTokenRevokedDialog(ctx, ctx.getString(R.string.alertDialogTokenRevokedTitle),
ctx.getResources().getString(R.string.alertDialogTokenRevokedMessage),
ctx.getResources().getString(R.string.alertDialogTokenRevokedCopyNegativeButton),
ctx.getResources().getString(R.string.alertDialogTokenRevokedCopyPositiveButton));
break;
case 403:
Toasty.error(ctx, ctx.getString(R.string.authorizeError));
break;
case 404:
Toasty.warning(ctx, ctx.getString(R.string.apiNotFound));
break;
default:
Toasty.error(ctx, ctx.getString(R.string.genericError));
}
}
@Override
public void onFailure(@NonNull Call<JsonElement> call, @NonNull Throwable t) {
Toasty.error(ctx, ctx.getString(R.string.genericServerResponseError));
}
});
}
@Override
public int getItemCount() {
return tasksList.size();
}
}

View File

@ -1,6 +1,8 @@
package org.mian.gitnex.adapters;
import android.content.Context;
import android.content.Intent;
import android.text.Html;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@ -9,12 +11,15 @@ import android.widget.Filterable;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.core.content.res.ResourcesCompat;
import androidx.recyclerview.widget.RecyclerView;
import com.amulyakhare.textdrawable.TextDrawable;
import com.squareup.picasso.Picasso;
import org.gitnex.tea4j.models.UserInfo;
import org.mian.gitnex.R;
import org.mian.gitnex.activities.ProfileActivity;
import org.mian.gitnex.clients.PicassoService;
import org.mian.gitnex.helpers.AppUtil;
import org.mian.gitnex.helpers.RoundedTransformation;
import org.mian.gitnex.models.UserInfo;
import java.util.ArrayList;
import java.util.List;
@ -24,19 +29,22 @@ import java.util.List;
public class AdminGetUsersAdapter extends RecyclerView.Adapter<AdminGetUsersAdapter.UsersViewHolder> implements Filterable {
private List<UserInfo> usersList;
private Context mCtx;
private List<UserInfo> usersListFull;
private final List<UserInfo> usersList;
private final Context context;
private final List<UserInfo> usersListFull;
static class UsersViewHolder extends RecyclerView.ViewHolder {
class UsersViewHolder extends RecyclerView.ViewHolder {
private ImageView userAvatar;
private TextView userFullName;
private TextView userEmail;
private ImageView userRole;
private TextView userName;
private String userLoginId;
private final ImageView userAvatar;
private final TextView userFullName;
private final TextView userEmail;
private final ImageView userRole;
private final TextView userName;
private UsersViewHolder(View itemView) {
super(itemView);
userAvatar = itemView.findViewById(R.id.userAvatar);
@ -45,11 +53,22 @@ public class AdminGetUsersAdapter extends RecyclerView.Adapter<AdminGetUsersAdap
userEmail = itemView.findViewById(R.id.userEmail);
userRole = itemView.findViewById(R.id.userRole);
itemView.setOnClickListener(loginId -> {
Intent intent = new Intent(context, ProfileActivity.class);
intent.putExtra("username", userLoginId);
context.startActivity(intent);
});
userAvatar.setOnLongClickListener(loginId -> {
AppUtil.copyToClipboard(context, userLoginId, context.getString(R.string.copyLoginIdToClipBoard, userLoginId));
return true;
});
}
}
public AdminGetUsersAdapter(Context mCtx, List<UserInfo> usersListMain) {
this.mCtx = mCtx;
public AdminGetUsersAdapter(Context ctx, List<UserInfo> usersListMain) {
this.context = ctx;
this.usersList = usersListMain;
usersListFull = new ArrayList<>(usersList);
}
@ -57,7 +76,8 @@ public class AdminGetUsersAdapter extends RecyclerView.Adapter<AdminGetUsersAdap
@NonNull
@Override
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);
}
@ -65,40 +85,49 @@ public class AdminGetUsersAdapter extends RecyclerView.Adapter<AdminGetUsersAdap
public void onBindViewHolder(@NonNull AdminGetUsersAdapter.UsersViewHolder holder, int position) {
UserInfo currentItem = usersList.get(position);
int imgRadius = AppUtil.getPixelsFromDensity(context, 3);
holder.userLoginId = currentItem.getLogin();
if(!currentItem.getFullname().equals("")) {
holder.userFullName.setText(currentItem.getFullname());
holder.userName.setText(mCtx.getResources().getString(R.string.usernameWithAt, currentItem.getUsername()));
holder.userFullName.setText(Html.fromHtml(currentItem.getFullname()));
holder.userName.setText(context.getResources().getString(R.string.usernameWithAt, currentItem.getUsername()));
}
else {
holder.userFullName.setText(mCtx.getResources().getString(R.string.usernameWithAt, currentItem.getUsername()));
holder.userFullName.setText(context.getResources().getString(R.string.usernameWithAt, currentItem.getUsername()));
holder.userName.setVisibility(View.GONE);
}
if(!currentItem.getEmail().equals("")) {
holder.userEmail.setText(currentItem.getEmail());
}
else {
holder.userEmail.setVisibility(View.GONE);
}
if(currentItem.getIs_admin()) {
holder.userRole.setVisibility(View.VISIBLE);
TextDrawable drawable = TextDrawable.builder()
.beginConfig()
.textColor(mCtx.getResources().getColor(R.color.white))
.textColor(ResourcesCompat.getColor(context.getResources(), R.color.colorWhite, null))
.fontSize(44)
.width(180)
.height(60)
.endConfig()
.buildRoundRect(mCtx.getResources().getString(R.string.userRoleAdmin).toLowerCase(), mCtx.getResources().getColor(R.color.releasePre), 8);
.buildRoundRect(context.getResources().getString(R.string.userRoleAdmin).toLowerCase(), ResourcesCompat.getColor(context.getResources(), R.color.releasePre, null), 8);
holder.userRole.setImageDrawable(drawable);
}
else {
holder.userRole.setVisibility(View.GONE);
}
Picasso.get().load(currentItem.getAvatar()).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(holder.userAvatar);
PicassoService.getInstance(context).get().load(currentItem.getAvatar()).placeholder(R.drawable.loader_animated).transform(new RoundedTransformation(imgRadius, 0)).resize(120, 120).centerCrop().into(holder.userAvatar);
}
@Override
@ -111,14 +140,15 @@ public class AdminGetUsersAdapter extends RecyclerView.Adapter<AdminGetUsersAdap
return usersFilter;
}
private Filter usersFilter = new Filter() {
private final Filter usersFilter = new Filter() {
@Override
protected FilterResults performFiltering(CharSequence constraint) {
List<UserInfo> filteredList = new ArrayList<>();
if (constraint == null || constraint.length() == 0) {
filteredList.addAll(usersListFull);
} else {
}
else {
String filterPattern = constraint.toString().toLowerCase().trim();
for (UserInfo item : usersListFull) {
@ -136,6 +166,7 @@ public class AdminGetUsersAdapter extends RecyclerView.Adapter<AdminGetUsersAdap
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
usersList.clear();
usersList.addAll((List) results.values);
notifyDataSetChanged();

View File

@ -0,0 +1,139 @@
package org.mian.gitnex.adapters;
import android.content.Context;
import android.text.Html;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import org.gitnex.tea4j.models.Collaborators;
import org.mian.gitnex.R;
import org.mian.gitnex.clients.PicassoService;
import org.mian.gitnex.helpers.AppUtil;
import org.mian.gitnex.helpers.RoundedTransformation;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
/**
* Author M M Arif
*/
public class AssigneesListAdapter extends RecyclerView.Adapter<AssigneesListAdapter.AssigneesViewHolder> {
private final Context context;
private final List<Collaborators> assigneesList;
private List<String> assigneesStrings = new ArrayList<>();
private List<String> currentAssignees;
private final AssigneesListAdapterListener assigneesListener;
public interface AssigneesListAdapterListener {
void assigneesInterface(List<String> data);
}
public AssigneesListAdapter(Context ctx, List<Collaborators> dataMain, AssigneesListAdapterListener assigneesListener, List<String> currentAssignees) {
this.context = ctx;
this.assigneesList = dataMain;
this.assigneesListener = assigneesListener;
this.currentAssignees = currentAssignees;
}
static class AssigneesViewHolder extends RecyclerView.ViewHolder {
private final CheckBox assigneesSelection;
private final TextView assigneesName;
private final ImageView assigneesAvatar;
private AssigneesViewHolder(View itemView) {
super(itemView);
this.setIsRecyclable(false);
assigneesSelection = itemView.findViewById(R.id.assigneesSelection);
assigneesName = itemView.findViewById(R.id.assigneesName);
assigneesAvatar = itemView.findViewById(R.id.assigneesAvatar);
}
}
@NonNull
@Override
public AssigneesListAdapter.AssigneesViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.custom_assignees_list, parent, false);
return new AssigneesListAdapter.AssigneesViewHolder(v);
}
@Override
public void onBindViewHolder(@NonNull AssigneesListAdapter.AssigneesViewHolder holder, int position) {
Collaborators currentItem = assigneesList.get(position);
int imgRadius = AppUtil.getPixelsFromDensity(context, 3);
if(currentItem.getFull_name().equals("")) {
holder.assigneesName.setText(currentItem.getLogin());
}
else {
holder.assigneesName.setText(Html.fromHtml(currentItem.getFull_name()));
}
PicassoService
.getInstance(context).get().load(currentItem.getAvatar_url()).placeholder(R.drawable.loader_animated).transform(new RoundedTransformation(imgRadius, 0)).resize(180, 180).centerCrop().into(holder.assigneesAvatar);
for(int i = 0; i < assigneesList.size(); i++) {
if(assigneesStrings.contains(currentItem.getLogin())) {
holder.assigneesSelection.setChecked(true);
}
}
currentAssignees = new ArrayList<>(new LinkedHashSet<>(currentAssignees));
for(int i = 0; i < currentAssignees.size(); i++) {
if(currentAssignees.contains(currentItem.getLogin())) {
holder.assigneesSelection.setChecked(true);
assigneesStrings.add(currentAssignees.get(i));
}
}
assigneesListener.assigneesInterface(assigneesStrings);
holder.assigneesSelection.setOnCheckedChangeListener((buttonView, isChecked) -> {
if(isChecked) {
assigneesStrings.add(currentItem.getLogin());
}
else {
assigneesStrings.remove(currentItem.getLogin());
}
assigneesListener.assigneesInterface(assigneesStrings);
});
assigneesStrings = new ArrayList<>(new LinkedHashSet<>(assigneesStrings));
}
@Override
public int getItemCount() {
return assigneesList.size();
}
public void updateList(List<String> list) {
currentAssignees = list;
notifyDataSetChanged();
}
}

View File

@ -1,83 +0,0 @@
package org.mian.gitnex.adapters;
import android.content.Context;
import android.text.Html;
import android.text.method.LinkMovementMethod;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import org.mian.gitnex.R;
import org.mian.gitnex.models.Branches;
import org.mian.gitnex.util.TinyDB;
import java.util.List;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
/**
* Author M M Arif
*/
public class BranchesAdapter extends RecyclerView.Adapter<BranchesAdapter.BranchesViewHolder> {
private List<Branches> branchesList;
private Context mCtx;
static class BranchesViewHolder extends RecyclerView.ViewHolder {
private TextView branchNameTv;
private TextView branchCommitAuthor;
private TextView branchCommitHash;
private BranchesViewHolder(View itemView) {
super(itemView);
branchNameTv = itemView.findViewById(R.id.branchName);
branchCommitAuthor = itemView.findViewById(R.id.branchCommitAuthor);
branchCommitHash = itemView.findViewById(R.id.branchCommitHash);
}
}
public BranchesAdapter(Context mCtx, List<Branches> branchesMain) {
this.mCtx = mCtx;
this.branchesList = branchesMain;
}
@NonNull
@Override
public BranchesAdapter.BranchesViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.branches_list, parent, false);
return new BranchesAdapter.BranchesViewHolder(v);
}
@Override
public void onBindViewHolder(@NonNull BranchesAdapter.BranchesViewHolder holder, int position) {
final TinyDB tinyDb = new TinyDB(mCtx);
final String instanceUrl = tinyDb.getString("instanceUrl");
Branches currentItem = branchesList.get(position);
holder.branchNameTv.setText(currentItem.getName());
if(currentItem.getCommit().getAuthor().getName() != null || !currentItem.getCommit().getAuthor().getName().equals("")) {
holder.branchCommitAuthor.setText(mCtx.getResources().getString(R.string.commitAuthor, currentItem.getCommit().getAuthor().getName()));
}
else {
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
public int getItemCount() {
return branchesList.size();
}
}

View File

@ -1,291 +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.RelativeLayout;
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 RelativeLayout relativeLayoutFrame;
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);
relativeLayoutFrame = itemView.findViewById(R.id.relativeLayoutFrame);
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());
tinyDb.putString("issueType", "issue");
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());
tinyDb.putString("issueType", "issue");
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.getPull_request() != null) {
if (issuesModel.getPull_request().isMerged()) {
relativeLayoutFrame.setVisibility(View.GONE);
relativeLayoutFrame.setLayoutParams(new RecyclerView.LayoutParams(0, 0));
}
}*/
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);
}
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

@ -2,15 +2,19 @@ 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.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import com.squareup.picasso.Picasso;
import org.gitnex.tea4j.models.Collaborators;
import org.mian.gitnex.R;
import org.mian.gitnex.models.Collaborators;
import org.mian.gitnex.activities.ProfileActivity;
import org.mian.gitnex.clients.PicassoService;
import org.mian.gitnex.helpers.AppUtil;
import org.mian.gitnex.helpers.RoundedTransformation;
import java.util.List;
@ -20,22 +24,37 @@ import java.util.List;
public class CollaboratorsAdapter extends BaseAdapter {
private List<Collaborators> collaboratorsList;
private Context mCtx;
private final List<Collaborators> collaboratorsList;
private final Context context;
private class ViewHolder {
private ImageView collaboratorAvatar;
private TextView collaboratorName;
private String userLoginId;
private final ImageView collaboratorAvatar;
private final TextView collaboratorName;
ViewHolder(View v) {
collaboratorAvatar = v.findViewById(R.id.collaboratorAvatar);
collaboratorName = v.findViewById(R.id.collaboratorName);
collaboratorAvatar.setOnClickListener(loginId -> {
Intent intent = new Intent(context, ProfileActivity.class);
intent.putExtra("username", userLoginId);
context.startActivity(intent);
});
collaboratorAvatar.setOnLongClickListener(loginId -> {
AppUtil.copyToClipboard(context, userLoginId, context.getString(R.string.copyLoginIdToClipBoard, userLoginId));
return true;
});
}
}
public CollaboratorsAdapter(Context mCtx, List<Collaborators> collaboratorsListMain) {
this.mCtx = mCtx;
public CollaboratorsAdapter(Context ctx, List<Collaborators> collaboratorsListMain) {
this.context = ctx;
this.collaboratorsList = collaboratorsListMain;
}
@ -61,28 +80,35 @@ public class CollaboratorsAdapter extends BaseAdapter {
ViewHolder viewHolder = null;
if (finalView == null) {
finalView = LayoutInflater.from(mCtx).inflate(R.layout.collaborators_list, null);
finalView = LayoutInflater.from(context).inflate(R.layout.list_collaborators, null);
viewHolder = new ViewHolder(finalView);
finalView.setTag(viewHolder);
}
else {
viewHolder = (ViewHolder) finalView.getTag();
}
initData(viewHolder, position);
return finalView;
}
private void initData(ViewHolder viewHolder, int position) {
int imgRadius = AppUtil.getPixelsFromDensity(context, 3);
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(context).get().load(currentItem.getAvatar_url()).placeholder(R.drawable.loader_animated).transform(new RoundedTransformation(imgRadius, 0)).resize(180, 180).centerCrop().into(viewHolder.collaboratorAvatar);
viewHolder.userLoginId = currentItem.getLogin();
if(!currentItem.getFull_name().equals("")) {
viewHolder.collaboratorName.setText(currentItem.getFull_name());
viewHolder.collaboratorName.setText(Html.fromHtml(currentItem.getFull_name()));
}
else {
viewHolder.collaboratorName.setText(currentItem.getLogin());
}

View File

@ -0,0 +1,150 @@
package org.mian.gitnex.adapters;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.vdurmont.emoji.EmojiParser;
import org.gitnex.tea4j.models.Commits;
import org.mian.gitnex.R;
import org.mian.gitnex.helpers.ClickListener;
import org.mian.gitnex.helpers.TimeHelper;
import org.mian.gitnex.helpers.TinyDB;
import java.util.List;
import java.util.Locale;
/**
* Author M M Arif
*/
public class CommitsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private final Context context;
private final int TYPE_LOAD = 0;
private List<Commits> commitsList;
private CommitsAdapter.OnLoadMoreListener loadMoreListener;
private boolean isLoading = false;
private boolean isMoreDataAvailable = true;
public CommitsAdapter(Context ctx, List<Commits> commitsListMain) {
this.context = ctx;
this.commitsList = commitsListMain;
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(context);
if(viewType == TYPE_LOAD) {
return new CommitsHolder(inflater.inflate(R.layout.list_commits, parent, false));
}
else {
return new 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) {
((CommitsHolder) holder).bindData(commitsList.get(position));
}
}
@Override
public int getItemViewType(int position) {
if(commitsList.get(position).getSha() != null) {
return TYPE_LOAD;
}
else {
return 1;
}
}
@Override
public int getItemCount() {
return commitsList.size();
}
class CommitsHolder extends RecyclerView.ViewHolder {
TextView commitTitle;
TextView commitCommitter;
TextView commitDate;
Button commitHtmlUrl;
CommitsHolder(View itemView) {
super(itemView);
commitTitle = itemView.findViewById(R.id.commitTitleVw);
commitCommitter = itemView.findViewById(R.id.commitCommitterVw);
commitDate = itemView.findViewById(R.id.commitDateVw);
commitHtmlUrl = itemView.findViewById(R.id.commitHtmlUrlVw);
}
@SuppressLint("SetTextI18n")
void bindData(Commits commitsModel) {
final TinyDB tinyDb = TinyDB.getInstance(context);
Locale locale = context.getResources().getConfiguration().locale;
final String timeFormat = tinyDb.getString("dateFormat");
commitTitle.setText(EmojiParser.parseToUnicode(commitsModel.getCommit().getMessage()));
commitCommitter.setText(context.getString(R.string.commitCommittedBy, commitsModel.getCommit().getCommitter().getName()));
commitDate.setText(TimeHelper.formatTime(commitsModel.getCommit().getCommitter().getDate(), locale, timeFormat, context));
if(timeFormat.equals("pretty")) {
commitDate.setOnClickListener(new ClickListener(TimeHelper.customDateFormatForToastDateFormat(commitsModel.getCommit().getCommitter().getDate()), context));
}
commitHtmlUrl.setOnClickListener(v -> context.startActivity(new Intent(Intent.ACTION_VIEW).setData(Uri.parse(commitsModel.getHtml_url()))));
}
}
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(CommitsAdapter.OnLoadMoreListener loadMoreListener) {
this.loadMoreListener = loadMoreListener;
}
public void updateList(List<Commits> list) {
commitsList = list;
notifyDataSetChanged();
}
}

View File

@ -1,59 +0,0 @@
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

@ -0,0 +1,151 @@
package org.mian.gitnex.adapters;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.text.Spanned;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.core.content.res.ResourcesCompat;
import androidx.core.text.HtmlCompat;
import androidx.fragment.app.FragmentManager;
import androidx.recyclerview.widget.RecyclerView;
import org.mian.gitnex.R;
import org.mian.gitnex.activities.IssueDetailActivity;
import org.mian.gitnex.database.api.BaseApi;
import org.mian.gitnex.database.api.DraftsApi;
import org.mian.gitnex.database.models.DraftWithRepository;
import org.mian.gitnex.fragments.BottomSheetReplyFragment;
import org.mian.gitnex.helpers.Markdown;
import org.mian.gitnex.helpers.TinyDB;
import org.mian.gitnex.helpers.Toasty;
import java.util.List;
/**
* Author M M Arif
*/
public class DraftsAdapter extends RecyclerView.Adapter<DraftsAdapter.DraftsViewHolder> {
private List<DraftWithRepository> draftsList;
private final FragmentManager fragmentManager;
private final Context context;
class DraftsViewHolder extends RecyclerView.ViewHolder {
private DraftWithRepository draftWithRepository;
private final TextView draftText;
private final TextView repoInfo;
private final ImageView editCommentStatus;
private DraftsViewHolder(View itemView) {
super(itemView);
draftText = itemView.findViewById(R.id.draftText);
repoInfo = itemView.findViewById(R.id.repoInfo);
ImageView deleteDraft = itemView.findViewById(R.id.deleteDraft);
editCommentStatus = itemView.findViewById(R.id.editCommentStatus);
deleteDraft.setOnClickListener(itemDelete -> {
int getDraftId = draftWithRepository.getDraftId();
deleteDraft(getAdapterPosition());
DraftsApi draftsApi = BaseApi.getInstance(context, DraftsApi.class);
assert draftsApi != null;
draftsApi.deleteSingleDraft(getDraftId);
});
itemView.setOnClickListener(itemEdit -> {
Bundle bundle = new Bundle();
bundle.putString("commentBody", draftWithRepository.getDraftText());
bundle.putString("issueNumber", String.valueOf(draftWithRepository.getIssueId()));
bundle.putString("repositoryId", String.valueOf(draftWithRepository.getRepositoryId()));
bundle.putString("draftTitle", repoInfo.getText().toString());
bundle.putString("commentId", draftWithRepository.getCommentId());
bundle.putString("draftId", String.valueOf(draftWithRepository.getDraftId()));
if(!draftWithRepository.getCommentId().isEmpty()) {
bundle.putString("commentAction", "edit");
}
TinyDB tinyDb = TinyDB.getInstance(context);
tinyDb.putString("issueNumber", String.valueOf(draftWithRepository.getIssueId()));
tinyDb.putLong("repositoryId", draftWithRepository.getRepositoryId());
tinyDb.putString("issueType", draftWithRepository.getIssueType());
tinyDb.putString("repoFullName", draftWithRepository.getRepositoryOwner() + "/" + draftWithRepository.getRepositoryName());
BottomSheetReplyFragment bottomSheetReplyFragment = BottomSheetReplyFragment.newInstance(bundle);
bottomSheetReplyFragment.setOnInteractedListener(() -> context.startActivity(new Intent(context, IssueDetailActivity.class)));
bottomSheetReplyFragment.show(fragmentManager, "replyBottomSheet");
});
}
}
public DraftsAdapter(Context ctx, FragmentManager fragmentManager, List<DraftWithRepository> draftsListMain) {
this.context = ctx;
this.fragmentManager = fragmentManager;
this.draftsList = draftsListMain;
}
private void deleteDraft(int position) {
draftsList.remove(position);
notifyItemRemoved(position);
notifyItemRangeChanged(position, draftsList.size());
Toasty.success(context, context.getResources().getString(R.string.draftsSingleDeleteSuccess));
}
@NonNull
@Override
public DraftsAdapter.DraftsViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_drafts, parent, false);
return new DraftsViewHolder(v);
}
@SuppressLint("DefaultLocale")
@Override
public void onBindViewHolder(@NonNull DraftsAdapter.DraftsViewHolder holder, int position) {
DraftWithRepository currentItem = draftsList.get(position);
String issueNumber = "<font color='" + ResourcesCompat.getColor(context.getResources(), R.color.lightGray, null) + "'>" + context.getResources().getString(R.string.hash) + currentItem.getIssueId() + "</font>";
Spanned headTitle = HtmlCompat
.fromHtml(issueNumber + " " + currentItem.getRepositoryOwner() + " / " + currentItem.getRepositoryName(), HtmlCompat.FROM_HTML_MODE_LEGACY);
holder.repoInfo.setText(headTitle);
holder.draftWithRepository = currentItem;
Markdown.render(context, currentItem.getDraftText(), holder.draftText);
if(!currentItem.getCommentId().equalsIgnoreCase("new")) {
holder.editCommentStatus.setVisibility(View.VISIBLE);
}
else {
holder.editCommentStatus.setVisibility(View.GONE);
}
}
@Override
public int getItemCount() {
return draftsList.size();
}
public void updateList(List<DraftWithRepository> list) {
draftsList = list;
notifyDataSetChanged();
}
}

View File

@ -0,0 +1,226 @@
package org.mian.gitnex.adapters;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.core.content.res.ResourcesCompat;
import androidx.core.text.HtmlCompat;
import androidx.recyclerview.widget.RecyclerView;
import org.gitnex.tea4j.models.Issues;
import org.mian.gitnex.R;
import org.mian.gitnex.activities.IssueDetailActivity;
import org.mian.gitnex.activities.ProfileActivity;
import org.mian.gitnex.clients.PicassoService;
import org.mian.gitnex.database.api.BaseApi;
import org.mian.gitnex.database.api.RepositoriesApi;
import org.mian.gitnex.database.models.Repository;
import org.mian.gitnex.helpers.AppUtil;
import org.mian.gitnex.helpers.ClickListener;
import org.mian.gitnex.helpers.RoundedTransformation;
import org.mian.gitnex.helpers.TimeHelper;
import org.mian.gitnex.helpers.TinyDB;
import org.ocpsoft.prettytime.PrettyTime;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.Locale;
/**
* Author M M Arif
*/
public class ExploreIssuesAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private final Context context;
private final int TYPE_LOAD = 0;
private List<Issues> searchedList;
private OnLoadMoreListener loadMoreListener;
private boolean isLoading = false, isMoreDataAvailable = true;
private final TinyDB tinyDb;
public ExploreIssuesAdapter(List<Issues> dataList, Context ctx) {
this.context = ctx;
this.searchedList = dataList;
this.tinyDb = TinyDB.getInstance(context);
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(context);
if(viewType == TYPE_LOAD) {
return new ExploreIssuesAdapter.IssuesHolder(inflater.inflate(R.layout.list_issues, parent, false));
}
else {
return new ExploreIssuesAdapter.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) {
((ExploreIssuesAdapter.IssuesHolder) holder).bindData(searchedList.get(position));
}
}
@Override
public int getItemViewType(int position) {
if(searchedList.get(position).getTitle() != null) {
return TYPE_LOAD;
}
else {
return 1;
}
}
@Override
public int getItemCount() {
return searchedList.size();
}
class IssuesHolder extends RecyclerView.ViewHolder {
private Issues issue;
private final ImageView issueAssigneeAvatar;
private final TextView issueTitle;
private final TextView issueCreatedTime;
private final TextView issueCommentsCount;
IssuesHolder(View itemView) {
super(itemView);
issueAssigneeAvatar = itemView.findViewById(R.id.assigneeAvatar);
issueTitle = itemView.findViewById(R.id.issueTitle);
issueCommentsCount = itemView.findViewById(R.id.issueCommentsCount);
issueCreatedTime = itemView.findViewById(R.id.issueCreatedTime);
itemView.setOnClickListener(v -> {
Intent intent = new Intent(context, IssueDetailActivity.class);
intent.putExtra("issueNumber", issue.getNumber());
intent.putExtra("openedFromLink", "true");
tinyDb.putString("issueNumber", String.valueOf(issue.getNumber()));
tinyDb.putString("issueType", "Issue");
tinyDb.putString("repoFullName", issue.getRepository().getFull_name());
String[] parts = issue.getRepository().getFull_name().split("/");
final String repoOwner = parts[0];
final String repoName = parts[1];
int currentActiveAccountId = tinyDb.getInt("currentActiveAccountId");
RepositoriesApi repositoryData = BaseApi.getInstance(context, RepositoriesApi.class);
assert repositoryData != null;
Integer count = repositoryData.checkRepository(currentActiveAccountId, repoOwner, repoName);
if(count == 0) {
long id = repositoryData.insertRepository(currentActiveAccountId, repoOwner, repoName);
tinyDb.putLong("repositoryId", id);
}
else {
Repository data = repositoryData.getRepository(currentActiveAccountId, repoOwner, repoName);
tinyDb.putLong("repositoryId", data.getRepositoryId());
}
context.startActivity(intent);
});
issueAssigneeAvatar.setOnClickListener(v -> {
Intent intent = new Intent(context, ProfileActivity.class);
intent.putExtra("username", issue.getUser().getLogin());
context.startActivity(intent);
});
issueAssigneeAvatar.setOnLongClickListener(loginId -> {
AppUtil.copyToClipboard(context, issue.getUser().getLogin(), context.getString(R.string.copyLoginIdToClipBoard, issue.getUser().getLogin()));
return true;
});
}
@SuppressLint("SetTextI18n")
void bindData(Issues issue) {
this.issue = issue;
int imgRadius = AppUtil.getPixelsFromDensity(context, 3);
Locale locale = context.getResources().getConfiguration().locale;
String timeFormat = tinyDb.getString("dateFormat");
PicassoService.getInstance(context).get()
.load(issue.getUser().getAvatar_url())
.placeholder(R.drawable.loader_animated)
.transform(new RoundedTransformation(imgRadius, 0))
.resize(120, 120)
.centerCrop()
.into(issueAssigneeAvatar);
String issueNumber_ = "<font color='" + ResourcesCompat.getColor(context.getResources(), R.color.lightGray, null) + "'>" + issue.getRepository().getFull_name() + context.getResources().getString(R.string.hash) + issue.getNumber() + "</font>";
issueTitle.setText(HtmlCompat.fromHtml(issueNumber_ + " " + issue.getTitle(), HtmlCompat.FROM_HTML_MODE_LEGACY));
issueCommentsCount.setText(String.valueOf(issue.getComments()));
switch(timeFormat) {
case "pretty": {
PrettyTime prettyTime = new PrettyTime(locale);
String createdTime = prettyTime.format(issue.getCreated_at());
issueCreatedTime.setText(createdTime);
issueCreatedTime.setOnClickListener(new ClickListener(TimeHelper.customDateFormatForToastDateFormat(issue.getCreated_at()), context));
break;
}
case "normal": {
DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd '" + context.getResources().getString(R.string.timeAtText) + "' HH:mm", locale);
String createdTime = formatter.format(issue.getCreated_at());
issueCreatedTime.setText(createdTime);
break;
}
case "normal1": {
DateFormat formatter = new SimpleDateFormat("dd-MM-yyyy '" + context.getResources().getString(R.string.timeAtText) + "' HH:mm", locale);
String createdTime = formatter.format(issue.getCreated_at());
issueCreatedTime.setText(createdTime);
break;
}
}
}
}
static class LoadHolder extends RecyclerView.ViewHolder {
LoadHolder(View itemView) {
super(itemView);
}
}
public void setMoreDataAvailable(boolean moreDataAvailable) {
isMoreDataAvailable = moreDataAvailable;
}
@SuppressLint("NotifyDataSetChanged")
public void notifyDataChanged() {
notifyDataSetChanged();
isLoading = false;
}
public interface OnLoadMoreListener {
void onLoadMore();
}
public void setLoadMoreListener(OnLoadMoreListener loadMoreListener) {
this.loadMoreListener = loadMoreListener;
}
public void updateList(List<Issues> list) {
searchedList = list;
notifyDataChanged();
}
}

View File

@ -0,0 +1,154 @@
package org.mian.gitnex.adapters;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import org.gitnex.tea4j.models.Organization;
import org.mian.gitnex.R;
import org.mian.gitnex.activities.OrganizationDetailActivity;
import org.mian.gitnex.clients.PicassoService;
import org.mian.gitnex.helpers.AppUtil;
import org.mian.gitnex.helpers.RoundedTransformation;
import org.mian.gitnex.helpers.TinyDB;
import java.util.List;
/**
* Author M M Arif
*/
public class ExplorePublicOrganizationsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private final Context context;
private final int TYPE_LOAD = 0;
private List<Organization> organizationsList;
private OnLoadMoreListener loadMoreListener;
private boolean isLoading = false, isMoreDataAvailable = true;
public ExplorePublicOrganizationsAdapter(Context ctx, List<Organization> organizationsListMain) {
this.context = ctx;
this.organizationsList = organizationsListMain;
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(context);
if(viewType == TYPE_LOAD) {
return new ExplorePublicOrganizationsAdapter.OrganizationsHolder(inflater.inflate(R.layout.list_organizations, parent, false));
}
else {
return new ExplorePublicOrganizationsAdapter.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) {
((ExplorePublicOrganizationsAdapter.OrganizationsHolder) holder).bindData(organizationsList.get(position));
}
}
@Override
public int getItemViewType(int position) {
if(organizationsList.get(position).getFull_name() != null) {
return TYPE_LOAD;
}
else {
return 1;
}
}
@Override
public int getItemCount() {
return organizationsList.size();
}
class OrganizationsHolder extends RecyclerView.ViewHolder {
private Organization organization;
private final ImageView image;
private final TextView orgName;
private final TextView orgDescription;
OrganizationsHolder(View itemView) {
super(itemView);
image = itemView.findViewById(R.id.imageAvatar);
orgName = itemView.findViewById(R.id.orgName);
orgDescription = itemView.findViewById(R.id.orgDescription);
itemView.setOnClickListener(v -> {
Context context = v.getContext();
Intent intent = new Intent(context, OrganizationDetailActivity.class);
intent.putExtra("orgName", organization.getUsername());
TinyDB tinyDb = TinyDB.getInstance(context);
tinyDb.putString("orgName", organization.getUsername());
tinyDb.putString("organizationId", String.valueOf(organization.getId()));
tinyDb.putBoolean("organizationAction", true);
context.startActivity(intent);
});
}
@SuppressLint("SetTextI18n")
void bindData(Organization organization) {
this.organization = organization;
int imgRadius = AppUtil.getPixelsFromDensity(context, 3);
orgName.setText(organization.getUsername());
PicassoService.getInstance(context).get()
.load(organization.getAvatar_url())
.placeholder(R.drawable.loader_animated)
.transform(new RoundedTransformation(imgRadius, 0))
.resize(120, 120)
.centerCrop()
.into(image);
if(!organization.getDescription().equals("")) {
orgDescription.setVisibility(View.VISIBLE);
orgDescription.setText(organization.getDescription());
}
else {
orgDescription.setVisibility(View.GONE);
}
}
}
static class LoadHolder extends RecyclerView.ViewHolder {
LoadHolder(View itemView) {
super(itemView);
}
}
public void setMoreDataAvailable(boolean moreDataAvailable) {
isMoreDataAvailable = moreDataAvailable;
}
@SuppressLint("NotifyDataSetChanged")
public void notifyDataChanged() {
notifyDataSetChanged();
isLoading = false;
}
public interface OnLoadMoreListener {
void onLoadMore();
}
public void setLoadMoreListener(OnLoadMoreListener loadMoreListener) {
this.loadMoreListener = loadMoreListener;
}
public void updateList(List<Organization> list) {
organizationsList = list;
notifyDataChanged();
}
}

View File

@ -1,217 +1,301 @@
package org.mian.gitnex.adapters;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.graphics.Typeface;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.view.ContextThemeWrapper;
import androidx.appcompat.widget.PopupMenu;
import androidx.recyclerview.widget.RecyclerView;
import com.amulyakhare.textdrawable.TextDrawable;
import com.amulyakhare.textdrawable.util.ColorGenerator;
import com.squareup.picasso.Picasso;
import org.gitnex.tea4j.models.UserRepositories;
import org.gitnex.tea4j.models.WatchInfo;
import org.mian.gitnex.R;
import org.mian.gitnex.activities.OpenRepoInBrowserActivity;
import org.mian.gitnex.activities.RepoDetailActivity;
import org.mian.gitnex.activities.RepoStargazersActivity;
import org.mian.gitnex.activities.RepoWatchersActivity;
import org.mian.gitnex.clients.PicassoService;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.database.api.BaseApi;
import org.mian.gitnex.database.api.RepositoriesApi;
import org.mian.gitnex.database.models.Repository;
import org.mian.gitnex.helpers.AppUtil;
import org.mian.gitnex.helpers.ClickListener;
import org.mian.gitnex.helpers.RoundedTransformation;
import org.mian.gitnex.models.UserRepositories;
import org.mian.gitnex.util.TinyDB;
import java.lang.reflect.Field;
import org.mian.gitnex.helpers.TimeHelper;
import org.mian.gitnex.helpers.TinyDB;
import org.mian.gitnex.helpers.Toasty;
import org.ocpsoft.prettytime.PrettyTime;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.Objects;
import java.util.Locale;
import retrofit2.Call;
import retrofit2.Callback;
/**
* Author M M Arif
*/
public class ExploreRepositoriesAdapter extends RecyclerView.Adapter<ExploreRepositoriesAdapter.ReposSearchViewHolder> {
public class ExploreRepositoriesAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private final Context context;
private final int TYPE_LOAD = 0;
private List<UserRepositories> reposList;
private OnLoadMoreListener loadMoreListener;
private boolean isLoading = false, isMoreDataAvailable = true;
private final TinyDB tinyDb;
private List<UserRepositories> searchedReposList;
private Context mCtx;
public ExploreRepositoriesAdapter(List<UserRepositories> dataList, Context ctx) {
this.context = ctx;
this.reposList = dataList;
this.tinyDb = TinyDB.getInstance(context);
}
public ExploreRepositoriesAdapter(List<UserRepositories> dataList, Context mCtx) {
this.mCtx = mCtx;
this.searchedReposList = dataList;
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(context);
if(viewType == TYPE_LOAD) {
return new ExploreRepositoriesAdapter.RepositoriesHolder(inflater.inflate(R.layout.list_repositories, parent, false));
}
else {
return new ExploreRepositoriesAdapter.LoadHolder(inflater.inflate(R.layout.row_load, parent, false));
}
}
static class ReposSearchViewHolder extends RecyclerView.ViewHolder {
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
if(position >= getItemCount() - 1 && isMoreDataAvailable && !isLoading && loadMoreListener != null) {
isLoading = true;
loadMoreListener.onLoadMore();
}
private ImageView image;
private TextView mTextView1;
private TextView mTextView2;
private TextView fullName;
private ImageView repoPrivatePublic;
private TextView repoStars;
private TextView repoForks;
private TextView repoOpenIssuesCount;
if(getItemViewType(position) == TYPE_LOAD) {
((ExploreRepositoriesAdapter.RepositoriesHolder) holder).bindData(reposList.get(position));
}
}
private ReposSearchViewHolder(View itemView) {
super(itemView);
@Override
public int getItemViewType(int position) {
if(reposList.get(position).getFullName() != null) {
return TYPE_LOAD;
}
else {
return 1;
}
}
mTextView1 = itemView.findViewById(R.id.repoName);
mTextView2 = itemView.findViewById(R.id.repoDescription);
image = itemView.findViewById(R.id.imageAvatar);
fullName = itemView.findViewById(R.id.repoFullName);
repoPrivatePublic = itemView.findViewById(R.id.imageRepoType);
repoStars = itemView.findViewById(R.id.repoStars);
repoForks = itemView.findViewById(R.id.repoForks);
repoOpenIssuesCount = itemView.findViewById(R.id.repoOpenIssuesCount);
ImageView reposDropdownMenu = itemView.findViewById(R.id.reposDropdownMenu);
@Override
public int getItemCount() {
return reposList.size();
}
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
class RepositoriesHolder extends RecyclerView.ViewHolder {
private UserRepositories userRepositories;
Context context = v.getContext();
TextView repoFullName = v.findViewById(R.id.repoFullName);
private final ImageView image;
private final TextView repoName;
private final TextView orgName;
private final TextView repoDescription;
private CheckBox isRepoAdmin;
private final TextView repoStars;
private final TextView repoLastUpdated;
private final View spacerView;
Intent intent = new Intent(context, RepoDetailActivity.class);
intent.putExtra("repoFullName", repoFullName.getText().toString());
RepositoriesHolder(View itemView) {
super(itemView);
repoName = itemView.findViewById(R.id.repoName);
orgName = itemView.findViewById(R.id.orgName);
repoDescription = itemView.findViewById(R.id.repoDescription);
isRepoAdmin = itemView.findViewById(R.id.repoIsAdmin);
image = itemView.findViewById(R.id.imageAvatar);
repoStars = itemView.findViewById(R.id.repoStars);
repoLastUpdated = itemView.findViewById(R.id.repoLastUpdated);
spacerView = itemView.findViewById(R.id.spacerView);
TinyDB tinyDb = new TinyDB(context);
tinyDb.putString("repoFullName", repoFullName.getText().toString());
tinyDb.putBoolean("resumeIssues", true);
context.startActivity(intent);
itemView.setOnClickListener(v -> {
}
});
Context context = v.getContext();
Intent intent = new Intent(context, RepoDetailActivity.class);
intent.putExtra("repoFullName", userRepositories.getFullName());
reposDropdownMenu.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
tinyDb.putString("repoFullName", userRepositories.getFullName());
tinyDb.putBoolean("resumeIssues", true);
tinyDb.putBoolean("isRepoAdmin", isRepoAdmin.isChecked());
tinyDb.putString("repoBranch", userRepositories.getDefault_branch());
final Context context = v.getContext();
//Context context_ = new ContextThemeWrapper(context, R.style.popupMenuStyle);
if(userRepositories.getPrivateFlag()) {
tinyDb.putString("repoType", context.getResources().getString(R.string.strPrivate));
}
else {
tinyDb.putString("repoType", context.getResources().getString(R.string.strPublic));
}
PopupMenu popupMenu = new PopupMenu(context, v);
popupMenu.inflate(R.menu.repo_dotted_list_menu);
String[] parts = userRepositories.getFullName().split("/");
final String repoOwner = parts[0];
final String repoName = parts[1];
Object menuHelper;
Class[] argTypes;
try {
int currentActiveAccountId = tinyDb.getInt("currentActiveAccountId");
RepositoriesApi repositoryData = BaseApi.getInstance(context, RepositoriesApi.class);
Field fMenuHelper = PopupMenu.class.getDeclaredField("mPopup");
fMenuHelper.setAccessible(true);
menuHelper = fMenuHelper.get(popupMenu);
argTypes = new Class[] { boolean.class };
Objects.requireNonNull(menuHelper).getClass().getDeclaredMethod("setForceShowIcon",
argTypes).invoke(menuHelper, true);
//RepositoriesRepository.deleteRepositoriesByAccount(currentActiveAccountId);
assert repositoryData != null;
Integer count = repositoryData.checkRepository(currentActiveAccountId, repoOwner, repoName);
} catch (Exception e) {
if(count == 0) {
popupMenu.show();
return;
long id = repositoryData.insertRepository(currentActiveAccountId, repoOwner, repoName);
tinyDb.putLong("repositoryId", id);
}
else {
}
Repository data = repositoryData.getRepository(currentActiveAccountId, repoOwner, repoName);
tinyDb.putLong("repositoryId", data.getRepositoryId());
}
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case R.id.repoStargazers:
//store if user is watching this repo
{
Intent intent = new Intent(context, RepoStargazersActivity.class);
intent.putExtra("repoFullNameForStars", fullName.getText());
context.startActivity(intent);
break;
final String token = "token " + tinyDb.getString(tinyDb.getString("loginUid") + "-token");
case R.id.repoWatchers:
WatchInfo watch = new WatchInfo();
Call<WatchInfo> call;
call = RetrofitClient.getApiInterface(context).checkRepoWatchStatus(token, repoOwner, repoName);
Intent intentW = new Intent(context, RepoWatchersActivity.class);
intentW.putExtra("repoFullNameForWatchers", fullName.getText());
context.startActivity(intentW);
break;
call.enqueue(new Callback<WatchInfo>() {
@Override
public void onResponse(@NonNull Call<WatchInfo> call, @NonNull retrofit2.Response<WatchInfo> response) {
case R.id.repoOpenInBrowser:
if(response.isSuccessful()) {
assert response.body() != null;
tinyDb.putBoolean("repoWatch", response.body().getSubscribed());
}
else {
tinyDb.putBoolean("repoWatch", false);
if(response.code() != 404) {
Toasty.error(context, context.getString(R.string.genericApiStatusError));
}
}
}
Intent intentOpenInBrowser = new Intent(context, OpenRepoInBrowserActivity.class);
intentOpenInBrowser.putExtra("repoFullNameBrowser", fullName.getText());
context.startActivity(intentOpenInBrowser);
break;
@Override
public void onFailure(@NonNull Call<WatchInfo> call, @NonNull Throwable t) {
tinyDb.putBoolean("repoWatch", false);
Toasty.error(context, context.getString(R.string.genericApiStatusError));
}
});
}
context.startActivity(intent);
}
return false;
}
});
});
}
popupMenu.show();
@SuppressLint("SetTextI18n")
void bindData(UserRepositories userRepositories) {
this.userRepositories = userRepositories;
}
});
int imgRadius = AppUtil.getPixelsFromDensity(context, 3);
Locale locale = context.getResources().getConfiguration().locale;
String timeFormat = tinyDb.getString("dateFormat");
}
orgName.setText(userRepositories.getFullName().split("/")[0]);
repoName.setText(userRepositories.getFullName().split("/")[1]);
repoStars.setText(userRepositories.getStars_count());
}
ColorGenerator generator = ColorGenerator.MATERIAL;
int color = generator.getColor(userRepositories.getName());
String firstCharacter = String.valueOf(userRepositories.getFullName().charAt(0));
@NonNull
@Override
public ExploreRepositoriesAdapter.ReposSearchViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.repos_list, parent, false);
return new ExploreRepositoriesAdapter.ReposSearchViewHolder(v);
}
TextDrawable drawable = TextDrawable.builder().beginConfig().useFont(Typeface.DEFAULT).fontSize(18).toUpperCase().width(28).height(28).endConfig().buildRoundRect(firstCharacter, color, 3);
@Override
public void onBindViewHolder(@NonNull final ExploreRepositoriesAdapter.ReposSearchViewHolder holder, int position) {
if(userRepositories.getAvatar_url() != null) {
if(!userRepositories.getAvatar_url().equals("")) {
PicassoService.getInstance(context).get().load(userRepositories.getAvatar_url()).placeholder(R.drawable.loader_animated).transform(new RoundedTransformation(imgRadius, 0)).resize(120, 120).centerCrop().into(image);
}
else {
image.setImageDrawable(drawable);
}
}
else {
image.setImageDrawable(drawable);
}
final UserRepositories currentItem = searchedReposList.get(position);
if(userRepositories.getUpdated_at() != null) {
switch(timeFormat) {
case "pretty": {
PrettyTime prettyTime = new PrettyTime(locale);
String createdTime = prettyTime.format(userRepositories.getUpdated_at());
repoLastUpdated.setText(context.getString(R.string.lastUpdatedAt, createdTime));
repoLastUpdated.setOnClickListener(new ClickListener(TimeHelper.customDateFormatForToastDateFormat(userRepositories.getUpdated_at()), context));
break;
}
case "normal": {
DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd '" + context.getResources().getString(R.string.timeAtText) + "' HH:mm", locale);
String createdTime = formatter.format(userRepositories.getUpdated_at());
repoLastUpdated.setText(context.getString(R.string.lastUpdatedAt, createdTime));
break;
}
case "normal1": {
DateFormat formatter = new SimpleDateFormat("dd-MM-yyyy '" + context.getResources().getString(R.string.timeAtText) + "' HH:mm", locale);
String createdTime = formatter.format(userRepositories.getUpdated_at());
repoLastUpdated.setText(context.getString(R.string.lastUpdatedAt, createdTime));
break;
}
}
}
else {
repoLastUpdated.setVisibility(View.GONE);
}
holder.mTextView2.setVisibility(View.GONE);
if(!userRepositories.getDescription().equals("")) {
repoDescription.setVisibility(View.VISIBLE);
repoDescription.setText(userRepositories.getDescription());
spacerView.setVisibility(View.GONE);
}
else {
repoDescription.setVisibility(View.GONE);
spacerView.setVisibility(View.VISIBLE);
}
ColorGenerator generator = ColorGenerator.MATERIAL;
int color = generator.getColor(currentItem.getName());
String firstCharacter = String.valueOf(currentItem.getName().charAt(0));
if(isRepoAdmin == null) {
isRepoAdmin = new CheckBox(context);
}
isRepoAdmin.setChecked(userRepositories.getPermissions().isAdmin());
}
}
TextDrawable drawable = TextDrawable.builder()
.beginConfig()
.useFont(Typeface.DEFAULT)
.fontSize(18)
.toUpperCase()
.width(28)
.height(28)
.endConfig()
.buildRoundRect(firstCharacter, color, 3);
static class LoadHolder extends RecyclerView.ViewHolder {
LoadHolder(View itemView) {
super(itemView);
}
}
if (currentItem.getAvatar_url() != null) {
if (!currentItem.getAvatar_url().equals("")) {
Picasso.get().load(currentItem.getAvatar_url()).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(holder.image);
} else {
holder.image.setImageDrawable(drawable);
}
}
else {
holder.image.setImageDrawable(drawable);
}
public void setMoreDataAvailable(boolean moreDataAvailable) {
isMoreDataAvailable = moreDataAvailable;
}
holder.mTextView1.setText(currentItem.getName());
if (!currentItem.getDescription().equals("")) {
holder.mTextView2.setVisibility(View.VISIBLE);
holder.mTextView2.setText(currentItem.getDescription());
}
holder.fullName.setText(currentItem.getFullname());
if(currentItem.getPrivateFlag()) {
holder.repoPrivatePublic.setImageResource(R.drawable.ic_lock_bold);
}
else {
holder.repoPrivatePublic.setImageResource(R.drawable.ic_public);
}
holder.repoStars.setText(currentItem.getStars_count());
holder.repoForks.setText(currentItem.getForks_count());
holder.repoOpenIssuesCount.setText(currentItem.getOpen_issues_count());
@SuppressLint("NotifyDataSetChanged")
public void notifyDataChanged() {
notifyDataSetChanged();
isLoading = false;
}
}
public interface OnLoadMoreListener {
void onLoadMore();
}
@Override
public int getItemCount() {
return searchedReposList.size();
}
public void setLoadMoreListener(OnLoadMoreListener loadMoreListener) {
this.loadMoreListener = loadMoreListener;
}
public void updateList(List<UserRepositories> list) {
reposList = list;
notifyDataChanged();
}
}

View File

@ -0,0 +1,154 @@
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.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import org.gitnex.tea4j.models.UserInfo;
import org.mian.gitnex.R;
import org.mian.gitnex.activities.ProfileActivity;
import org.mian.gitnex.clients.PicassoService;
import org.mian.gitnex.helpers.AppUtil;
import org.mian.gitnex.helpers.RoundedTransformation;
import java.util.List;
/**
* Author M M Arif
*/
public class ExploreUsersAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private final Context context;
private final int TYPE_LOAD = 0;
private List<UserInfo> usersList;
private OnLoadMoreListener loadMoreListener;
private boolean isLoading = false, isMoreDataAvailable = true;
public ExploreUsersAdapter(Context ctx, List<UserInfo> usersListMain) {
this.context = ctx;
this.usersList = usersListMain;
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(context);
if(viewType == TYPE_LOAD) {
return new ExploreUsersAdapter.UsersHolder(inflater.inflate(R.layout.list_explore_users, parent, false));
}
else {
return new ExploreUsersAdapter.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) {
((ExploreUsersAdapter.UsersHolder) holder).bindData(usersList.get(position));
}
}
@Override
public int getItemViewType(int position) {
if(usersList.get(position).getUsername() != null) {
return TYPE_LOAD;
}
else {
return 1;
}
}
@Override
public int getItemCount() {
return usersList.size();
}
class UsersHolder extends RecyclerView.ViewHolder {
private UserInfo userInfo;
private final ImageView userAvatar;
private final TextView userFullName;
private final TextView userName;
UsersHolder(View itemView) {
super(itemView);
userAvatar = itemView.findViewById(R.id.userAvatar);
userFullName = itemView.findViewById(R.id.userFullName);
userName = itemView.findViewById(R.id.userName);
itemView.setOnClickListener(loginId -> {
Intent intent = new Intent(context, ProfileActivity.class);
intent.putExtra("username", userInfo.getLogin());
context.startActivity(intent);
});
itemView.setOnLongClickListener(loginId -> {
AppUtil.copyToClipboard(context, userInfo.getLogin(), context.getString(R.string.copyLoginIdToClipBoard, userInfo.getLogin()));
return true;
});
}
@SuppressLint("SetTextI18n")
void bindData(UserInfo userInfo) {
this.userInfo = userInfo;
int imgRadius = AppUtil.getPixelsFromDensity(context, 3);
userName.setText(userInfo.getUsername());
PicassoService.getInstance(context).get()
.load(userInfo.getAvatar())
.placeholder(R.drawable.loader_animated)
.transform(new RoundedTransformation(imgRadius, 0))
.resize(120, 120)
.centerCrop()
.into(userAvatar);
if(!userInfo.getFullname().equals("")) {
userFullName.setText(Html.fromHtml(userInfo.getFullname()));
userName.setText(context.getResources().getString(R.string.usernameWithAt, userInfo.getUsername()));
}
else {
userFullName.setText(userInfo.getUsername());
userName.setVisibility(View.GONE);
}
}
}
static class LoadHolder extends RecyclerView.ViewHolder {
LoadHolder(View itemView) {
super(itemView);
}
}
public void setMoreDataAvailable(boolean moreDataAvailable) {
isMoreDataAvailable = moreDataAvailable;
}
@SuppressLint("NotifyDataSetChanged")
public void notifyDataChanged() {
notifyDataSetChanged();
isLoading = false;
}
public interface OnLoadMoreListener {
void onLoadMore();
}
public void setLoadMoreListener(OnLoadMoreListener loadMoreListener) {
this.loadMoreListener = loadMoreListener;
}
public void updateList(List<UserInfo> list) {
usersList = list;
notifyDataChanged();
}
}

View File

@ -7,12 +7,14 @@ 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.appcompat.content.res.AppCompatResources;
import androidx.recyclerview.widget.RecyclerView;
import org.apache.commons.io.FileUtils;
import org.gitnex.tea4j.models.Files;
import org.mian.gitnex.R;
import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.models.Files;
import java.util.ArrayList;
import java.util.List;
@ -22,52 +24,39 @@ import java.util.List;
public class FilesAdapter extends RecyclerView.Adapter<FilesAdapter.FilesViewHolder> implements Filterable {
private List<Files> filesList;
private Context mCtx;
private List<Files> filesListFull;
private final List<Files> originalFiles = new ArrayList<>();
private final List<Files> alteredFiles = new ArrayList<>();
private FilesAdapterListener filesListener;
private final Context context;
private final FilesAdapterListener filesListener;
public interface FilesAdapterListener {
void onClickDir(String str);
void onClickFile(String str);
void onClickFile(Files file);
}
class FilesViewHolder extends RecyclerView.ViewHolder {
class FilesViewHolder extends RecyclerView.ViewHolder {
private ImageView fileTypeImage;
private TextView fileName;
private TextView fileType;
private Files file;
private final ImageView fileTypeIs;
private final TextView fileName;
private final TextView fileInfo;
private FilesViewHolder(View itemView) {
super(itemView);
LinearLayout fileFrame = itemView.findViewById(R.id.fileFrame);
fileName = itemView.findViewById(R.id.fileName);
fileTypeImage = itemView.findViewById(R.id.fileImage);
fileType = itemView.findViewById(R.id.fileType);
fileTypeIs = itemView.findViewById(R.id.fileTypeIs);
fileInfo = itemView.findViewById(R.id.fileInfo);
fileFrame.setOnClickListener(v -> filesListener.onClickFile(file));
//ImageView filesDropdownMenu = itemView.findViewById(R.id.filesDropdownMenu);
fileName.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Context context = v.getContext();
if(fileType.getText().toString().equals("file")) {
filesListener.onClickFile(fileName.getText().toString());
}
else if(fileType.getText().toString().equals("dir")) {
filesListener.onClickDir(fileName.getText().toString());
}
else {
Toasty.info(context, context.getString(R.string.filesGenericError));
}
}
});
/*filesDropdownMenu.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
@ -134,43 +123,71 @@ public class FilesAdapter extends RecyclerView.Adapter<FilesAdapter.FilesViewHol
}
}
public FilesAdapter(Context mCtx, List<Files> filesListMain, FilesAdapterListener filesListener) {
this.mCtx = mCtx;
this.filesList = filesListMain;
filesListFull = new ArrayList<>(filesList);
public FilesAdapter(Context ctx, FilesAdapterListener filesListener) {
this.context = ctx;
this.filesListener = filesListener;
}
public List<Files> getOriginalFiles() {
return originalFiles;
}
public void notifyOriginalDataSetChanged() {
alteredFiles.clear();
alteredFiles.addAll(originalFiles);
notifyDataSetChanged();
}
@NonNull
@Override
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);
}
@Override
public void onBindViewHolder(@NonNull FilesAdapter.FilesViewHolder holder, int position) {
Files currentItem = filesList.get(position);
Files currentItem = alteredFiles.get(position);
holder.fileType.setText(currentItem.getType());
holder.file = currentItem;
holder.fileName.setText(currentItem.getName());
if(currentItem.getType().equals("file")) {
holder.fileTypeImage.setImageDrawable(mCtx.getResources().getDrawable(R.drawable.ic_file_new));
}
else if(currentItem.getType().equals("dir")) {
holder.fileTypeImage.setImageDrawable(mCtx.getResources().getDrawable(R.drawable.ic_folder_24));
}
else {
holder.fileTypeImage.setImageDrawable(mCtx.getResources().getDrawable(R.drawable.ic_question_mark_24));
}
switch(currentItem.getType()) {
case "file":
holder.fileTypeIs.setImageDrawable(AppCompatResources.getDrawable(context, R.drawable.ic_file));
holder.fileInfo.setVisibility(View.VISIBLE);
holder.fileInfo.setText(FileUtils.byteCountToDisplaySize(currentItem.getSize()));
break;
case "dir":
holder.fileTypeIs.setImageDrawable(AppCompatResources.getDrawable(context, R.drawable.ic_directory));
holder.fileInfo.setVisibility(View.GONE);
break;
case "submodule":
holder.fileTypeIs.setImageDrawable(AppCompatResources.getDrawable(context, R.drawable.ic_submodule));
holder.fileInfo.setVisibility(View.GONE);
break;
case "symlink":
holder.fileTypeIs.setImageDrawable(AppCompatResources.getDrawable(context, R.drawable.ic_symlink));
holder.fileInfo.setVisibility(View.GONE);
break;
default:
holder.fileTypeIs.setImageDrawable(AppCompatResources.getDrawable(context, R.drawable.ic_question));
}
}
@Override
public int getItemCount() {
return filesList.size();
return alteredFiles.size();
}
@Override
@ -178,17 +195,19 @@ public class FilesAdapter extends RecyclerView.Adapter<FilesAdapter.FilesViewHol
return filesFilter;
}
private Filter filesFilter = new Filter() {
private final Filter filesFilter = new Filter() {
@Override
protected FilterResults performFiltering(CharSequence constraint) {
List<Files> filteredList = new ArrayList<>();
if (constraint == null || constraint.length() == 0) {
filteredList.addAll(filesListFull);
filteredList.addAll(originalFiles);
} else {
String filterPattern = constraint.toString().toLowerCase().trim();
for (Files item : filesListFull) {
for (Files item : originalFiles) {
if (item.getName().toLowerCase().contains(filterPattern) || item.getPath().toLowerCase().contains(filterPattern)) {
filteredList.add(item);
}
@ -199,14 +218,19 @@ public class FilesAdapter extends RecyclerView.Adapter<FilesAdapter.FilesViewHol
results.values = filteredList;
return results;
}
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
filesList.clear();
filesList.addAll((List) results.values);
alteredFiles.clear();
alteredFiles.addAll((List) results.values);
notifyDataSetChanged();
}
};
}

View File

@ -1,138 +1,252 @@
package org.mian.gitnex.adapters;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Typeface;
import android.os.Bundle;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.HorizontalScrollView;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import androidx.fragment.app.FragmentManager;
import org.gitnex.tea4j.models.FileDiffView;
import org.mian.gitnex.R;
import org.mian.gitnex.models.FileDiffView;
import org.mian.gitnex.fragments.BottomSheetReplyFragment;
import org.mian.gitnex.helpers.AppUtil;
import org.mian.gitnex.views.DiffTextView;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentSkipListMap;
/**
* Author M M Arif
* Author opyale
*/
public class FilesDiffAdapter extends RecyclerView.Adapter<FilesDiffAdapter.FilesDiffViewHolder> {
public class FilesDiffAdapter extends BaseAdapter {
private List<FileDiffView> dataList;
private Context ctx;
private static Map<Long, View> selectedViews;
private static final int MAXIMUM_LINES = 5000;
static class FilesDiffViewHolder extends RecyclerView.ViewHolder {
private static int COLOR_ADDED;
private static int COLOR_REMOVED;
private static int COLOR_NORMAL;
private static int COLOR_SELECTED;
private static int COLOR_FONT;
private TextView fileContents;
private TextView fileName;
private TextView fileInfo;
private ImageView fileImage;
private HorizontalScrollView fileContentsView;
private LinearLayout allLines;
private final Context context;
private final FragmentManager fragmentManager;
private final List<FileDiffView> fileDiffViews;
private FilesDiffViewHolder(View itemView) {
super(itemView);
public FilesDiffAdapter(Context context, FragmentManager fragmentManager, List<FileDiffView> fileDiffViews) {
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);
this.context = context;
this.fragmentManager = fragmentManager;
this.fileDiffViews = fileDiffViews;
}
}
selectedViews = new ConcurrentSkipListMap<>();
public FilesDiffAdapter(List<FileDiffView> dataListMain, Context ctx) {
this.dataList = dataListMain;
this.ctx = ctx;
}
COLOR_ADDED = AppUtil.getColorFromAttribute(context, R.attr.diffAddedColor);
COLOR_REMOVED = AppUtil.getColorFromAttribute(context, R.attr.diffRemovedColor);
COLOR_NORMAL = AppUtil.getColorFromAttribute(context, R.attr.primaryBackgroundColor);
COLOR_SELECTED = AppUtil.getColorFromAttribute(context, R.attr.diffSelectedColor);
COLOR_FONT = AppUtil.getColorFromAttribute(context, R.attr.inputTextColor);
}
@NonNull
@Override
public FilesDiffAdapter.FilesDiffViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.files_diffs_list, parent, false);
return new FilesDiffAdapter.FilesDiffViewHolder(v);
}
@Override
public int getCount() {
@Override
public void onBindViewHolder(@NonNull FilesDiffViewHolder holder, int position) {
return fileDiffViews.size();
}
FileDiffView data = dataList.get(position);
@Override
public Object getItem(int position) {
if(data.isFileType()) {
return fileDiffViews.get(position);
}
holder.fileName.setText(data.getFileName());
@Override
public long getItemId(int position) {
holder.fileInfo.setVisibility(View.GONE);
return position;
}
//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);
@SuppressLint({"ViewHolder", "InflateParams"})
@Override
public View getView(int position, View convertView, ViewGroup parent) {
}
else {
convertView = LayoutInflater.from(context).inflate(R.layout.list_files_diffs, null, false);
String[] splitData = data.getFileContents().split("\\R");
TextView headerFileName = convertView.findViewById(R.id.headerFileName);
TextView headerFileInfo = convertView.findViewById(R.id.headerFileInfo);
ImageView footerImage = convertView.findViewById(R.id.footerImage);
LinearLayout diffStats = convertView.findViewById(R.id.diff_stats);
LinearLayout diffLines = convertView.findViewById(R.id.diffLines);
for (String eachSplit : splitData) {
FileDiffView data = (FileDiffView) getItem(position);
headerFileName.setText(data.getFileName());
TextView textLine = new TextView(ctx);
textLine.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
if(data.isFileBinary()) {
if (eachSplit.startsWith("+")) {
diffStats.setVisibility(View.GONE);
diffLines.addView(getMessageView(context.getResources().getString(R.string.binaryFileError)));
}
else {
textLine.setText(eachSplit);
holder.allLines.addView(textLine);
diffStats.setVisibility(View.VISIBLE);
headerFileInfo.setText(data.getFileInfo());
textLine.setTextColor(ctx.getResources().getColor(R.color.colorPrimary));
textLine.setPadding(5, 5, 5, 5);
textLine.setBackgroundColor(ctx.getResources().getColor(R.color.diffAddedColor));
String[] codeLines = getLines(data.toString());
}
else if (eachSplit.startsWith("-")) {
if(MAXIMUM_LINES > codeLines.length) {
textLine.setText(eachSplit);
holder.allLines.addView(textLine);
for(int l=0; l<codeLines.length; l++) {
textLine.setTextColor(ctx.getResources().getColor(R.color.colorPrimary));
textLine.setPadding(5, 5, 5, 5);
textLine.setBackgroundColor(ctx.getResources().getColor(R.color.diffRemovedColor));
if(codeLines[l].length() > 0) {
}
else {
int uniquePosition = l + (position * MAXIMUM_LINES);
if(eachSplit.length() > 0) {
textLine.setText(eachSplit);
holder.allLines.addView(textLine);
DiffTextView diffTextView = new DiffTextView(context);
textLine.setTextColor(ctx.getResources().getColor(R.color.colorPrimary));
textLine.setPadding(5, 5, 5, 5);
textLine.setBackgroundColor(ctx.getResources().getColor(R.color.white));
}
diffTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 15);
diffTextView.setPadding(15, 2, 15, 2);
diffTextView.setTypeface(Typeface.createFromAsset(context.getAssets(), "fonts/sourcecodeproregular.ttf"));
diffTextView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
diffTextView.setPosition(uniquePosition);
}
boolean isSelected = false;
}
for(View view : selectedViews.values()) {
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);
}
if(((DiffTextView) view).getPosition() == uniquePosition) {
}
diffTextView.setBackgroundColor(COLOR_SELECTED);
isSelected = true;
break;
}
}
@Override
public int getItemCount() {
return dataList.size();
}
}
}
if(codeLines[l].startsWith("+")) {
diffTextView.setText(codeLines[l]);
diffTextView.setTextColor(COLOR_FONT);
if(!isSelected) {
diffTextView.setInitialBackgroundColor(COLOR_ADDED);
}
}
else if(codeLines[l].startsWith("-")) {
diffTextView.setText(codeLines[l]);
diffTextView.setTextColor(COLOR_FONT);
if(!isSelected) {
diffTextView.setInitialBackgroundColor(COLOR_REMOVED);
}
}
else {
diffTextView.setText(codeLines[l]);
diffTextView.setTextColor(COLOR_FONT);
if(!isSelected) {
diffTextView.setInitialBackgroundColor(COLOR_NORMAL);
}
}
diffTextView.setOnClickListener(v -> {
if(((DiffTextView) v).getCurrentBackgroundColor() != COLOR_SELECTED) {
selectedViews.put(((DiffTextView) v).getPosition(), v);
v.setBackgroundColor(COLOR_SELECTED);
}
else {
selectedViews.remove(((DiffTextView) v).getPosition());
v.setBackgroundColor(((DiffTextView) v).getInitialBackgroundColor());
}
});
diffTextView.setOnLongClickListener(v -> {
if(((DiffTextView) v).getCurrentBackgroundColor() == COLOR_SELECTED) {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("```\n");
for(View view : selectedViews.values()) {
stringBuilder.append(((DiffTextView) view).getText());
stringBuilder.append("\n");
}
stringBuilder.append("```\n\n");
selectedViews.clear();
Bundle bundle = new Bundle();
bundle.putString("commentBody", stringBuilder.toString());
bundle.putBoolean("cursorToEnd", true);
BottomSheetReplyFragment.newInstance(bundle).show(fragmentManager, "replyBottomSheet");
}
return true;
});
diffLines.addView(diffTextView);
}
}
}
else {
diffLines.addView(getMessageView(context.getResources().getString(R.string.fileTooLarge)));
}
}
return convertView;
}
private TextView getMessageView(String message) {
TextView textView = new TextView(context);
textView.setTextColor(COLOR_FONT);
textView.setBackgroundColor(COLOR_NORMAL);
textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14);
textView.setPadding(15, 15, 15, 15);
textView.setTypeface(Typeface.DEFAULT);
textView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
textView.setText(message);
return textView;
}
private String[] getLines(String content) {
return content.split("\\R");
}
}

View File

@ -1,57 +1,45 @@
package org.mian.gitnex.adapters;
import android.annotation.SuppressLint;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.text.Spanned;
import android.os.Bundle;
import android.os.Handler;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.squareup.picasso.Picasso;
import androidx.annotation.NonNull;
import androidx.fragment.app.FragmentManager;
import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.bottomsheet.BottomSheetDialog;
import com.google.gson.JsonElement;
import com.vdurmont.emoji.EmojiParser;
import org.gitnex.tea4j.models.IssueComments;
import org.mian.gitnex.R;
import org.mian.gitnex.activities.ReplyToIssueActivity;
import org.mian.gitnex.helpers.TimeHelper;
import org.mian.gitnex.helpers.UserMentions;
import org.mian.gitnex.models.IssueComments;
import org.mian.gitnex.activities.ProfileActivity;
import org.mian.gitnex.clients.PicassoService;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.fragments.BottomSheetReplyFragment;
import org.mian.gitnex.helpers.AlertDialogs;
import org.mian.gitnex.helpers.AppUtil;
import org.mian.gitnex.helpers.Markdown;
import org.mian.gitnex.helpers.RoundedTransformation;
import org.mian.gitnex.util.TinyDB;
import org.mian.gitnex.helpers.ClickListener;
import org.ocpsoft.prettytime.PrettyTime;
import java.lang.reflect.Field;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Collections;
import org.mian.gitnex.helpers.TimeHelper;
import org.mian.gitnex.helpers.TinyDB;
import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.views.ReactionList;
import org.mian.gitnex.views.ReactionSpinner;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.view.ContextThemeWrapper;
import androidx.appcompat.widget.PopupMenu;
import androidx.recyclerview.widget.RecyclerView;
import io.noties.markwon.AbstractMarkwonPlugin;
import io.noties.markwon.Markwon;
import io.noties.markwon.core.CorePlugin;
import io.noties.markwon.core.MarkwonTheme;
import io.noties.markwon.ext.strikethrough.StrikethroughPlugin;
import io.noties.markwon.ext.tables.TablePlugin;
import io.noties.markwon.ext.tasklist.TaskListPlugin;
import io.noties.markwon.html.HtmlPlugin;
import io.noties.markwon.image.AsyncDrawable;
import io.noties.markwon.image.DefaultMediaDecoder;
import io.noties.markwon.image.ImageItem;
import io.noties.markwon.image.ImagesPlugin;
import io.noties.markwon.image.SchemeHandler;
import io.noties.markwon.image.gif.GifMediaDecoder;
import io.noties.markwon.image.svg.SvgMediaDecoder;
import io.noties.markwon.linkify.LinkifyPlugin;
import retrofit2.Call;
import retrofit2.Callback;
/**
* Author M M Arif
@ -59,232 +47,329 @@ import io.noties.markwon.linkify.LinkifyPlugin;
public class IssueCommentsAdapter extends RecyclerView.Adapter<IssueCommentsAdapter.IssueCommentViewHolder> {
private List<IssueComments> issuesComments;
private Context mCtx;
private final Context context;
private final TinyDB tinyDB;
private final Bundle bundle;
private final List<IssueComments> issuesComments;
private final FragmentManager fragmentManager;
private final BottomSheetReplyFragment.OnInteractedListener onInteractedListener;
private final Locale locale;
static class IssueCommentViewHolder extends RecyclerView.ViewHolder {
public IssueCommentsAdapter(Context ctx, Bundle bundle, List<IssueComments> issuesCommentsMain, FragmentManager fragmentManager, BottomSheetReplyFragment.OnInteractedListener onInteractedListener) {
private TextView issueNumber;
private TextView commendId;
private ImageView issueCommenterAvatar;
private TextView issueComment;
private TextView issueCommentDate;
private ImageView commentsOptionsMenu;
private TextView commendBodyRaw;
private TextView commentModified;
this.context = ctx;
this.bundle = bundle;
this.issuesComments = issuesCommentsMain;
this.fragmentManager = fragmentManager;
this.onInteractedListener = onInteractedListener;
tinyDB = TinyDB.getInstance(ctx);
locale = ctx.getResources().getConfiguration().locale;
}
private IssueCommentViewHolder(View itemView) {
super(itemView);
class IssueCommentViewHolder extends RecyclerView.ViewHolder {
issueNumber = itemView.findViewById(R.id.issueNumber);
commendId = itemView.findViewById(R.id.commendId);
issueCommenterAvatar = itemView.findViewById(R.id.issueCommenterAvatar);
issueComment = itemView.findViewById(R.id.issueComment);
issueCommentDate = itemView.findViewById(R.id.issueCommentDate);
commentsOptionsMenu = itemView.findViewById(R.id.commentsOptionsMenu);
commendBodyRaw = itemView.findViewById(R.id.commendBodyRaw);
commentModified = itemView.findViewById(R.id.commentModified);
private String userLoginId;
private IssueComments issueComment;
commentsOptionsMenu.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
private final ImageView avatar;
private final TextView author;
private final TextView information;
private final TextView comment;
private final LinearLayout commentReactionBadges;
final Context context = v.getContext();
//Context context_ = new ContextThemeWrapper(context, R.style.popupMenuStyle);
private IssueCommentViewHolder(View view) {
PopupMenu popupMenu = new PopupMenu(context, v);
popupMenu.inflate(R.menu.issue_comment_menu);
super(view);
Object menuHelper;
Class[] argTypes;
try {
avatar = view.findViewById(R.id.avatar);
author = view.findViewById(R.id.author);
information = view.findViewById(R.id.information);
ImageView menu = view.findViewById(R.id.menu);
comment = view.findViewById(R.id.comment);
commentReactionBadges = view.findViewById(R.id.commentReactionBadges);
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);
menu.setOnClickListener(v -> {
} catch (Exception e) {
final String loginUid = tinyDB.getString("loginUid");
popupMenu.show();
return;
@SuppressLint("InflateParams") View vw = LayoutInflater.from(context).inflate(R.layout.bottom_sheet_issue_comments, null);
}
TextView commentMenuEdit = vw.findViewById(R.id.commentMenuEdit);
TextView commentShare = vw.findViewById(R.id.issueCommentShare);
TextView commentMenuQuote = vw.findViewById(R.id.commentMenuQuote);
TextView commentMenuCopy = vw.findViewById(R.id.commentMenuCopy);
TextView commentMenuDelete = vw.findViewById(R.id.commentMenuDelete);
TextView issueCommentCopyUrl = vw.findViewById(R.id.issueCommentCopyUrl);
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case R.id.commentMenuEdit:
if(!loginUid.contentEquals(issueComment.getUser().getUsername())) {
commentMenuEdit.setVisibility(View.GONE);
commentMenuDelete.setVisibility(View.GONE);
}
Intent intent = new Intent(context, ReplyToIssueActivity.class);
intent.putExtra("commentId", commendId.getText());
intent.putExtra("commentAction", "edit");
intent.putExtra("commentBody", commendBodyRaw.getText());
context.startActivity(intent);
break;
if(issueComment.getBody().isEmpty()) {
commentMenuCopy.setVisibility(View.GONE);
}
case R.id.commentMenuDelete:
BottomSheetDialog dialog = new BottomSheetDialog(context);
dialog.setContentView(vw);
dialog.show();
break;
LinearLayout linearLayout = vw.findViewById(R.id.commentReactionButtons);
TextView loadReactions = new TextView(context);
loadReactions.setText(context.getString(R.string.genericWaitFor));
loadReactions.setGravity(Gravity.CENTER);
loadReactions.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 160));
linearLayout.addView(loadReactions);
}
return false;
}
});
Bundle bundle1 = new Bundle();
bundle1.putAll(bundle);
bundle1.putInt("commentId", issueComment.getId());
popupMenu.show();
ReactionSpinner reactionSpinner = new ReactionSpinner(context, bundle1);
reactionSpinner.setOnInteractedListener(() -> {
tinyDB.putBoolean("commentEdited", true);
}
});
onInteractedListener.onInteracted();
dialog.dismiss();
});
}
}
Handler handler = new Handler();
handler.postDelayed(() -> {
linearLayout.removeView(loadReactions);
reactionSpinner.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 160));
linearLayout.addView(reactionSpinner);
}, 2500);
public IssueCommentsAdapter(Context mCtx, List<IssueComments> issuesCommentsMain) {
this.mCtx = mCtx;
this.issuesComments = issuesCommentsMain;
}
commentMenuEdit.setOnClickListener(v1 -> {
Bundle bundle = new Bundle();
bundle.putInt("commentId", issueComment.getId());
bundle.putString("commentAction", "edit");
bundle.putString("commentBody", issueComment.getBody());
@NonNull
@Override
public IssueCommentsAdapter.IssueCommentViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.issue_comments, parent, false);
return new IssueCommentsAdapter.IssueCommentViewHolder(v);
}
BottomSheetReplyFragment bottomSheetReplyFragment = BottomSheetReplyFragment.newInstance(bundle);
bottomSheetReplyFragment.setOnInteractedListener(onInteractedListener);
bottomSheetReplyFragment.show(fragmentManager, "replyBottomSheet");
@SuppressLint("SetTextI18n")
@Override
public void onBindViewHolder(@NonNull IssueCommentsAdapter.IssueCommentViewHolder holder, int position) {
dialog.dismiss();
});
final TinyDB tinyDb = new TinyDB(mCtx);
final String locale = tinyDb.getString("locale");
final String timeFormat = tinyDb.getString("dateFormat");
final String loginUid = tinyDb.getString("loginUid");
commentShare.setOnClickListener(v1 -> {
// get comment Url
CharSequence commentUrl = issueComment.getHtml_url();
IssueComments currentItem = issuesComments.get(position);
// 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-" + issueComment.getId() + " " + 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));
if(!loginUid.equals(currentItem.getUser().getUsername())) {
holder.commentsOptionsMenu.setVisibility(View.INVISIBLE);
}
holder.commendId.setText(String.valueOf(currentItem.getId()));
holder.commendBodyRaw.setText(currentItem.getBody());
dialog.dismiss();
});
if (!currentItem.getUser().getFull_name().equals("")) {
holder.issueCommenterAvatar.setOnClickListener(new ClickListener(mCtx.getResources().getString(R.string.issueCommenter) + currentItem.getUser().getFull_name(), mCtx));
} else {
holder.issueCommenterAvatar.setOnClickListener(new ClickListener(mCtx.getResources().getString(R.string.issueCommenter) + currentItem.getUser().getLogin(), mCtx));
}
issueCommentCopyUrl.setOnClickListener(v1 -> {
// comment Url
CharSequence commentUrl = issueComment.getHtml_url();
if (currentItem.getUser().getAvatar_url() != null) {
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);
}
ClipboardManager clipboard = (ClipboardManager) Objects.requireNonNull(context).getSystemService(Context.CLIPBOARD_SERVICE);
assert clipboard != null;
String cleanIssueComments = currentItem.getBody().trim();
ClipData clip = ClipData.newPlainText(commentUrl, commentUrl);
clipboard.setPrimaryClip(clip);
final Markwon markwon = Markwon.builder(Objects.requireNonNull(mCtx))
.usePlugin(CorePlugin.create())
.usePlugin(ImagesPlugin.create(new ImagesPlugin.ImagesConfigure() {
@Override
public void configureImages(@NonNull ImagesPlugin plugin) {
plugin.addSchemeHandler(new SchemeHandler() {
@NonNull
@Override
public ImageItem handle(@NonNull String raw, @NonNull Uri uri) {
dialog.dismiss();
Toasty.success(context, context.getString(R.string.copyIssueUrlToastMsg));
});
final int resourceId = mCtx.getResources().getIdentifier(
raw.substring("drawable://".length()),
"drawable",
mCtx.getPackageName());
commentMenuQuote.setOnClickListener(v1 -> {
StringBuilder stringBuilder = new StringBuilder();
String commenterName = issueComment.getUser().getUsername();
final Drawable drawable = mCtx.getDrawable(resourceId);
if(!commenterName.equals(tinyDB.getString("userLogin"))) {
stringBuilder.append("@").append(commenterName).append("\n\n");
}
assert drawable != null;
return ImageItem.withResult(drawable);
}
String[] lines = issueComment.getBody().split("\\R");
@NonNull
@Override
public Collection<String> supportedSchemes() {
return Collections.singleton("drawable");
}
});
plugin.placeholderProvider(new ImagesPlugin.PlaceholderProvider() {
@Nullable
@Override
public Drawable providePlaceholder(@NonNull AsyncDrawable drawable) {
return null;
}
});
plugin.addMediaDecoder(GifMediaDecoder.create(false));
plugin.addMediaDecoder(SvgMediaDecoder.create(mCtx.getResources()));
plugin.addMediaDecoder(SvgMediaDecoder.create());
plugin.defaultMediaDecoder(DefaultMediaDecoder.create(mCtx.getResources()));
plugin.defaultMediaDecoder(DefaultMediaDecoder.create());
}
}))
.usePlugin(new AbstractMarkwonPlugin() {
@Override
public void configureTheme(@NonNull MarkwonTheme.Builder builder) {
builder
.codeTextColor(tinyDb.getInt("codeBlockColor"))
.codeBackgroundColor(tinyDb.getInt("codeBlockBackground"))
.linkColor(mCtx.getResources().getColor(R.color.lightBlue));
}
})
.usePlugin(TablePlugin.create(mCtx))
.usePlugin(TaskListPlugin.create(mCtx))
.usePlugin(HtmlPlugin.create())
.usePlugin(StrikethroughPlugin.create())
.usePlugin(LinkifyPlugin.create())
.build();
for(String line : lines) {
stringBuilder.append(">").append(line).append("\n");
}
Spanned bodyWithMD = markwon.toMarkdown(EmojiParser.parseToUnicode(cleanIssueComments));
markwon.setParsedMarkdown(holder.issueComment, UserMentions.UserMentionsFunc(mCtx, bodyWithMD, cleanIssueComments));
stringBuilder.append("\n");
String edited;
Bundle bundle = new Bundle();
bundle.putString("commentBody", stringBuilder.toString());
bundle.putBoolean("cursorToEnd", true);
if(!currentItem.getUpdated_at().equals(currentItem.getCreated_at())) {
edited = mCtx.getResources().getString(R.string.colorfulBulletSpan) + mCtx.getResources().getString(R.string.modifiedText);
holder.commentModified.setVisibility(View.VISIBLE);
holder.commentModified.setText(edited);
holder.commentModified.setOnClickListener(new ClickListener(TimeHelper.customDateFormatForToastDateFormat(currentItem.getUpdated_at()), mCtx));
}
else {
holder.commentModified.setVisibility(View.INVISIBLE);
}
dialog.dismiss();
BottomSheetReplyFragment.newInstance(bundle).show(fragmentManager, "replyBottomSheet");
});
switch (timeFormat) {
case "pretty": {
PrettyTime prettyTime = new PrettyTime(new Locale(locale));
String createdTime = prettyTime.format(currentItem.getCreated_at());
holder.issueCommentDate.setText(createdTime);
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;
}
}
commentMenuCopy.setOnClickListener(v1 -> {
ClipboardManager clipboard = (ClipboardManager) Objects.requireNonNull(context).getSystemService(Context.CLIPBOARD_SERVICE);
assert clipboard != null;
}
ClipData clip = ClipData.newPlainText("Comment on issue #" + tinyDB.getString("issueNumber"), issueComment.getBody());
clipboard.setPrimaryClip(clip);
@Override
public int getItemCount() {
return issuesComments.size();
}
dialog.dismiss();
Toasty.success(context, context.getString(R.string.copyIssueCommentToastMsg));
});
commentMenuDelete.setOnClickListener(v1 -> {
deleteIssueComment(context, issueComment.getId(), getAdapterPosition());
dialog.dismiss();
});
});
avatar.setOnClickListener(loginId -> {
Intent intent = new Intent(context, ProfileActivity.class);
intent.putExtra("username", userLoginId);
context.startActivity(intent);
});
avatar.setOnLongClickListener(loginId -> {
AppUtil.copyToClipboard(context, userLoginId, context.getString(R.string.copyLoginIdToClipBoard, userLoginId));
return true;
});
}
}
private void updateAdapter(int position) {
issuesComments.remove(position);
notifyItemRemoved(position);
notifyItemRangeChanged(position, issuesComments.size());
}
private void deleteIssueComment(final Context ctx, final int commentId, int position) {
final String loginUid = tinyDB.getString("loginUid");
final String instanceToken = "token " + tinyDB.getString(loginUid + "-token");
String[] repoFullName = tinyDB.getString("repoFullName").split("/");
if (repoFullName.length != 2) {
return;
}
final String repoOwner = repoFullName[0];
final String repoName = repoFullName[1];
Call<JsonElement> call = RetrofitClient
.getApiInterface(ctx)
.deleteComment(instanceToken, repoOwner, repoName, commentId);
call.enqueue(new Callback<JsonElement>() {
@Override
public void onResponse(@NonNull Call<JsonElement> call, @NonNull retrofit2.Response<JsonElement> response) {
switch(response.code()) {
case 204:
updateAdapter(position);
Toasty.success(ctx, ctx.getResources().getString(R.string.deleteCommentSuccess));
break;
case 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));
break;
case 403:
Toasty.error(ctx, ctx.getString(R.string.authorizeError));
break;
case 404:
Toasty.warning(ctx, ctx.getString(R.string.apiNotFound));
break;
default:
Toasty.error(ctx, ctx.getString(R.string.genericError));
}
}
@Override
public void onFailure(@NonNull Call<JsonElement> call, @NonNull Throwable t) {
Toasty.error(ctx, ctx.getResources().getString(R.string.genericServerResponseError));
}
});
}
@NonNull
@Override
public IssueCommentsAdapter.IssueCommentViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_issue_comments, parent, false);
return new IssueCommentsAdapter.IssueCommentViewHolder(v);
}
@Override
public void onBindViewHolder(@NonNull IssueCommentsAdapter.IssueCommentViewHolder holder, int position) {
String timeFormat = tinyDB.getString("dateFormat");
IssueComments issueComment = issuesComments.get(position);
int imgRadius = AppUtil.getPixelsFromDensity(context, 3);
holder.userLoginId = issueComment.getUser().getLogin();
holder.issueComment = issueComment;
holder.author.setText(issueComment.getUser().getUsername());
PicassoService.getInstance(context).get()
.load(issueComment.getUser().getAvatar_url())
.placeholder(R.drawable.loader_animated)
.transform(new RoundedTransformation(imgRadius, 0))
.resize(AppUtil.getPixelsFromDensity(context, 35), AppUtil.getPixelsFromDensity(context, 35))
.centerCrop()
.into(holder.avatar);
Markdown.render(context, EmojiParser.parseToUnicode(issueComment.getBody()), holder.comment);
StringBuilder informationBuilder = null;
if(issueComment.getCreated_at() != null) {
if(timeFormat.equals("pretty")) {
informationBuilder = new StringBuilder(TimeHelper.formatTime(issueComment.getCreated_at(), locale, "pretty", context));
holder.information.setOnClickListener(v -> TimeHelper.customDateFormatForToastDateFormat(issueComment.getCreated_at()));
}
else if(timeFormat.equals("normal")) {
informationBuilder = new StringBuilder(TimeHelper.formatTime(issueComment.getCreated_at(), locale, "normal", context));
}
if(!issueComment.getCreated_at().equals(issueComment.getUpdated_at())) {
if(informationBuilder != null) {
informationBuilder.append(context.getString(R.string.colorfulBulletSpan)).append(context.getString(R.string.modifiedText));
}
}
}
holder.information.setText(informationBuilder);
Bundle bundle1 = new Bundle();
bundle1.putAll(bundle);
bundle1.putInt("commentId", issueComment.getId());
ReactionList reactionList = new ReactionList(context, bundle1);
holder.commentReactionBadges.addView(reactionList);
reactionList.setOnReactionAddedListener(() -> {
if(holder.commentReactionBadges.getVisibility() != View.VISIBLE) {
holder.commentReactionBadges.post(() -> holder.commentReactionBadges.setVisibility(View.VISIBLE));
}
});
}
@Override
public int getItemCount() {
return issuesComments.size();
}
}

View File

@ -3,289 +3,217 @@ 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.RelativeLayout;
import android.widget.TextView;
import com.squareup.picasso.Picasso;
import androidx.annotation.NonNull;
import androidx.core.content.res.ResourcesCompat;
import androidx.core.text.HtmlCompat;
import androidx.recyclerview.widget.RecyclerView;
import com.vdurmont.emoji.EmojiParser;
import org.gitnex.tea4j.models.Issues;
import org.mian.gitnex.R;
import org.mian.gitnex.activities.IssueDetailActivity;
import org.mian.gitnex.activities.ProfileActivity;
import org.mian.gitnex.clients.PicassoService;
import org.mian.gitnex.helpers.AppUtil;
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.mian.gitnex.helpers.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 IssuesAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> implements Filterable {
public class IssuesAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private Context context;
private final int TYPE_LOAD = 0;
private List<Issues> issuesList;
private List<Issues> issuesListFull;
private OnLoadMoreListener loadMoreListener;
private boolean isLoading = false, isMoreDataAvailable = true;
private final Context context;
private final int TYPE_LOAD = 0;
private List<Issues> issuesList;
private OnLoadMoreListener loadMoreListener;
private boolean isLoading = false, isMoreDataAvailable = true;
public IssuesAdapter(Context context, List<Issues> issuesListMain) {
public IssuesAdapter(Context ctx, List<Issues> issuesListMain) {
this.context = context;
this.issuesList = issuesListMain;
issuesListFull = new ArrayList<>(issuesList);
this.context = ctx;
this.issuesList = issuesListMain;
}
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(context);
LayoutInflater inflater = LayoutInflater.from(context);
if(viewType == TYPE_LOAD) {
return new IssuesHolder(inflater.inflate(R.layout.list_issues, parent, false));
}
else {
return new 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) {
((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 Issues issue;
private final ImageView issueAssigneeAvatar;
private final TextView issueTitle;
private final TextView issueCreatedTime;
private final TextView issueCommentsCount;
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));
}
IssuesHolder(View itemView) {
}
super(itemView);
issueAssigneeAvatar = itemView.findViewById(R.id.assigneeAvatar);
issueTitle = itemView.findViewById(R.id.issueTitle);
issueCommentsCount = itemView.findViewById(R.id.issueCommentsCount);
issueCreatedTime = itemView.findViewById(R.id.issueCreatedTime);
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
itemView.setOnClickListener(layoutView -> {
Intent intent = new Intent(context, IssueDetailActivity.class);
intent.putExtra("issueNumber", issue.getNumber());
if(position >= getItemCount()-1 && isMoreDataAvailable && !isLoading && loadMoreListener!=null) {
TinyDB tinyDb = TinyDB.getInstance(context);
tinyDb.putString("issueNumber", String.valueOf(issue.getNumber()));
tinyDb.putString("issueType", "Issue");
context.startActivity(intent);
});
isLoading = true;
loadMoreListener.onLoadMore();
issueAssigneeAvatar.setOnClickListener(v -> {
Intent intent = new Intent(context, ProfileActivity.class);
intent.putExtra("username", issue.getUser().getLogin());
context.startActivity(intent);
});
}
issueAssigneeAvatar.setOnLongClickListener(loginId -> {
AppUtil.copyToClipboard(context, issue.getUser().getLogin(), context.getString(R.string.copyLoginIdToClipBoard, issue.getUser().getLogin()));
return true;
});
}
if(getItemViewType(position) == TYPE_LOAD) {
@SuppressLint("SetTextI18n")
void bindData(Issues issue) {
((IssuesHolder)holder).bindData(issuesList.get(position));
TinyDB tinyDb = TinyDB.getInstance(context);
Locale locale = context.getResources().getConfiguration().locale;
String timeFormat = tinyDb.getString("dateFormat");
}
int imgRadius = AppUtil.getPixelsFromDensity(context, 3);
}
PicassoService.getInstance(context).get()
.load(issue.getUser().getAvatar_url())
.placeholder(R.drawable.loader_animated)
.transform(new RoundedTransformation(imgRadius, 0))
.resize(120, 120)
.centerCrop()
.into(issueAssigneeAvatar);
@Override
public int getItemViewType(int position) {
String issueNumber_ = "<font color='" + ResourcesCompat.getColor(context.getResources(), R.color.lightGray, null) + "'>" + context.getResources().getString(R.string.hash) + issue.getNumber() + "</font>";
issueTitle.setText(HtmlCompat.fromHtml(issueNumber_ + " " + EmojiParser.parseToUnicode(issue.getTitle()), HtmlCompat.FROM_HTML_MODE_LEGACY));
if(issuesList.get(position).getTitle() != null) {
return TYPE_LOAD;
}
else {
return 1;
}
this.issue = issue;
this.issueCommentsCount.setText(String.valueOf(issue.getComments()));
}
switch(timeFormat) {
case "pretty": {
PrettyTime prettyTime = new PrettyTime(locale);
String createdTime = prettyTime.format(issue.getCreated_at());
this.issueCreatedTime.setText(createdTime);
this.issueCreatedTime.setOnClickListener(new ClickListener(TimeHelper.customDateFormatForToastDateFormat(issue.getCreated_at()), context));
break;
}
case "normal": {
DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd '" + context.getResources().getString(R.string.timeAtText) + "' HH:mm", locale);
String createdTime = formatter.format(issue.getCreated_at());
this.issueCreatedTime.setText(createdTime);
break;
}
case "normal1": {
DateFormat formatter = new SimpleDateFormat("dd-MM-yyyy '" + context.getResources().getString(R.string.timeAtText) + "' HH:mm", locale);
String createdTime = formatter.format(issue.getCreated_at());
this.issueCreatedTime.setText(createdTime);
break;
}
}
@Override
public int getItemCount() {
}
return issuesList.size();
}
}
static class LoadHolder extends RecyclerView.ViewHolder {
class IssuesHolder extends RecyclerView.ViewHolder {
LoadHolder(View itemView) {
private TextView issueNumber;
private ImageView issueAssigneeAvatar;
private TextView issueTitle;
private TextView issueCreatedTime;
private TextView issueCommentsCount;
private RelativeLayout relativeLayoutFrame;
super(itemView);
}
}
IssuesHolder(View itemView) {
public void setMoreDataAvailable(boolean moreDataAvailable) {
super(itemView);
isMoreDataAvailable = moreDataAvailable;
}
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);
relativeLayoutFrame = itemView.findViewById(R.id.relativeLayoutFrame);
public void notifyDataChanged() {
notifyDataSetChanged();
isLoading = false;
}
public interface OnLoadMoreListener {
issueTitle.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
void onLoadMore();
}
public void setLoadMoreListener(OnLoadMoreListener loadMoreListener) {
this.loadMoreListener = loadMoreListener;
}
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());
tinyDb.putString("issueType", "issue");
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());
tinyDb.putString("issueType", "issue");
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.getPull_request() != null) {
if (!issuesModel.getPull_request().isMerged()) {
relativeLayoutFrame.setVisibility(View.GONE);
relativeLayoutFrame.setLayoutParams(new RecyclerView.LayoutParams(0, 0));
}
}*/
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);
}
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(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();
}
};
public void updateList(List<Issues> list) {
issuesList = list;
notifyDataSetChanged();
}
}

View File

@ -1,29 +1,26 @@
package org.mian.gitnex.adapters;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.content.res.ColorStateList;
import android.graphics.Color;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.amulyakhare.textdrawable.TextDrawable;
import androidx.annotation.NonNull;
import androidx.cardview.widget.CardView;
import androidx.core.widget.ImageViewCompat;
import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.bottomsheet.BottomSheetDialog;
import org.gitnex.tea4j.models.Labels;
import org.mian.gitnex.R;
import org.mian.gitnex.activities.CreateLabelActivity;
import org.mian.gitnex.helpers.AlertDialogs;
import org.mian.gitnex.helpers.ColorInverter;
import org.mian.gitnex.helpers.LabelWidthCalculator;
import org.mian.gitnex.models.Labels;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import androidx.annotation.NonNull;
import androidx.appcompat.view.ContextThemeWrapper;
import androidx.appcompat.widget.PopupMenu;
import androidx.recyclerview.widget.RecyclerView;
/**
* Author M M Arif
@ -31,99 +28,82 @@ import androidx.recyclerview.widget.RecyclerView;
public class LabelsAdapter extends RecyclerView.Adapter<LabelsAdapter.LabelsViewHolder> {
private List<Labels> labelsList;
final private Context mCtx;
private ArrayList<Integer> labelsArray = new ArrayList<>();
private final List<Labels> labelsList;
private static String type;
private static String orgName;
static class LabelsViewHolder extends RecyclerView.ViewHolder {
private TextView labelTitle;
private TextView labelId;
private TextView labelColor;
private ImageView labelsView;
private Labels labels;
private final CardView labelView;
private final ImageView labelIcon;
private final TextView labelName;
private LabelsViewHolder(View itemView) {
super(itemView);
labelsView = itemView.findViewById(R.id.labelsView);
labelView = itemView.findViewById(R.id.labelView);
labelIcon = itemView.findViewById(R.id.labelIcon);
labelName = itemView.findViewById(R.id.labelName);
ImageView labelsOptionsMenu = itemView.findViewById(R.id.labelsOptionsMenu);
labelTitle = itemView.findViewById(R.id.labelTitle);
labelId = itemView.findViewById(R.id.labelId);
labelColor = itemView.findViewById(R.id.labelColor);
labelsOptionsMenu.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
labelsOptionsMenu.setOnClickListener(v -> {
final Context context = v.getContext();
//Context context_ = new ContextThemeWrapper(context, R.style.popupMenuStyle);
final Context context = v.getContext();
PopupMenu popupMenu = new PopupMenu(context, v);
popupMenu.inflate(R.menu.labels_menu);
@SuppressLint("InflateParams")
View view = LayoutInflater.from(context).inflate(R.layout.bottom_sheet_labels_in_list, null);
Object menuHelper;
Class[] argTypes;
try {
TextView labelMenuEdit = view.findViewById(R.id.labelMenuEdit);
TextView labelMenuDelete = view.findViewById(R.id.labelMenuDelete);
TextView bottomSheetHeader = view.findViewById(R.id.bottomSheetHeader);
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);
bottomSheetHeader.setText(labels.getName());
BottomSheetDialog dialog = new BottomSheetDialog(context);
dialog.setContentView(view);
dialog.show();
} catch (Exception e) {
labelMenuEdit.setOnClickListener(editLabel -> {
popupMenu.show();
return;
Intent intent = new Intent(context, CreateLabelActivity.class);
intent.putExtra("labelId", String.valueOf(labels.getId()));
intent.putExtra("labelTitle", labels.getName());
intent.putExtra("labelColor", labels.getColor());
intent.putExtra("labelAction", "edit");
intent.putExtra("type", type);
intent.putExtra("orgName", orgName);
context.startActivity(intent);
dialog.dismiss();
});
}
labelMenuDelete.setOnClickListener(deleteLabel -> {
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case R.id.labelMenuEdit:
AlertDialogs.labelDeleteDialog(context, labels.getName(), String.valueOf(labels.getId()),
context.getResources().getString(R.string.labelDeleteTitle),
context.getResources().getString(R.string.labelDeleteMessage),
context.getResources().getString(R.string.labelDeleteTitle),
context.getResources().getString(R.string.labelDeleteNegativeButton),
type, orgName);
dialog.dismiss();
});
Intent intent = new Intent(context, CreateLabelActivity.class);
intent.putExtra("labelId", labelId.getText());
intent.putExtra("labelTitle", labelTitle.getText());
intent.putExtra("labelColor", labelColor.getText());
intent.putExtra("labelAction", "edit");
context.startActivity(intent);
break;
case R.id.labelMenuDelete:
AlertDialogs.labelDeleteDialog(context, labelTitle.getText().toString(), labelId.getText().toString(),
context.getResources().getString(R.string.labelDeleteTitle),
context.getResources().getString(R.string.labelDeleteMessage),
context.getResources().getString(R.string.labelDeletePositiveButton),
context.getResources().getString(R.string.labelDeleteNegativeButton));
break;
}
return false;
}
});
popupMenu.show();
}
});
}
}
public LabelsAdapter(Context mCtx, List<Labels> labelsMain) {
this.mCtx = mCtx;
this.labelsList = labelsMain;
public LabelsAdapter(Context ctx, List<Labels> labelsMain, String type, String orgName) {
this.labelsList = labelsMain;
LabelsAdapter.type = type;
LabelsAdapter.orgName = orgName;
}
@NonNull
@Override
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);
}
@ -131,41 +111,19 @@ public class LabelsAdapter extends RecyclerView.Adapter<LabelsAdapter.LabelsView
public void onBindViewHolder(@NonNull LabelsAdapter.LabelsViewHolder holder, int position) {
Labels currentItem = labelsList.get(position);
int width = 33;
holder.labelTitle.setText(currentItem.getName());
holder.labelId.setText(String.valueOf(currentItem.getId()));
holder.labelColor.setText(currentItem.getColor());
holder.labels = currentItem;
String labelColor = currentItem.getColor();
String labelName = currentItem.getName();
int color = Color.parseColor("#" + labelColor);
int contrastColor = new ColorInverter().getContrastColor(color);
TextDrawable drawable = TextDrawable.builder()
.beginConfig()
//.useFont(Typeface.DEFAULT)
.bold()
.textColor(new ColorInverter().getContrastColor(color))
.fontSize(36)
.width(LabelWidthCalculator.customWidth(getMaxLabelLength()))
.height(60)
.endConfig()
.buildRoundRect(labelName, color, 8);
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);
ImageViewCompat.setImageTintList(holder.labelIcon, ColorStateList.valueOf(contrastColor));
holder.labelName.setTextColor(contrastColor);
holder.labelName.setText(labelName);
holder.labelView.setCardBackgroundColor(color);
}
@Override
@ -173,4 +131,4 @@ public class LabelsAdapter extends RecyclerView.Adapter<LabelsAdapter.LabelsView
return labelsList.size();
}
}
}

View File

@ -0,0 +1,132 @@
package org.mian.gitnex.adapters;
import android.graphics.Color;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import org.gitnex.tea4j.models.Labels;
import org.mian.gitnex.R;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
/**
* Author M M Arif
*/
public class LabelsListAdapter extends RecyclerView.Adapter<LabelsListAdapter.LabelsViewHolder> {
private List<Integer> currentLabelsIds;
private final List<Labels> labels;
private final List<String> labelsStrings = new ArrayList<>();
private List<Integer> labelsIds = new ArrayList<>();
private final LabelsListAdapterListener labelsListener;
public interface LabelsListAdapterListener {
void labelsInterface(List<String> data);
void labelsIdsInterface(List<Integer> data);
}
public LabelsListAdapter(List<Labels> labelsMain, LabelsListAdapterListener labelsListener, List<Integer> currentLabelsIds) {
this.labels = labelsMain;
this.labelsListener = labelsListener;
this.currentLabelsIds = currentLabelsIds;
}
static class LabelsViewHolder extends RecyclerView.ViewHolder {
private final CheckBox labelSelection;
private final TextView labelText;
private final ImageView labelColor;
private LabelsViewHolder(View itemView) {
super(itemView);
this.setIsRecyclable(false);
labelSelection = itemView.findViewById(R.id.labelSelection);
labelText = itemView.findViewById(R.id.labelText);
labelColor = itemView.findViewById(R.id.labelColor);
}
}
@NonNull
@Override
public LabelsListAdapter.LabelsViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.custom_labels_list, parent, false);
return new LabelsListAdapter.LabelsViewHolder(v);
}
@Override
public void onBindViewHolder(@NonNull LabelsListAdapter.LabelsViewHolder holder, int position) {
Labels currentItem = labels.get(position);
String labelColor = currentItem.getColor();
int color = Color.parseColor("#" + labelColor);
holder.labelText.setText(currentItem.getName());
holder.labelColor.setBackgroundColor(color);
for(int i = 0; i < labelsIds.size(); i++) {
if(labelsStrings.contains(currentItem.getName())) {
holder.labelSelection.setChecked(true);
}
}
currentLabelsIds = new ArrayList<>(new LinkedHashSet<>(currentLabelsIds));
for(int i = 0; i < currentLabelsIds.size(); i++) {
if(currentLabelsIds.contains(currentItem.getId())) {
holder.labelSelection.setChecked(true);
labelsIds.add(currentLabelsIds.get(i));
}
}
labelsListener.labelsIdsInterface(labelsIds);
holder.labelSelection.setOnCheckedChangeListener((buttonView, isChecked) -> {
if(isChecked) {
labelsStrings.add(currentItem.getName());
labelsIds.add(currentItem.getId());
}
else {
labelsStrings.remove(currentItem.getName());
labelsIds.remove(Integer.valueOf(currentItem.getId()));
}
labelsListener.labelsInterface(labelsStrings);
labelsListener.labelsIdsInterface(labelsIds);
});
labelsIds = new ArrayList<>(new LinkedHashSet<>(labelsIds));
}
@Override
public int getItemCount() {
return labels.size();
}
public void updateList(List<Integer> list) {
currentLabelsIds = list;
notifyDataSetChanged();
}
}

View File

@ -2,6 +2,8 @@ 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;
@ -10,10 +12,12 @@ import android.widget.Filter;
import android.widget.Filterable;
import android.widget.ImageView;
import android.widget.TextView;
import com.squareup.picasso.Picasso;
import org.gitnex.tea4j.models.UserInfo;
import org.mian.gitnex.R;
import org.mian.gitnex.activities.ProfileActivity;
import org.mian.gitnex.clients.PicassoService;
import org.mian.gitnex.helpers.AppUtil;
import org.mian.gitnex.helpers.RoundedTransformation;
import org.mian.gitnex.models.UserInfo;
import java.util.ArrayList;
import java.util.List;
@ -23,26 +27,40 @@ import java.util.List;
public class MembersByOrgAdapter extends BaseAdapter implements Filterable {
private List<UserInfo> membersList;
private Context mCtx;
private List<UserInfo> membersListFull;
private final List<UserInfo> membersList;
private final Context context;
private final List<UserInfo> membersListFull;
private class ViewHolder {
private ImageView memberAvatar;
private TextView memberName;
private String userLoginId;
private final ImageView memberAvatar;
private final TextView memberName;
ViewHolder(View v) {
memberAvatar = v.findViewById(R.id.memberAvatar);
memberName = v.findViewById(R.id.memberName);
memberAvatar.setOnClickListener(loginId -> {
Intent intent = new Intent(context, ProfileActivity.class);
intent.putExtra("username", userLoginId);
context.startActivity(intent);
});
memberAvatar.setOnLongClickListener(loginId -> {
AppUtil.copyToClipboard(context, userLoginId, context.getString(R.string.copyLoginIdToClipBoard, userLoginId));
return true;
});
}
}
public MembersByOrgAdapter(Context mCtx, List<UserInfo> membersListMain) {
this.mCtx = mCtx;
public MembersByOrgAdapter(Context ctx, List<UserInfo> membersListMain) {
this.context = ctx;
this.membersList = membersListMain;
membersListFull = new ArrayList<>(membersList);
}
@Override
@ -67,31 +85,37 @@ public class MembersByOrgAdapter extends BaseAdapter implements Filterable {
MembersByOrgAdapter.ViewHolder viewHolder = null;
if (finalView == null) {
finalView = LayoutInflater.from(mCtx).inflate(R.layout.members_by_org_list, null);
viewHolder = new MembersByOrgAdapter.ViewHolder(finalView);
finalView = LayoutInflater.from(context).inflate(R.layout.list_members_by_org, null);
viewHolder = new ViewHolder(finalView);
finalView.setTag(viewHolder);
}
else {
viewHolder = (MembersByOrgAdapter.ViewHolder) finalView.getTag();
}
initData(viewHolder, position);
return finalView;
}
private void initData(MembersByOrgAdapter.ViewHolder viewHolder, int position) {
UserInfo currentItem = membersList.get(position);
Picasso.get().load(currentItem.getAvatar()).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(viewHolder.memberAvatar);
int imgRadius = AppUtil.getPixelsFromDensity(context, 3);
PicassoService.getInstance(context).get().load(currentItem.getAvatar()).placeholder(R.drawable.loader_animated).transform(new RoundedTransformation(imgRadius, 0)).resize(120, 120).centerCrop().into(viewHolder.memberAvatar);
viewHolder.userLoginId = currentItem.getLogin();
if(!currentItem.getFullname().equals("")) {
viewHolder.memberName.setText(currentItem.getFullname());
viewHolder.memberName.setText(Html.fromHtml(currentItem.getFullname()));
}
else {
viewHolder.memberName.setText(currentItem.getLogin());
}
}
@Override
@ -99,14 +123,17 @@ public class MembersByOrgAdapter extends BaseAdapter implements Filterable {
return membersFilter;
}
private Filter membersFilter = new Filter() {
private final Filter membersFilter = new Filter() {
@Override
protected FilterResults performFiltering(CharSequence constraint) {
List<UserInfo> filteredList = new ArrayList<>();
if (constraint == null || constraint.length() == 0) {
filteredList.addAll(membersListFull);
} else {
}
else {
String filterPattern = constraint.toString().toLowerCase().trim();
for (UserInfo item : membersListFull) {
@ -124,6 +151,7 @@ public class MembersByOrgAdapter extends BaseAdapter implements Filterable {
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
membersList.clear();
membersList.addAll((List) results.values);
notifyDataSetChanged();

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