mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-26 12:23:58 +01:00
[GSoC] Merge Leaderboard branch with master (#3905)
* [GSoC] Fixes #3789 Updated UI of achievements activity to display level in first tab & Leaderboard in the second tab (#3794)
* Updated UI of achievements activity to display level in first tab and Leaderboard in the second tab
* Removed hardcoded string
* Fixes #3861 Use the APIs to fetch leaderboard’s based on uploads via mobile app (all time) and display it in the Leaderboard screen. (#3865)
* [GSoC] Added Unit Tests and Fixed Landscape Mode Bug (#3872)
* Fixes #3861 Use the APIs to fetch leaderboard’s based on uploads via mobile app (all time) and display it in the Leaderboard screen.
* Fixed Bug - missing data in landscape mode
* Added Unit Tests for Leaderboard
* Added JavaDocs
* Updated JavaDocs
* [GSoC] Added Pagination to Leaderboard (#3881)
* Fixes #3861 Use the APIs to fetch leaderboard’s based on uploads via mobile app (all time) and display it in the Leaderboard screen.
* Fixed Bug - missing data in landscape mode
* Added Unit Tests for Leaderboard
* Added JavaDocs
* Updated JavaDocs
* Added Pagination
* Added Merge Adapter
* Fixed Test Case
* Added Smooth Scroll
* Added Progress Bar for Paging
* Fixed Gradle
* [GSoC] Added option to set a new avatar (#3892)
* Fixes #3861 Use the APIs to fetch leaderboard’s based on uploads via mobile app (all time) and display it in the Leaderboard screen.
* Added option to set a new avatar
* [GSoC] Added Click to open user profile for leaderboard (#3887)
* Localisation updates from https://translatewiki.net.
* Localisation updates from https://translatewiki.net.
* #3749 Improve MediaClient UnitTests (#3846)
* #3468 Switch from RvRenderer to AdapterDelegates - replace SearchDepictionsRenderer
* #3468 Switch from RvRenderer to AdapterDelegates - replace UploadCategoryDepictionsRenderer
* #3468 Switch from RvRenderer to AdapterDelegates - update BaseAdapter to be easier to use
* #3468 Switch from RvRenderer to AdapterDelegates - replace SearchImagesRenderer
* #3468 Switch from RvRenderer to AdapterDelegates - replace SearchCategoriesRenderer
* #3468 Switch from RvRenderer to AdapterDelegates - replace NotificationRenderer
* #3468 Switch from RvRenderer to AdapterDelegates - replace UploadDepictsRenderer
* #3468 Switch from RvRenderer to AdapterDelegates - replace PlaceRenderer
* #3756 Convert SearchDepictionsFragment to use Pagination - convert SearchDepictionsFragment
* #3756 Convert SearchDepictionsFragment to use Pagination - fix presenter unit tests now that view is not nullable - fix Category prefix imports
* #3756 Convert SearchDepictionsFragment to use Pagination - test DataSource related classes
* #3756 Convert SearchDepictionsFragment to use Pagination - reset rx scheduler - ignore failing test
* #3760 Convert SearchCategoriesFragment to use Pagination - extract functionality of pagination to base classes - add category pagination
* #3772 Convert SearchImagesFragment to use Pagination - convert SearchImagesFragment - tidy up showing the empty view - make search fragments show snackbar with appropriate text
* #3772 Convert SearchImagesFragment to use Pagination - allow viewpager to load more data
* #3760 remove test that got re-added by merge
* #3760 remove duplicate dependency
* #3772 fix compilation
* #3780 Create media using a combination of Entities & MwQueryResult - construct media with an entity - move fields from media down to contribution - move dynamic fields outside of media - remove unused constructors - remove all unnecessary fetching of captions/descriptions - bump database version
* #3808 Construct media objects that depict an item id correctly - use generator to construct media for DepictedImages
* #3810 Convert DepictedImagesFragment to use Pagination - extract common media paging methods - convert to DepictedImages to use pagination
* #3810 Convert DepictedImagesFragment to use Pagination - rename base classes to better reflect usage
* #3810 Convert DepictedImagesFragment to use Pagination - map to empty result with no pages
* #3810 Convert DepictedImagesFragment to use Pagination - align test with returned values
* #3780 Create media using a combination of Entities & MwQueryResult - update wikicode to align with expected behaviour
* #3780 Create media using a combination of Entities & MwQueryResult - replace old site of thumbnail title with most relevant caption
* #3818 Convert SubDepictionListFragment to use Pagination - replace SubDepictionList with Child and Parent Fragments - replace contracts with simple presenter declarations - move classes to appropriate packages - delete unused network models - delete duplicated paging classes
* #3820 Convert CategoryImagesListFragment to use Pagination - replace CategoryImagesListFragment with CategoriesMediaFragment - disallow the construction of media objects without imageinfo
* #3822 Convert SubCategoryImagesListFragment to use Pagination - convert subcategories - add continuation support in category client - rely on interfaces for callbacks of PageableMediaFragments
* #3822 Convert SubCategoryImagesListFragment to use Pagination - convert parent categories - delete list fragment - creat base class to support continuation requests in clients
* #3822 Convert SubCategoryImagesListFragment to use Pagination - add tests for ParentCategoriesDataSource
* #3822 Convert SubCategoryImagesListFragment to use Pagination - remove no longer applicable test
* #3749 Improve MediaClient UnitTests - test rewrite
* #3749 Improve MediaClient UnitTests - align with buildConfig property
* With pause and resume for uploads (#3858)
* With pause and resume for uploads
* Dispose current upload
* Make pause and resume work
* Check stash validity
* With java docs
* minor
* Localisation updates from https://translatewiki.net.
* Localisation updates from https://translatewiki.net.
* Add nearby presenter unit tests (#3615)
* init the test file
* Add tests to check if searchthisarea button action and checkbox actions are added after initialize test
* Add tests to locked unlocked nearby cases
* Add tests for null cases in updateMapAndList method
* Add test to check which locations are used to populate places, depending to LocationChangeType
* Add tests to test users position is not followed if blue dot (current location marker) is not visible
* Add tests to decide search this area method visibility on camera move
* Add tests for multi filteirng of placetypes
* add tests for single place type selection too
* Add tests to tests search view focus gain and bottom sheet visibilities
* Add tests for SearchCloseToCurrentLocation
* Remove two unneeded getter and setter for isNearbyLocked, use @VisibleForTesting annotation instead
* Add VisibleForTesting annotation to initializeNearbyOperations method so that it will be private by default
* Add missing tests
* Add tests for map updated case and add missing lines those are being tested
* Add some missind method verifications
* Create real latlang objects isntead of spying them
* Use a real presenter object instead of a spy
* Revert nonneeded @VisibleForTest annotations, instead reach via lockUnlock method
* Reduce code repetitions
* Do not call a test from another test method
* Add some more tests
* Fix minor issues
* Hidden categories are not showed in suggested categories (#3853)
* Localisation updates from https://translatewiki.net.
* Clarify that the caption would also be used as the image title (#3876)
The app uses the fist caption as the file title. This should also
be communicated to the user via the info box as they would not be
aware of it otherwise.
* Localisation updates from https://translatewiki.net.
* Added Click event for leaderboard, Fixed #3886
* Fixed Travis
Co-authored-by: translatewiki.net <l10n-bot@translatewiki.net>
Co-authored-by: Seán Mac Gillicuddy <seantheappdev@gmail.com>
Co-authored-by: Vivek Maskara <maskaravivek@gmail.com>
Co-authored-by: neslihanturan <tur.neslihan@gmail.com>
Co-authored-by: Paulina <63326136+PaulinaQuintero@users.noreply.github.com>
Co-authored-by: Kaartic Sivaraam <kaartic.sivaraam@gmail.com>
* [GSoC] Added Leaderboard Filters (#3902)
* Attempt to add filters
* Basic Filter Working
* Filter Improved
* Filter Completed
* Add JavaDocs
* Added Test for Update Avatar
* Decreased Margin of Filter
* [GSoC] Updated leaderboard string (#3897)
* Localisation updates from https://translatewiki.net.
* Localisation updates from https://translatewiki.net.
* #3749 Improve MediaClient UnitTests (#3846)
* #3468 Switch from RvRenderer to AdapterDelegates - replace SearchDepictionsRenderer
* #3468 Switch from RvRenderer to AdapterDelegates - replace UploadCategoryDepictionsRenderer
* #3468 Switch from RvRenderer to AdapterDelegates - update BaseAdapter to be easier to use
* #3468 Switch from RvRenderer to AdapterDelegates - replace SearchImagesRenderer
* #3468 Switch from RvRenderer to AdapterDelegates - replace SearchCategoriesRenderer
* #3468 Switch from RvRenderer to AdapterDelegates - replace NotificationRenderer
* #3468 Switch from RvRenderer to AdapterDelegates - replace UploadDepictsRenderer
* #3468 Switch from RvRenderer to AdapterDelegates - replace PlaceRenderer
* #3756 Convert SearchDepictionsFragment to use Pagination - convert SearchDepictionsFragment
* #3756 Convert SearchDepictionsFragment to use Pagination - fix presenter unit tests now that view is not nullable - fix Category prefix imports
* #3756 Convert SearchDepictionsFragment to use Pagination - test DataSource related classes
* #3756 Convert SearchDepictionsFragment to use Pagination - reset rx scheduler - ignore failing test
* #3760 Convert SearchCategoriesFragment to use Pagination - extract functionality of pagination to base classes - add category pagination
* #3772 Convert SearchImagesFragment to use Pagination - convert SearchImagesFragment - tidy up showing the empty view - make search fragments show snackbar with appropriate text
* #3772 Convert SearchImagesFragment to use Pagination - allow viewpager to load more data
* #3760 remove test that got re-added by merge
* #3760 remove duplicate dependency
* #3772 fix compilation
* #3780 Create media using a combination of Entities & MwQueryResult - construct media with an entity - move fields from media down to contribution - move dynamic fields outside of media - remove unused constructors - remove all unnecessary fetching of captions/descriptions - bump database version
* #3808 Construct media objects that depict an item id correctly - use generator to construct media for DepictedImages
* #3810 Convert DepictedImagesFragment to use Pagination - extract common media paging methods - convert to DepictedImages to use pagination
* #3810 Convert DepictedImagesFragment to use Pagination - rename base classes to better reflect usage
* #3810 Convert DepictedImagesFragment to use Pagination - map to empty result with no pages
* #3810 Convert DepictedImagesFragment to use Pagination - align test with returned values
* #3780 Create media using a combination of Entities & MwQueryResult - update wikicode to align with expected behaviour
* #3780 Create media using a combination of Entities & MwQueryResult - replace old site of thumbnail title with most relevant caption
* #3818 Convert SubDepictionListFragment to use Pagination - replace SubDepictionList with Child and Parent Fragments - replace contracts with simple presenter declarations - move classes to appropriate packages - delete unused network models - delete duplicated paging classes
* #3820 Convert CategoryImagesListFragment to use Pagination - replace CategoryImagesListFragment with CategoriesMediaFragment - disallow the construction of media objects without imageinfo
* #3822 Convert SubCategoryImagesListFragment to use Pagination - convert subcategories - add continuation support in category client - rely on interfaces for callbacks of PageableMediaFragments
* #3822 Convert SubCategoryImagesListFragment to use Pagination - convert parent categories - delete list fragment - creat base class to support continuation requests in clients
* #3822 Convert SubCategoryImagesListFragment to use Pagination - add tests for ParentCategoriesDataSource
* #3822 Convert SubCategoryImagesListFragment to use Pagination - remove no longer applicable test
* #3749 Improve MediaClient UnitTests - test rewrite
* #3749 Improve MediaClient UnitTests - align with buildConfig property
* With pause and resume for uploads (#3858)
* With pause and resume for uploads
* Dispose current upload
* Make pause and resume work
* Check stash validity
* With java docs
* minor
* Localisation updates from https://translatewiki.net.
* Localisation updates from https://translatewiki.net.
* Add nearby presenter unit tests (#3615)
* init the test file
* Add tests to check if searchthisarea button action and checkbox actions are added after initialize test
* Add tests to locked unlocked nearby cases
* Add tests for null cases in updateMapAndList method
* Add test to check which locations are used to populate places, depending to LocationChangeType
* Add tests to test users position is not followed if blue dot (current location marker) is not visible
* Add tests to decide search this area method visibility on camera move
* Add tests for multi filteirng of placetypes
* add tests for single place type selection too
* Add tests to tests search view focus gain and bottom sheet visibilities
* Add tests for SearchCloseToCurrentLocation
* Remove two unneeded getter and setter for isNearbyLocked, use @VisibleForTesting annotation instead
* Add VisibleForTesting annotation to initializeNearbyOperations method so that it will be private by default
* Add missing tests
* Add tests for map updated case and add missing lines those are being tested
* Add some missind method verifications
* Create real latlang objects isntead of spying them
* Use a real presenter object instead of a spy
* Revert nonneeded @VisibleForTest annotations, instead reach via lockUnlock method
* Reduce code repetitions
* Do not call a test from another test method
* Add some more tests
* Fix minor issues
* Hidden categories are not showed in suggested categories (#3853)
* Localisation updates from https://translatewiki.net.
* Clarify that the caption would also be used as the image title (#3876)
The app uses the fist caption as the file title. This should also
be communicated to the user via the info box as they would not be
aware of it otherwise.
* Localisation updates from https://translatewiki.net.
* Delete NearbyMapFragment & NearbyListFragment (#3885)
* Fixes #3884
* Delete NearbyMapFragment & NearbyListFragment
* Fixed NearbyParentFragmentPresenterTest
* Localisation updates from https://translatewiki.net.
* Localisation updates from https://translatewiki.net.
* Add more nearby tests (#3877)
* more nearby tests added
* Add tests for Label class
* Add checkbox test javadocs
* Add javadocs for label
* Localisation updates from https://translatewiki.net.
* Updated strings.xml
Co-authored-by: translatewiki.net <l10n-bot@translatewiki.net>
Co-authored-by: Seán Mac Gillicuddy <seantheappdev@gmail.com>
Co-authored-by: Vivek Maskara <maskaravivek@gmail.com>
Co-authored-by: neslihanturan <tur.neslihan@gmail.com>
Co-authored-by: Paulina <63326136+PaulinaQuintero@users.noreply.github.com>
Co-authored-by: Kaartic Sivaraam <kaartic.sivaraam@gmail.com>
Co-authored-by: Ashish Kumar <ashishkumar468@gmail.com>
* Updated Strings
* Added JavaDocs for all methods and classes
* Added JavaDocs for all methods and classes
* Added More JavaDocs
* Revert string.xml
* Revert "Revert string.xml"
This reverts commit 00019b598a.
* Added protected
* Fixed strings.xml extra changes
* Revert codeStyle change
* Fixed extra string change
Co-authored-by: Vivek Maskara <maskaravivek@gmail.com>
Co-authored-by: translatewiki.net <l10n-bot@translatewiki.net>
Co-authored-by: Seán Mac Gillicuddy <seantheappdev@gmail.com>
Co-authored-by: neslihanturan <tur.neslihan@gmail.com>
Co-authored-by: Paulina <63326136+PaulinaQuintero@users.noreply.github.com>
Co-authored-by: Kaartic Sivaraam <kaartic.sivaraam@gmail.com>
Co-authored-by: Ashish Kumar <ashishkumar468@gmail.com>
This commit is contained in:
parent
50bcaab15d
commit
eb816b4536
44 changed files with 2839 additions and 641 deletions
|
|
@ -21,7 +21,7 @@ dependencies {
|
|||
// Utils
|
||||
implementation 'in.yuvi:http.fluent:1.3'
|
||||
implementation 'com.google.code.gson:gson:2.8.5'
|
||||
implementation 'com.squareup.okhttp3:okhttp:4.5.0'
|
||||
implementation 'com.squareup.okhttp3:okhttp:4.8.0'
|
||||
implementation 'com.squareup.okio:okio:2.2.2'
|
||||
implementation 'io.reactivex.rxjava2:rxandroid:2.1.0'
|
||||
implementation 'io.reactivex.rxjava2:rxjava:2.2.3'
|
||||
|
|
@ -42,6 +42,7 @@ dependencies {
|
|||
implementation 'com.dinuscxj:circleprogressbar:1.1.1'
|
||||
implementation 'com.karumi:dexter:5.0.0'
|
||||
implementation "com.jakewharton:butterknife:$BUTTERKNIFE_VERSION"
|
||||
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
|
||||
|
||||
kapt "com.jakewharton:butterknife-compiler:$BUTTERKNIFE_VERSION"
|
||||
implementation "com.hannesdorfmann:adapterdelegates4-kotlin-dsl-layoutcontainer:$ADAPTER_DELEGATES_VERSION"
|
||||
|
|
@ -50,6 +51,7 @@ dependencies {
|
|||
testImplementation "androidx.paging:paging-common-ktx:$PAGING_VERSION"
|
||||
implementation "androidx.paging:paging-rxjava2-ktx:$PAGING_VERSION"
|
||||
implementation "androidx.recyclerview:recyclerview:1.2.0-alpha02"
|
||||
implementation 'com.squareup.okhttp3:okhttp-ws:3.4.1'
|
||||
|
||||
// Logging
|
||||
implementation 'ch.acra:acra-dialog:5.3.0'
|
||||
|
|
@ -79,7 +81,7 @@ dependencies {
|
|||
testImplementation 'junit:junit:4.13'
|
||||
testImplementation 'org.robolectric:robolectric:4.3'
|
||||
testImplementation 'androidx.test:core:1.2.0'
|
||||
testImplementation 'com.squareup.okhttp3:mockwebserver:3.12.1'
|
||||
testImplementation "com.squareup.okhttp3:mockwebserver:4.8.0"
|
||||
testImplementation "org.powermock:powermock-module-junit4:2.0.0-beta.5"
|
||||
testImplementation "org.powermock:powermock-api-mockito2:2.0.0-beta.5"
|
||||
testImplementation 'org.mockito:mockito-core:2.23.0'
|
||||
|
|
@ -94,7 +96,7 @@ dependencies {
|
|||
androidTestImplementation 'androidx.test:runner:1.2.0'
|
||||
androidTestImplementation 'androidx.test:rules:1.2.0'
|
||||
androidTestImplementation 'androidx.annotation:annotation:1.1.0'
|
||||
androidTestImplementation 'com.squareup.okhttp3:mockwebserver:3.12.1'
|
||||
androidTestImplementation 'com.squareup.okhttp3:mockwebserver:4.8.0'
|
||||
androidTestUtil 'androidx.test:orchestrator:1.2.0'
|
||||
|
||||
// Debugging
|
||||
|
|
@ -209,8 +211,8 @@ android {
|
|||
|
||||
configurations.all {
|
||||
resolutionStrategy.force 'androidx.annotation:annotation:1.0.2'
|
||||
exclude module: 'okhttp-ws'
|
||||
}
|
||||
|
||||
flavorDimensions 'tier'
|
||||
productFlavors {
|
||||
prod {
|
||||
|
|
|
|||
|
|
@ -7,10 +7,9 @@ import androidx.test.espresso.intent.Intents
|
|||
import androidx.test.espresso.intent.matcher.IntentMatchers.hasComponent
|
||||
import androidx.test.espresso.intent.rule.IntentsTestRule
|
||||
import androidx.test.espresso.matcher.ViewMatchers.withId
|
||||
import androidx.test.filters.MediumTest
|
||||
import androidx.test.runner.AndroidJUnit4
|
||||
import fr.free.nrw.commons.achievements.AchievementsActivity
|
||||
import fr.free.nrw.commons.auth.LoginActivity
|
||||
import fr.free.nrw.commons.profile.ProfileActivity
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
|
|
@ -32,6 +31,6 @@ class AchievementsActivityTest {
|
|||
onView(withId(R.id.drawer_layout)).perform(DrawerActions.open())
|
||||
onView(withId(R.id.user_icon)).perform(click())
|
||||
|
||||
Intents.intended(hasComponent(AchievementsActivity::class.java.name))
|
||||
Intents.intended(hasComponent(ProfileActivity::class.java.name))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -137,8 +137,8 @@
|
|||
/>
|
||||
|
||||
<activity
|
||||
android:name=".achievements.AchievementsActivity"
|
||||
android:label="@string/Achievements" />
|
||||
android:name=".profile.ProfileActivity"
|
||||
android:label="@string/Profile" />
|
||||
|
||||
<activity
|
||||
android:name=".bookmarks.BookmarksActivity"
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import javax.inject.Singleton;
|
|||
|
||||
import fr.free.nrw.commons.Media;
|
||||
import fr.free.nrw.commons.R;
|
||||
import fr.free.nrw.commons.achievements.FeedbackResponse;
|
||||
import fr.free.nrw.commons.profile.achievements.FeedbackResponse;
|
||||
import fr.free.nrw.commons.auth.SessionManager;
|
||||
import fr.free.nrw.commons.mwapi.OkHttpJsonApiClient;
|
||||
import fr.free.nrw.commons.utils.ViewUtilWrapper;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import dagger.Module;
|
|||
import dagger.android.ContributesAndroidInjector;
|
||||
import fr.free.nrw.commons.AboutActivity;
|
||||
import fr.free.nrw.commons.WelcomeActivity;
|
||||
import fr.free.nrw.commons.achievements.AchievementsActivity;
|
||||
import fr.free.nrw.commons.auth.LoginActivity;
|
||||
import fr.free.nrw.commons.auth.SignupActivity;
|
||||
import fr.free.nrw.commons.bookmarks.BookmarksActivity;
|
||||
|
|
@ -15,6 +14,7 @@ import fr.free.nrw.commons.explore.depictions.WikidataItemDetailsActivity;
|
|||
import fr.free.nrw.commons.explore.SearchActivity;
|
||||
import fr.free.nrw.commons.explore.ExploreActivity;
|
||||
import fr.free.nrw.commons.notification.NotificationActivity;
|
||||
import fr.free.nrw.commons.profile.ProfileActivity;
|
||||
import fr.free.nrw.commons.review.ReviewActivity;
|
||||
import fr.free.nrw.commons.settings.SettingsActivity;
|
||||
import fr.free.nrw.commons.upload.UploadActivity;
|
||||
|
|
@ -68,7 +68,7 @@ public abstract class ActivityBuilderModule {
|
|||
abstract ExploreActivity bindExploreActivity();
|
||||
|
||||
@ContributesAndroidInjector
|
||||
abstract AchievementsActivity bindAchievementsActivity();
|
||||
abstract ProfileActivity bindAchievementsActivity();
|
||||
|
||||
@ContributesAndroidInjector
|
||||
abstract BookmarksActivity bindBookmarksActivity();
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@ import fr.free.nrw.commons.explore.recentsearches.RecentSearchesFragment;
|
|||
import fr.free.nrw.commons.media.MediaDetailFragment;
|
||||
import fr.free.nrw.commons.media.MediaDetailPagerFragment;
|
||||
import fr.free.nrw.commons.nearby.fragments.NearbyParentFragment;
|
||||
import fr.free.nrw.commons.profile.achievements.AchievementsFragment;
|
||||
import fr.free.nrw.commons.profile.leaderboard.LeaderboardFragment;
|
||||
import fr.free.nrw.commons.review.ReviewImageFragment;
|
||||
import fr.free.nrw.commons.settings.SettingsFragment;
|
||||
import fr.free.nrw.commons.upload.categories.UploadCategoriesFragment;
|
||||
|
|
@ -103,4 +105,10 @@ public abstract class FragmentBuilderModule {
|
|||
|
||||
@ContributesAndroidInjector
|
||||
abstract ParentCategoriesFragment bindParentCategoriesFragment();
|
||||
|
||||
@ContributesAndroidInjector
|
||||
abstract AchievementsFragment bindAchievementsFragment();
|
||||
|
||||
@ContributesAndroidInjector
|
||||
abstract LeaderboardFragment bindLeaderboardFragment();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -85,11 +85,13 @@ public class NetworkingModule {
|
|||
public OkHttpJsonApiClient provideOkHttpJsonApiClient(OkHttpClient okHttpClient,
|
||||
DepictsClient depictsClient,
|
||||
@Named("tools_forge") HttpUrl toolsForgeUrl,
|
||||
@Named("test_tools_forge") HttpUrl testToolsForgeUrl,
|
||||
@Named("default_preferences") JsonKvStore defaultKvStore,
|
||||
Gson gson) {
|
||||
return new OkHttpJsonApiClient(okHttpClient,
|
||||
depictsClient,
|
||||
toolsForgeUrl,
|
||||
testToolsForgeUrl,
|
||||
WIKIDATA_SPARQL_QUERY_URL,
|
||||
BuildConfig.WIKIMEDIA_CAMPAIGNS_URL,
|
||||
gson);
|
||||
|
|
@ -124,6 +126,14 @@ public class NetworkingModule {
|
|||
return HttpUrl.parse(TOOLS_FORGE_URL);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Named("test_tools_forge")
|
||||
@NonNull
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
public HttpUrl provideTestToolsForgeUrl() {
|
||||
return HttpUrl.parse(TEST_TOOLS_FORGE_URL);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
@Named(NAMED_COMMONS_WIKI_SITE)
|
||||
|
|
|
|||
|
|
@ -22,15 +22,19 @@ import butterknife.ButterKnife;
|
|||
import com.google.android.material.snackbar.Snackbar;
|
||||
import fr.free.nrw.commons.Media;
|
||||
import fr.free.nrw.commons.R;
|
||||
import fr.free.nrw.commons.auth.SessionManager;
|
||||
import fr.free.nrw.commons.bookmarks.Bookmark;
|
||||
import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesContentProvider;
|
||||
import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesDao;
|
||||
import fr.free.nrw.commons.contributions.Contribution;
|
||||
import fr.free.nrw.commons.di.CommonsDaggerSupportFragment;
|
||||
import fr.free.nrw.commons.mwapi.OkHttpJsonApiClient;
|
||||
import fr.free.nrw.commons.utils.DownloadUtils;
|
||||
import fr.free.nrw.commons.utils.ImageUtils;
|
||||
import fr.free.nrw.commons.utils.NetworkUtils;
|
||||
import fr.free.nrw.commons.utils.ViewUtil;
|
||||
import io.reactivex.disposables.CompositeDisposable;
|
||||
import java.util.Objects;
|
||||
import javax.inject.Inject;
|
||||
import timber.log.Timber;
|
||||
|
||||
|
|
@ -38,6 +42,14 @@ public class MediaDetailPagerFragment extends CommonsDaggerSupportFragment imple
|
|||
|
||||
@Inject BookmarkPicturesDao bookmarkDao;
|
||||
|
||||
@Inject
|
||||
protected OkHttpJsonApiClient okHttpJsonApiClient;
|
||||
|
||||
@Inject
|
||||
protected SessionManager sessionManager;
|
||||
|
||||
private static CompositeDisposable compositeDisposable = new CompositeDisposable();
|
||||
|
||||
@BindView(R.id.mediaDetailsPager) ViewPager pager;
|
||||
private Boolean editable;
|
||||
private boolean isFeaturedImage;
|
||||
|
|
@ -160,6 +172,10 @@ public class MediaDetailPagerFragment extends CommonsDaggerSupportFragment imple
|
|||
// Set wallpaper
|
||||
setWallpaper(m);
|
||||
return true;
|
||||
case R.id.menu_set_as_avatar:
|
||||
// Set avatar
|
||||
setAvatar(m);
|
||||
return true;
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
|
@ -178,6 +194,20 @@ public class MediaDetailPagerFragment extends CommonsDaggerSupportFragment imple
|
|||
ImageUtils.setWallpaperFromImageUrl(getActivity(), Uri.parse(media.getImageUrl()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the media as user's leaderboard avatar
|
||||
* @param media
|
||||
*/
|
||||
private void setAvatar(Media media) {
|
||||
if (media.getImageUrl() == null || media.getImageUrl().isEmpty()) {
|
||||
Timber.d("Media URL not present");
|
||||
return;
|
||||
}
|
||||
ImageUtils.setAvatarFromImageUrl(getActivity(), media.getImageUrl(),
|
||||
Objects.requireNonNull(sessionManager.getCurrentAccount()).name,
|
||||
okHttpJsonApiClient, compositeDisposable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
if (!editable) { // Disable menu options for editable views
|
||||
|
|
|
|||
|
|
@ -1,16 +1,21 @@
|
|||
package fr.free.nrw.commons.mwapi;
|
||||
|
||||
import static fr.free.nrw.commons.profile.leaderboard.LeaderboardConstants.LEADERBOARD_END_POINT;
|
||||
import static fr.free.nrw.commons.profile.leaderboard.LeaderboardConstants.UPDATE_AVATAR_END_POINT;
|
||||
|
||||
import android.text.TextUtils;
|
||||
import androidx.annotation.NonNull;
|
||||
import com.google.gson.Gson;
|
||||
import fr.free.nrw.commons.achievements.FeaturedImages;
|
||||
import fr.free.nrw.commons.achievements.FeedbackResponse;
|
||||
import fr.free.nrw.commons.campaigns.CampaignResponseDTO;
|
||||
import fr.free.nrw.commons.explore.depictions.DepictsClient;
|
||||
import fr.free.nrw.commons.location.LatLng;
|
||||
import fr.free.nrw.commons.nearby.Place;
|
||||
import fr.free.nrw.commons.nearby.model.NearbyResponse;
|
||||
import fr.free.nrw.commons.nearby.model.NearbyResultItem;
|
||||
import fr.free.nrw.commons.profile.achievements.FeaturedImages;
|
||||
import fr.free.nrw.commons.profile.achievements.FeedbackResponse;
|
||||
import fr.free.nrw.commons.profile.leaderboard.LeaderboardResponse;
|
||||
import fr.free.nrw.commons.profile.leaderboard.UpdateAvatarResponse;
|
||||
import fr.free.nrw.commons.upload.FileUtils;
|
||||
import fr.free.nrw.commons.upload.structure.depictions.DepictedItem;
|
||||
import fr.free.nrw.commons.utils.ConfigUtils;
|
||||
|
|
@ -40,6 +45,7 @@ public class OkHttpJsonApiClient {
|
|||
private final OkHttpClient okHttpClient;
|
||||
private final DepictsClient depictsClient;
|
||||
private final HttpUrl wikiMediaToolforgeUrl;
|
||||
private final HttpUrl wikiMediaTestToolforgeUrl;
|
||||
private final String sparqlQueryUrl;
|
||||
private final String campaignsUrl;
|
||||
private final Gson gson;
|
||||
|
|
@ -49,17 +55,105 @@ public class OkHttpJsonApiClient {
|
|||
public OkHttpJsonApiClient(OkHttpClient okHttpClient,
|
||||
DepictsClient depictsClient,
|
||||
HttpUrl wikiMediaToolforgeUrl,
|
||||
HttpUrl wikiMediaTestToolforgeUrl,
|
||||
String sparqlQueryUrl,
|
||||
String campaignsUrl,
|
||||
Gson gson) {
|
||||
this.okHttpClient = okHttpClient;
|
||||
this.depictsClient = depictsClient;
|
||||
this.wikiMediaToolforgeUrl = wikiMediaToolforgeUrl;
|
||||
this.wikiMediaTestToolforgeUrl = wikiMediaTestToolforgeUrl;
|
||||
this.sparqlQueryUrl = sparqlQueryUrl;
|
||||
this.campaignsUrl = campaignsUrl;
|
||||
this.gson = gson;
|
||||
}
|
||||
|
||||
/**
|
||||
* The method will gradually calls the leaderboard API and fetches the leaderboard
|
||||
* @param userName username of leaderboard user
|
||||
* @param duration duration for leaderboard
|
||||
* @param category category for leaderboard
|
||||
* @param limit page size limit for list
|
||||
* @param offset offset for the list
|
||||
* @return LeaderboardResponse object
|
||||
*/
|
||||
@NonNull
|
||||
public Observable<LeaderboardResponse> getLeaderboard(String userName, String duration, String category, String limit, String offset) {
|
||||
final String fetchLeaderboardUrlTemplate = wikiMediaTestToolforgeUrl
|
||||
+ LEADERBOARD_END_POINT;
|
||||
String url = String.format(Locale.ENGLISH,
|
||||
fetchLeaderboardUrlTemplate,
|
||||
userName,
|
||||
duration,
|
||||
category,
|
||||
limit,
|
||||
offset);
|
||||
HttpUrl.Builder urlBuilder = HttpUrl.parse(url).newBuilder();
|
||||
urlBuilder.addQueryParameter("user", userName);
|
||||
urlBuilder.addQueryParameter("duration", duration);
|
||||
urlBuilder.addQueryParameter("category", category);
|
||||
urlBuilder.addQueryParameter("limit", limit);
|
||||
urlBuilder.addQueryParameter("offset", offset);
|
||||
Timber.i("Url %s", urlBuilder.toString());
|
||||
Request request = new Request.Builder()
|
||||
.url(urlBuilder.toString())
|
||||
.build();
|
||||
return Observable.fromCallable(() -> {
|
||||
Response response = okHttpClient.newCall(request).execute();
|
||||
if (response != null && response.body() != null && response.isSuccessful()) {
|
||||
String json = response.body().string();
|
||||
if (json == null) {
|
||||
return new LeaderboardResponse();
|
||||
}
|
||||
Timber.d("Response for leaderboard is %s", json);
|
||||
try {
|
||||
return gson.fromJson(json, LeaderboardResponse.class);
|
||||
} catch (Exception e) {
|
||||
return new LeaderboardResponse();
|
||||
}
|
||||
}
|
||||
return new LeaderboardResponse();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will update the leaderboard user avatar
|
||||
* @param username username to update
|
||||
* @param avatar url of the new avatar
|
||||
* @return UpdateAvatarResponse object
|
||||
*/
|
||||
@NonNull
|
||||
public Single<UpdateAvatarResponse> setAvatar(String username, String avatar) {
|
||||
final String urlTemplate = wikiMediaTestToolforgeUrl
|
||||
+ UPDATE_AVATAR_END_POINT;
|
||||
return Single.fromCallable(() -> {
|
||||
String url = String.format(Locale.ENGLISH,
|
||||
urlTemplate,
|
||||
username,
|
||||
avatar);
|
||||
HttpUrl.Builder urlBuilder = HttpUrl.parse(url).newBuilder();
|
||||
urlBuilder.addQueryParameter("user", username);
|
||||
urlBuilder.addQueryParameter("avatar", avatar);
|
||||
Timber.i("Url %s", urlBuilder.toString());
|
||||
Request request = new Request.Builder()
|
||||
.url(urlBuilder.toString())
|
||||
.build();
|
||||
Response response = okHttpClient.newCall(request).execute();
|
||||
if (response != null && response.body() != null && response.isSuccessful()) {
|
||||
String json = response.body().string();
|
||||
if (json == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return gson.fromJson(json, UpdateAvatarResponse.class);
|
||||
} catch (Exception e) {
|
||||
return new UpdateAvatarResponse();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public Single<Integer> getUploadCount(String userName) {
|
||||
HttpUrl.Builder urlBuilder = wikiMediaToolforgeUrl.newBuilder();
|
||||
|
|
@ -145,7 +239,6 @@ public class OkHttpJsonApiClient {
|
|||
userName);
|
||||
HttpUrl.Builder urlBuilder = HttpUrl.parse(url).newBuilder();
|
||||
urlBuilder.addQueryParameter("user", userName);
|
||||
Timber.i("Url %s", urlBuilder.toString());
|
||||
Request request = new Request.Builder()
|
||||
.url(urlBuilder.toString())
|
||||
.build();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,84 @@
|
|||
package fr.free.nrw.commons.profile;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import com.google.android.material.tabs.TabLayout;
|
||||
import fr.free.nrw.commons.R;
|
||||
import fr.free.nrw.commons.profile.achievements.AchievementsFragment;
|
||||
import fr.free.nrw.commons.profile.leaderboard.LeaderboardFragment;
|
||||
import fr.free.nrw.commons.theme.NavigationBaseActivity;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This activity will set two tabs, achievements and
|
||||
* each tab will have their own fragments
|
||||
*/
|
||||
public class ProfileActivity extends NavigationBaseActivity {
|
||||
|
||||
private FragmentManager supportFragmentManager;
|
||||
|
||||
@BindView(R.id.viewPager)
|
||||
ViewPager viewPager;
|
||||
|
||||
@BindView(R.id.tab_layout)
|
||||
TabLayout tabLayout;
|
||||
|
||||
private ViewPagerAdapter viewPagerAdapter;
|
||||
private AchievementsFragment achievementsFragment;
|
||||
private LeaderboardFragment leaderboardFragment;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_profile);
|
||||
ButterKnife.bind(this);
|
||||
initDrawer();
|
||||
setTitle(R.string.Profile);
|
||||
|
||||
supportFragmentManager = getSupportFragmentManager();
|
||||
viewPagerAdapter = new ViewPagerAdapter(getSupportFragmentManager());
|
||||
viewPager.setAdapter(viewPagerAdapter);
|
||||
tabLayout.setupWithViewPager(viewPager);
|
||||
setTabs();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a way to change current activity to AchievementActivity
|
||||
* @param context
|
||||
*/
|
||||
public static void startYourself(Context context) {
|
||||
Intent intent = new Intent(context, ProfileActivity.class);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_SINGLE_TOP);
|
||||
context.startActivity(intent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the tabs for the fragments
|
||||
*/
|
||||
private void setTabs() {
|
||||
List<Fragment> fragmentList = new ArrayList<>();
|
||||
List<String> titleList = new ArrayList<>();
|
||||
achievementsFragment = new AchievementsFragment();
|
||||
fragmentList.add(achievementsFragment);
|
||||
titleList.add(getResources().getString(R.string.achievements_tab_title).toUpperCase());
|
||||
leaderboardFragment = new LeaderboardFragment();
|
||||
fragmentList.add(leaderboardFragment);
|
||||
titleList.add(getResources().getString(R.string.leaderboard_tab_title).toUpperCase());
|
||||
viewPagerAdapter.setTabData(fragmentList, titleList);
|
||||
viewPagerAdapter.notifyDataSetChanged();
|
||||
|
||||
}
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
compositeDisposable.clear();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
package fr.free.nrw.commons.profile;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentPagerAdapter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This View Pager Adapter will set the fragments for profile activity
|
||||
*/
|
||||
public class ViewPagerAdapter extends FragmentPagerAdapter {
|
||||
private List<Fragment> fragmentList = new ArrayList<>();
|
||||
private List<String> fragmentTitleList = new ArrayList<>();
|
||||
|
||||
public ViewPagerAdapter(FragmentManager manager) {
|
||||
super(manager);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the fragment of the viewpager at a particular position
|
||||
* @param position
|
||||
*/
|
||||
@Override
|
||||
public Fragment getItem(int position) {
|
||||
return fragmentList.get(position);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the total number of fragments in the viewpager.
|
||||
* @return size
|
||||
*/
|
||||
@Override
|
||||
public int getCount() {
|
||||
return fragmentList.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method sets the fragment and title list in the viewpager
|
||||
* @param fragmentList List of all fragments to be displayed in the viewpager
|
||||
* @param fragmentTitleList List of all titles of the fragments
|
||||
*/
|
||||
public void setTabData(List<Fragment> fragmentList, List<String> fragmentTitleList) {
|
||||
this.fragmentList = fragmentList;
|
||||
this.fragmentTitleList = fragmentTitleList;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the title of the page at a particular position
|
||||
* @param position
|
||||
*/
|
||||
@Override
|
||||
public CharSequence getPageTitle(int position) {
|
||||
return fragmentTitleList.get(position);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package fr.free.nrw.commons.achievements
|
||||
package fr.free.nrw.commons.profile.achievements
|
||||
|
||||
/**
|
||||
* Represents Achievements class and stores all the parameters
|
||||
|
|
@ -87,12 +87,14 @@ class Achievements {
|
|||
*/
|
||||
@JvmStatic
|
||||
fun from(response: FeedbackResponse): Achievements {
|
||||
return Achievements(response.uniqueUsedImages,
|
||||
response.articlesUsingImages,
|
||||
response.thanksReceived,
|
||||
response.featuredImages.qualityImages
|
||||
+ response.featuredImages.featuredPicturesOnWikimediaCommons, 0,
|
||||
response.deletedUploads)
|
||||
return Achievements(
|
||||
response.uniqueUsedImages,
|
||||
response.articlesUsingImages,
|
||||
response.thanksReceived,
|
||||
response.featuredImages.qualityImages
|
||||
+ response.featuredImages.featuredPicturesOnWikimediaCommons, 0,
|
||||
response.deletedUploads
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,61 +1,52 @@
|
|||
package fr.free.nrw.commons.achievements;
|
||||
package fr.free.nrw.commons.profile.achievements;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.ContextThemeWrapper;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.appcompat.view.ContextThemeWrapper;
|
||||
import androidx.constraintlayout.widget.ConstraintLayout;
|
||||
import androidx.core.content.FileProvider;
|
||||
import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat;
|
||||
|
||||
import com.dinuscxj.progressbar.CircleProgressBar;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import butterknife.OnClick;
|
||||
import com.dinuscxj.progressbar.CircleProgressBar;
|
||||
import fr.free.nrw.commons.R;
|
||||
import fr.free.nrw.commons.Utils;
|
||||
import fr.free.nrw.commons.auth.SessionManager;
|
||||
import fr.free.nrw.commons.di.CommonsDaggerSupportFragment;
|
||||
import fr.free.nrw.commons.mwapi.OkHttpJsonApiClient;
|
||||
import fr.free.nrw.commons.theme.NavigationBaseActivity;
|
||||
import fr.free.nrw.commons.utils.ViewUtil;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.CompositeDisposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
import javax.inject.Inject;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import timber.log.Timber;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* activity for sharing feedback on uploaded activity
|
||||
* fragment for sharing feedback on uploaded activity
|
||||
*/
|
||||
public class AchievementsActivity extends NavigationBaseActivity {
|
||||
public class AchievementsFragment extends CommonsDaggerSupportFragment {
|
||||
|
||||
private static final double BADGE_IMAGE_WIDTH_RATIO = 0.4;
|
||||
private static final double BADGE_IMAGE_HEIGHT_RATIO = 0.3;
|
||||
|
|
@ -64,55 +55,72 @@ public class AchievementsActivity extends NavigationBaseActivity {
|
|||
|
||||
@BindView(R.id.achievement_badge_image)
|
||||
ImageView imageView;
|
||||
|
||||
@BindView(R.id.achievement_badge_text)
|
||||
TextView badgeText;
|
||||
|
||||
@BindView(R.id.achievement_level)
|
||||
TextView levelNumber;
|
||||
@BindView(R.id.toolbar)
|
||||
Toolbar toolbar;
|
||||
|
||||
@BindView(R.id.thanks_received)
|
||||
TextView thanksReceived;
|
||||
|
||||
@BindView(R.id.images_uploaded_progressbar)
|
||||
CircleProgressBar imagesUploadedProgressbar;
|
||||
|
||||
@BindView(R.id.images_used_by_wiki_progress_bar)
|
||||
CircleProgressBar imagesUsedByWikiProgressBar;
|
||||
|
||||
@BindView(R.id.image_reverts_progressbar)
|
||||
CircleProgressBar imageRevertsProgressbar;
|
||||
|
||||
@BindView(R.id.image_featured)
|
||||
TextView imagesFeatured;
|
||||
|
||||
@BindView(R.id.images_revert_limit_text)
|
||||
TextView imagesRevertLimitText;
|
||||
|
||||
@BindView(R.id.progressBar)
|
||||
ProgressBar progressBar;
|
||||
|
||||
@BindView(R.id.layout_image_uploaded)
|
||||
RelativeLayout layoutImageUploaded;
|
||||
|
||||
@BindView(R.id.layout_image_reverts)
|
||||
RelativeLayout layoutImageReverts;
|
||||
|
||||
@BindView(R.id.layout_image_used_by_wiki)
|
||||
RelativeLayout layoutImageUsedByWiki;
|
||||
|
||||
@BindView(R.id.layout_statistics)
|
||||
LinearLayout layoutStatistics;
|
||||
|
||||
@BindView(R.id.images_used_by_wiki_text)
|
||||
TextView imageByWikiText;
|
||||
|
||||
@BindView(R.id.images_reverted_text)
|
||||
TextView imageRevertedText;
|
||||
|
||||
@BindView(R.id.images_upload_text_param)
|
||||
TextView imageUploadedText;
|
||||
|
||||
@BindView(R.id.wikidata_edits)
|
||||
TextView wikidataEditsText;
|
||||
|
||||
|
||||
@Inject
|
||||
SessionManager sessionManager;
|
||||
|
||||
@Inject
|
||||
OkHttpJsonApiClient okHttpJsonApiClient;
|
||||
MenuItem item;
|
||||
|
||||
private CompositeDisposable compositeDisposable = new CompositeDisposable();
|
||||
|
||||
// To keep track of the number of wiki edits made by a user
|
||||
private int numberOfEdits = 0;
|
||||
|
||||
// menu item for action bar
|
||||
private MenuItem item;
|
||||
|
||||
/**
|
||||
* This method helps in the creation Achievement screen and
|
||||
* dynamically set the size of imageView
|
||||
|
|
@ -120,15 +128,13 @@ public class AchievementsActivity extends NavigationBaseActivity {
|
|||
* @param savedInstanceState Data bundle
|
||||
*/
|
||||
@Override
|
||||
@SuppressLint("StringFormatInvalid")
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_achievements);
|
||||
ButterKnife.bind(this);
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
View rootView = inflater.inflate(R.layout.fragment_achievements, container, false);
|
||||
ButterKnife.bind(this, rootView);
|
||||
|
||||
// DisplayMetrics used to fetch the size of the screen
|
||||
DisplayMetrics displayMetrics = new DisplayMetrics();
|
||||
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
|
||||
getActivity().getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
|
||||
int height = displayMetrics.heightPixels;
|
||||
int width = displayMetrics.widthPixels;
|
||||
|
||||
|
|
@ -139,37 +145,23 @@ public class AchievementsActivity extends NavigationBaseActivity {
|
|||
params.width = (int) (width * BADGE_IMAGE_WIDTH_RATIO);
|
||||
imageView.requestLayout();
|
||||
|
||||
setSupportActionBar(toolbar);
|
||||
progressBar.setVisibility(View.VISIBLE);
|
||||
|
||||
setHasOptionsMenu(true);
|
||||
|
||||
hideLayouts();
|
||||
setWikidataEditCount();
|
||||
setAchievements();
|
||||
initDrawer();
|
||||
return rootView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
compositeDisposable.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* To invoke the AlertDialog on clicking info button
|
||||
*/
|
||||
@OnClick(R.id.achievement_info)
|
||||
public void showInfoDialog(){
|
||||
launchAlert(getResources().getString(R.string.Achievements)
|
||||
,getResources().getString(R.string.achievements_info_message));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) {
|
||||
// Inflate the menu; this adds items to the action bar if it is present.
|
||||
getMenuInflater().inflate(R.menu.menu_about, menu);
|
||||
item=menu.getItem(0);
|
||||
super.onCreateOptionsMenu(menu, menuInflater);
|
||||
menuInflater.inflate(R.menu.menu_about, menu);
|
||||
item = menu.getItem(0);
|
||||
item.setVisible(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -180,7 +172,7 @@ public class AchievementsActivity extends NavigationBaseActivity {
|
|||
int id = item.getItemId();
|
||||
// take screenshot in form of bitmap and show it in Alert Dialog
|
||||
if (id == R.id.share_app_icon) {
|
||||
View rootView = getWindow().getDecorView().findViewById(android.R.id.content);
|
||||
View rootView = getActivity().getWindow().getDecorView().findViewById(android.R.id.content);
|
||||
Bitmap screenShot = Utils.getScreenShot(rootView);
|
||||
showAlert(screenShot);
|
||||
}
|
||||
|
|
@ -188,20 +180,39 @@ public class AchievementsActivity extends NavigationBaseActivity {
|
|||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
/**
|
||||
* It displays the alertDialog with Image of screenshot
|
||||
* @param screenshot
|
||||
*/
|
||||
public void showAlert(Bitmap screenshot){
|
||||
AlertDialog.Builder alertadd = new AlertDialog.Builder(getActivity());
|
||||
LayoutInflater factory = LayoutInflater.from(getActivity());
|
||||
final View view = factory.inflate(R.layout.image_alert_layout, null);
|
||||
ImageView screenShotImage = view.findViewById(R.id.alert_image);
|
||||
screenShotImage.setImageBitmap(screenshot);
|
||||
TextView shareMessage = view.findViewById(R.id.alert_text);
|
||||
shareMessage.setText(R.string.achievements_share_message);
|
||||
alertadd.setView(view);
|
||||
alertadd.setPositiveButton(R.string.about_translate_proceed, (dialog, which) -> shareScreen(screenshot));
|
||||
alertadd.setNegativeButton(android.R.string.cancel, (dialog, which) -> dialog.cancel());
|
||||
alertadd.show();
|
||||
}
|
||||
|
||||
/**
|
||||
* To take bitmap and store it temporary storage and share it
|
||||
* @param bitmap
|
||||
*/
|
||||
void shareScreen(Bitmap bitmap) {
|
||||
try {
|
||||
File file = new File(this.getExternalCacheDir(), "screen.png");
|
||||
File file = new File(getActivity().getExternalCacheDir(), "screen.png");
|
||||
FileOutputStream fOut = new FileOutputStream(file);
|
||||
bitmap.compress(Bitmap.CompressFormat.PNG, 100, fOut);
|
||||
fOut.flush();
|
||||
fOut.close();
|
||||
file.setReadable(true, false);
|
||||
Uri fileUri = FileProvider.getUriForFile(getApplicationContext(), getPackageName()+".provider", file);
|
||||
grantUriPermission(getPackageName(), fileUri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
Uri fileUri = FileProvider
|
||||
.getUriForFile(getActivity().getApplicationContext(), getActivity().getPackageName()+".provider", file);
|
||||
getActivity().grantUriPermission(getActivity().getPackageName(), fileUri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
final Intent intent = new Intent(android.content.Intent.ACTION_SEND);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
intent.putExtra(Intent.EXTRA_STREAM, fileUri);
|
||||
|
|
@ -212,6 +223,15 @@ public class AchievementsActivity extends NavigationBaseActivity {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* To invoke the AlertDialog on clicking info button
|
||||
*/
|
||||
@OnClick(R.id.achievement_info)
|
||||
public void showInfoDialog(){
|
||||
launchAlert(getResources().getString(R.string.Achievements)
|
||||
,getResources().getString(R.string.achievements_info_message));
|
||||
}
|
||||
|
||||
/**
|
||||
* To call the API to get results in form Single<JSONObject>
|
||||
* which then calls parseJson when results are fetched
|
||||
|
|
@ -234,7 +254,7 @@ public class AchievementsActivity extends NavigationBaseActivity {
|
|||
layoutImageReverts.setVisibility(View.INVISIBLE);
|
||||
imageView.setVisibility(View.INVISIBLE);
|
||||
// If the number of edits made by the user are more than 150,000
|
||||
// in some cases such high number of wiki edit counts cause the
|
||||
// in some cases such high number of wiki edit counts cause the
|
||||
// achievements calculator to fail in some cases, for more details
|
||||
// refer Issue: #3295
|
||||
if (numberOfEdits <= 150000) {
|
||||
|
|
@ -264,7 +284,6 @@ public class AchievementsActivity extends NavigationBaseActivity {
|
|||
* To call the API to fetch the count of wiki data edits
|
||||
* in the form of JavaRx Single object<JSONobject>
|
||||
*/
|
||||
@SuppressLint("CheckResult")
|
||||
private void setWikidataEditCount() {
|
||||
String userName = sessionManager.getUserName();
|
||||
if (StringUtils.isBlank(userName)) {
|
||||
|
|
@ -285,18 +304,18 @@ public class AchievementsActivity extends NavigationBaseActivity {
|
|||
/**
|
||||
* Shows a snack bar which has an action button which on click dismisses the snackbar and invokes the
|
||||
* listener passed
|
||||
* @param tooManyAchievements if this value is true it means that the number of achievements of the
|
||||
* user are so high that it wrecks havoc with the Achievements calculator due to which request may time
|
||||
* @param tooManyAchievements if this value is true it means that the number of achievements of the
|
||||
* user are so high that it wrecks havoc with the Achievements calculator due to which request may time
|
||||
* out. Well this is the Ultimate Achievement
|
||||
*/
|
||||
private void showSnackBarWithRetry(boolean tooManyAchievements) {
|
||||
if (tooManyAchievements) {
|
||||
progressBar.setVisibility(View.GONE);
|
||||
ViewUtil.showDismissibleSnackBar(findViewById(android.R.id.content),
|
||||
ViewUtil.showDismissibleSnackBar(getActivity().findViewById(android.R.id.content),
|
||||
R.string.achievements_fetch_failed_ultimate_achievement, R.string.retry, view -> setAchievements());
|
||||
} else {
|
||||
progressBar.setVisibility(View.GONE);
|
||||
ViewUtil.showDismissibleSnackBar(findViewById(android.R.id.content),
|
||||
ViewUtil.showDismissibleSnackBar(getActivity().findViewById(android.R.id.content),
|
||||
R.string.achievements_fetch_failed, R.string.retry, view -> setAchievements());
|
||||
}
|
||||
}
|
||||
|
|
@ -305,7 +324,7 @@ public class AchievementsActivity extends NavigationBaseActivity {
|
|||
* Shows a generic error toast when error occurs while loading achievements or uploads
|
||||
*/
|
||||
private void onError() {
|
||||
ViewUtil.showLongToast(this, getResources().getString(R.string.error_occurred));
|
||||
ViewUtil.showLongToast(getActivity(), getResources().getString(R.string.error_occurred));
|
||||
progressBar.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
|
|
@ -355,7 +374,7 @@ public class AchievementsActivity extends NavigationBaseActivity {
|
|||
}
|
||||
|
||||
private void setZeroAchievements() {
|
||||
AlertDialog.Builder builder=new AlertDialog.Builder(this)
|
||||
AlertDialog.Builder builder=new AlertDialog.Builder(getActivity())
|
||||
.setMessage(getString(R.string.no_achievements_yet))
|
||||
.setPositiveButton(getString(R.string.ok), (dialog, which) -> {
|
||||
});
|
||||
|
|
@ -399,20 +418,10 @@ public class AchievementsActivity extends NavigationBaseActivity {
|
|||
levelUpInfoString += " " + levelInfo.getLevelNumber();
|
||||
levelNumber.setText(levelUpInfoString);
|
||||
imageView.setImageDrawable(VectorDrawableCompat.create(getResources(), R.drawable.badge,
|
||||
new ContextThemeWrapper(this, levelInfo.getLevelStyle()).getTheme()));
|
||||
new ContextThemeWrapper(getActivity(), levelInfo.getLevelStyle()).getTheme()));
|
||||
badgeText.setText(Integer.toString(levelInfo.getLevelNumber()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a way to change current activity to AchievementActivity
|
||||
* @param context
|
||||
*/
|
||||
public static void startYourself(Context context) {
|
||||
Intent intent = new Intent(context, AchievementsActivity.class);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_SINGLE_TOP);
|
||||
context.startActivity(intent);
|
||||
}
|
||||
|
||||
/**
|
||||
* to hide progressbar
|
||||
*/
|
||||
|
|
@ -447,24 +456,6 @@ public class AchievementsActivity extends NavigationBaseActivity {
|
|||
levelNumber.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
|
||||
/**
|
||||
* It display the alertDialog with Image of screenshot
|
||||
* @param screenshot
|
||||
*/
|
||||
public void showAlert(Bitmap screenshot){
|
||||
AlertDialog.Builder alertadd = new AlertDialog.Builder(AchievementsActivity.this);
|
||||
LayoutInflater factory = LayoutInflater.from(AchievementsActivity.this);
|
||||
final View view = factory.inflate(R.layout.image_alert_layout, null);
|
||||
ImageView screenShotImage = view.findViewById(R.id.alert_image);
|
||||
screenShotImage.setImageBitmap(screenshot);
|
||||
TextView shareMessage = view.findViewById(R.id.alert_text);
|
||||
shareMessage.setText(R.string.achievements_share_message);
|
||||
alertadd.setView(view);
|
||||
alertadd.setPositiveButton(R.string.about_translate_proceed, (dialog, which) -> shareScreen(screenshot));
|
||||
alertadd.setNegativeButton(android.R.string.cancel, (dialog, which) -> dialog.cancel());
|
||||
alertadd.show();
|
||||
}
|
||||
|
||||
@OnClick(R.id.images_upload_info)
|
||||
public void showUploadInfo(){
|
||||
launchAlert(getResources().getString(R.string.images_uploaded)
|
||||
|
|
@ -507,7 +498,7 @@ public class AchievementsActivity extends NavigationBaseActivity {
|
|||
* @param message
|
||||
*/
|
||||
private void launchAlert(String title, String message){
|
||||
new AlertDialog.Builder(AchievementsActivity.this)
|
||||
new AlertDialog.Builder(getActivity())
|
||||
.setTitle(title)
|
||||
.setMessage(message)
|
||||
.setCancelable(true)
|
||||
|
|
@ -524,11 +515,11 @@ public class AchievementsActivity extends NavigationBaseActivity {
|
|||
Account currentAccount = sessionManager.getCurrentAccount();
|
||||
if (currentAccount == null) {
|
||||
Timber.d("Current account is null");
|
||||
ViewUtil.showLongToast(this, getResources().getString(R.string.user_not_logged_in));
|
||||
sessionManager.forceLogin(this);
|
||||
ViewUtil.showLongToast(getActivity(), getResources().getString(R.string.user_not_logged_in));
|
||||
sessionManager.forceLogin(getActivity());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
package fr.free.nrw.commons.achievements
|
||||
package fr.free.nrw.commons.profile.achievements
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
/**
|
||||
* Represents Featured Images on WikiMedia Commons platform
|
||||
* Used by Achievements and FeedbackResponse (objects) of the user
|
||||
*/
|
||||
* Represents Featured Images on WikiMedia Commons platform
|
||||
* Used by Achievements and FeedbackResponse (objects) of the user
|
||||
*/
|
||||
class FeaturedImages(
|
||||
@field:SerializedName("Quality_images") val qualityImages: Int,
|
||||
@field:SerializedName("Featured_pictures_on_Wikimedia_Commons") val featuredPicturesOnWikimediaCommons: Int
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
package fr.free.nrw.commons.achievements
|
||||
package fr.free.nrw.commons.profile.achievements
|
||||
|
||||
/**
|
||||
* Represent the Feedback Response of the user
|
||||
*/
|
||||
* Represent the Feedback Response of the user
|
||||
*/
|
||||
data class FeedbackResponse(val uniqueUsedImages: Int,
|
||||
val articlesUsingImages: Int,
|
||||
val deletedUploads: Int,
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package fr.free.nrw.commons.achievements
|
||||
package fr.free.nrw.commons.profile.achievements
|
||||
|
||||
import fr.free.nrw.commons.R
|
||||
|
||||
|
|
@ -0,0 +1,125 @@
|
|||
package fr.free.nrw.commons.profile.leaderboard;
|
||||
|
||||
import static fr.free.nrw.commons.profile.leaderboard.LeaderboardConstants.LOADED;
|
||||
import static fr.free.nrw.commons.profile.leaderboard.LeaderboardConstants.LOADING;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
import androidx.paging.PageKeyedDataSource;
|
||||
import fr.free.nrw.commons.auth.SessionManager;
|
||||
import fr.free.nrw.commons.mwapi.OkHttpJsonApiClient;
|
||||
import io.reactivex.disposables.CompositeDisposable;
|
||||
import java.util.Objects;
|
||||
import timber.log.Timber;
|
||||
|
||||
/**
|
||||
* This class will call the leaderboard API to get new list when the pagination is performed
|
||||
*/
|
||||
public class DataSourceClass extends PageKeyedDataSource<Integer, LeaderboardList> {
|
||||
|
||||
private OkHttpJsonApiClient okHttpJsonApiClient;
|
||||
private SessionManager sessionManager;
|
||||
private MutableLiveData<String> progressLiveStatus;
|
||||
private CompositeDisposable compositeDisposable = new CompositeDisposable();
|
||||
private String duration;
|
||||
private String category;
|
||||
private int limit;
|
||||
private int offset;
|
||||
|
||||
/**
|
||||
* Initialise the Data Source Class with API params
|
||||
* @param okHttpJsonApiClient
|
||||
* @param sessionManager
|
||||
* @param duration
|
||||
* @param category
|
||||
* @param limit
|
||||
* @param offset
|
||||
*/
|
||||
public DataSourceClass(OkHttpJsonApiClient okHttpJsonApiClient,SessionManager sessionManager,
|
||||
String duration, String category, int limit, int offset) {
|
||||
this.okHttpJsonApiClient = okHttpJsonApiClient;
|
||||
this.sessionManager = sessionManager;
|
||||
this.duration = duration;
|
||||
this.category = category;
|
||||
this.limit = limit;
|
||||
this.offset = offset;
|
||||
progressLiveStatus = new MutableLiveData<>();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the status of the list
|
||||
*/
|
||||
public MutableLiveData<String> getProgressLiveStatus() {
|
||||
return progressLiveStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the initial set of data from API
|
||||
* @param params
|
||||
* @param callback
|
||||
*/
|
||||
@Override
|
||||
public void loadInitial(@NonNull LoadInitialParams<Integer> params,
|
||||
@NonNull LoadInitialCallback<Integer, LeaderboardList> callback) {
|
||||
|
||||
compositeDisposable.add(okHttpJsonApiClient
|
||||
.getLeaderboard(Objects.requireNonNull(sessionManager.getCurrentAccount()).name,
|
||||
duration, category, String.valueOf(limit), String.valueOf(offset))
|
||||
.doOnSubscribe(disposable -> {
|
||||
compositeDisposable.add(disposable);
|
||||
progressLiveStatus.postValue(LOADING);
|
||||
}).subscribe(
|
||||
response -> {
|
||||
if (response != null && response.getStatus() == 200) {
|
||||
progressLiveStatus.postValue(LOADED);
|
||||
callback.onResult(response.getLeaderboardList(), null, response.getLimit());
|
||||
}
|
||||
},
|
||||
t -> {
|
||||
Timber.e(t, "Fetching leaderboard statistics failed");
|
||||
progressLiveStatus.postValue(LOADING);
|
||||
}
|
||||
));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads any data before the inital page is loaded
|
||||
* @param params
|
||||
* @param callback
|
||||
*/
|
||||
@Override
|
||||
public void loadBefore(@NonNull LoadParams<Integer> params,
|
||||
@NonNull LoadCallback<Integer, LeaderboardList> callback) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the next set of data on scrolling with offset as the limit of the last set of data
|
||||
* @param params
|
||||
* @param callback
|
||||
*/
|
||||
@Override
|
||||
public void loadAfter(@NonNull LoadParams<Integer> params,
|
||||
@NonNull LoadCallback<Integer, LeaderboardList> callback) {
|
||||
compositeDisposable.add(okHttpJsonApiClient
|
||||
.getLeaderboard(Objects.requireNonNull(sessionManager.getCurrentAccount()).name,
|
||||
duration, category, String.valueOf(limit), String.valueOf(params.key))
|
||||
.doOnSubscribe(disposable -> {
|
||||
compositeDisposable.add(disposable);
|
||||
progressLiveStatus.postValue(LOADING);
|
||||
}).subscribe(
|
||||
response -> {
|
||||
if (response != null && response.getStatus() == 200) {
|
||||
progressLiveStatus.postValue(LOADED);
|
||||
callback.onResult(response.getLeaderboardList(), params.key + limit);
|
||||
}
|
||||
},
|
||||
t -> {
|
||||
Timber.e(t, "Fetching leaderboard statistics failed");
|
||||
progressLiveStatus.postValue(LOADING);
|
||||
}
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
package fr.free.nrw.commons.profile.leaderboard;
|
||||
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
import androidx.paging.DataSource;
|
||||
import fr.free.nrw.commons.auth.SessionManager;
|
||||
import fr.free.nrw.commons.mwapi.OkHttpJsonApiClient;
|
||||
import io.reactivex.disposables.CompositeDisposable;
|
||||
|
||||
/**
|
||||
* This class will create a new instance of the data source class on pagination
|
||||
*/
|
||||
public class DataSourceFactory extends DataSource.Factory<Integer, LeaderboardList> {
|
||||
|
||||
private MutableLiveData<DataSourceClass> liveData;
|
||||
private OkHttpJsonApiClient okHttpJsonApiClient;
|
||||
private CompositeDisposable compositeDisposable;
|
||||
private SessionManager sessionManager;
|
||||
private String duration;
|
||||
private String category;
|
||||
private int limit;
|
||||
private int offset;
|
||||
|
||||
/**
|
||||
* Gets the current set leaderboard list duration
|
||||
*/
|
||||
public String getDuration() {
|
||||
return duration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current set leaderboard duration with the new duration
|
||||
*/
|
||||
public void setDuration(final String duration) {
|
||||
this.duration = duration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current set leaderboard list category
|
||||
*/
|
||||
public String getCategory() {
|
||||
return category;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current set leaderboard category with the new category
|
||||
*/
|
||||
public void setCategory(final String category) {
|
||||
this.category = category;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current set leaderboard list limit
|
||||
*/
|
||||
public int getLimit() {
|
||||
return limit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current set leaderboard limit with the new limit
|
||||
*/
|
||||
public void setLimit(final int limit) {
|
||||
this.limit = limit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current set leaderboard list offset
|
||||
*/
|
||||
public int getOffset() {
|
||||
return offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current set leaderboard offset with the new offset
|
||||
*/
|
||||
public void setOffset(final int offset) {
|
||||
this.offset = offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for DataSourceFactory class
|
||||
* @param okHttpJsonApiClient client for OKhttp
|
||||
* @param compositeDisposable composite disposable
|
||||
* @param sessionManager sessionManager
|
||||
*/
|
||||
public DataSourceFactory(OkHttpJsonApiClient okHttpJsonApiClient, CompositeDisposable compositeDisposable,
|
||||
SessionManager sessionManager) {
|
||||
this.okHttpJsonApiClient = okHttpJsonApiClient;
|
||||
this.compositeDisposable = compositeDisposable;
|
||||
this.sessionManager = sessionManager;
|
||||
liveData = new MutableLiveData<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the live data
|
||||
*/
|
||||
public MutableLiveData<DataSourceClass> getMutableLiveData() {
|
||||
return liveData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the new instance of data source class
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public DataSource<Integer, LeaderboardList> create() {
|
||||
DataSourceClass dataSourceClass = new DataSourceClass(okHttpJsonApiClient, sessionManager, duration, category, limit, offset);
|
||||
liveData.postValue(dataSourceClass);
|
||||
return dataSourceClass;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
package fr.free.nrw.commons.profile.leaderboard;
|
||||
|
||||
/**
|
||||
* This class contains the constant variables for leaderboard
|
||||
*/
|
||||
public class LeaderboardConstants {
|
||||
|
||||
/**
|
||||
* This is the size of the page i.e. number items to load in a batch when pagination is performed
|
||||
*/
|
||||
public static final int PAGE_SIZE = 10;
|
||||
|
||||
/**
|
||||
* This is the starting offset, we set it to 0 to start loading from rank 1
|
||||
*/
|
||||
public static final int START_OFFSET = 0;
|
||||
|
||||
/**
|
||||
* This is the prefix of the user's homepage url, appending the username will give us complete url
|
||||
*/
|
||||
public static final String USER_LINK_PREFIX = "https://commons.wikimedia.org/wiki/User:";
|
||||
|
||||
/**
|
||||
* This is the a constant string for the state loading, when the pages are getting loaded we can
|
||||
* use this constant to identify if we need to show the progress bar or not
|
||||
*/
|
||||
public final static String LOADING = "Loading";
|
||||
|
||||
/**
|
||||
* This is the a constant string for the state loaded, when the pages are loaded we can
|
||||
* use this constant to identify if we need to show the progress bar or not
|
||||
*/
|
||||
public final static String LOADED = "Loaded";
|
||||
|
||||
/**
|
||||
* This API endpoint is to update the leaderboard avatar
|
||||
*/
|
||||
public final static String UPDATE_AVATAR_END_POINT = "/update_avatar.py";
|
||||
|
||||
/**
|
||||
* This API endpoint is to get leaderboard data
|
||||
*/
|
||||
public final static String LEADERBOARD_END_POINT = "/leaderboard.py";
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,277 @@
|
|||
package fr.free.nrw.commons.profile.leaderboard;
|
||||
|
||||
import static fr.free.nrw.commons.profile.leaderboard.LeaderboardConstants.LOADED;
|
||||
import static fr.free.nrw.commons.profile.leaderboard.LeaderboardConstants.LOADING;
|
||||
import static fr.free.nrw.commons.profile.leaderboard.LeaderboardConstants.PAGE_SIZE;
|
||||
import static fr.free.nrw.commons.profile.leaderboard.LeaderboardConstants.START_OFFSET;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.AdapterView.OnItemSelectedListener;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.Spinner;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.MergeAdapter;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import fr.free.nrw.commons.R;
|
||||
import fr.free.nrw.commons.auth.SessionManager;
|
||||
import fr.free.nrw.commons.di.CommonsDaggerSupportFragment;
|
||||
import fr.free.nrw.commons.mwapi.OkHttpJsonApiClient;
|
||||
import fr.free.nrw.commons.utils.ViewUtil;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.CompositeDisposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import java.util.Objects;
|
||||
import javax.inject.Inject;
|
||||
import timber.log.Timber;
|
||||
|
||||
/**
|
||||
* This class extends the CommonsDaggerSupportFragment and creates leaderboard fragment
|
||||
*/
|
||||
public class LeaderboardFragment extends CommonsDaggerSupportFragment {
|
||||
|
||||
@BindView(R.id.leaderboard_list)
|
||||
RecyclerView leaderboardListRecyclerView;
|
||||
|
||||
@BindView(R.id.progressBar)
|
||||
ProgressBar progressBar;
|
||||
|
||||
@BindView(R.id.category_spinner)
|
||||
Spinner categorySpinner;
|
||||
|
||||
@BindView(R.id.duration_spinner)
|
||||
Spinner durationSpinner;
|
||||
|
||||
@Inject
|
||||
SessionManager sessionManager;
|
||||
|
||||
@Inject
|
||||
OkHttpJsonApiClient okHttpJsonApiClient;
|
||||
|
||||
@Inject
|
||||
ViewModelFactory viewModelFactory;
|
||||
|
||||
/**
|
||||
* View model for the paged leaderboard list
|
||||
*/
|
||||
private LeaderboardListViewModel viewModel;
|
||||
|
||||
/**
|
||||
* Composite disposable for API call
|
||||
*/
|
||||
private CompositeDisposable compositeDisposable = new CompositeDisposable();
|
||||
|
||||
/**
|
||||
* Duration of the leaderboard API
|
||||
*/
|
||||
private String duration;
|
||||
|
||||
/**
|
||||
* Category of the Leaderboard API
|
||||
*/
|
||||
private String category;
|
||||
|
||||
/**
|
||||
* Page size of the leaderboard API
|
||||
*/
|
||||
private int limit = PAGE_SIZE;
|
||||
|
||||
/**
|
||||
* offset for the leaderboard API
|
||||
*/
|
||||
private int offset = START_OFFSET;
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
View rootView = inflater.inflate(R.layout.fragment_leaderboard, container, false);
|
||||
ButterKnife.bind(this, rootView);
|
||||
|
||||
progressBar.setVisibility(View.VISIBLE);
|
||||
hideLayouts();
|
||||
setSpinners();
|
||||
|
||||
/**
|
||||
* This array is for the duration filter, we have three filters weekly, yearly and all-time
|
||||
* each filter have a key and value pair, the value represents the param of the API
|
||||
*/
|
||||
String[] durationValues = getContext().getResources().getStringArray(R.array.leaderboard_duration_values);
|
||||
|
||||
/**
|
||||
* This array is for the category filter, we have three filters upload, used and nearby
|
||||
* each filter have a key and value pair, the value represents the param of the API
|
||||
*/
|
||||
String[] categoryValues = getContext().getResources().getStringArray(R.array.leaderboard_category_values);
|
||||
|
||||
duration = durationValues[0];
|
||||
category = categoryValues[0];
|
||||
|
||||
setLeaderboard(duration, category, limit, offset);
|
||||
|
||||
durationSpinner.setOnItemSelectedListener(new OnItemSelectedListener() {
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
|
||||
|
||||
duration = durationValues[durationSpinner.getSelectedItemPosition()];
|
||||
refreshLeaderboard();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> adapterView) {
|
||||
}
|
||||
});
|
||||
|
||||
categorySpinner.setOnItemSelectedListener(new OnItemSelectedListener() {
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
|
||||
category = categoryValues[categorySpinner.getSelectedItemPosition()];
|
||||
refreshLeaderboard();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> adapterView) {
|
||||
}
|
||||
});
|
||||
|
||||
return rootView;
|
||||
}
|
||||
|
||||
/**
|
||||
* Refreshes the leaderboard list
|
||||
*/
|
||||
private void refreshLeaderboard() {
|
||||
if (viewModel != null) {
|
||||
viewModel.refresh(duration, category, limit, offset);
|
||||
setLeaderboard(duration, category, limit, offset);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the spinners for the leaderboard filters
|
||||
*/
|
||||
private void setSpinners() {
|
||||
ArrayAdapter<CharSequence> categoryAdapter = ArrayAdapter.createFromResource(getContext(),
|
||||
R.array.leaderboard_categories, android.R.layout.simple_spinner_item);
|
||||
categoryAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||
categorySpinner.setAdapter(categoryAdapter);
|
||||
|
||||
ArrayAdapter<CharSequence> durationAdapter = ArrayAdapter.createFromResource(getContext(),
|
||||
R.array.leaderboard_durations, android.R.layout.simple_spinner_item);
|
||||
durationAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||
durationSpinner.setAdapter(durationAdapter);
|
||||
}
|
||||
|
||||
/**
|
||||
* To call the API to get results
|
||||
* which then sets the views using setLeaderboardUser method
|
||||
*/
|
||||
private void setLeaderboard(String duration, String category, int limit, int offset) {
|
||||
if (checkAccount()) {
|
||||
try {
|
||||
compositeDisposable.add(okHttpJsonApiClient
|
||||
.getLeaderboard(Objects.requireNonNull(sessionManager.getCurrentAccount()).name,
|
||||
duration, category, null, null)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
response -> {
|
||||
if (response != null && response.getStatus() == 200) {
|
||||
setViews(response, duration, category, limit, offset);
|
||||
}
|
||||
},
|
||||
t -> {
|
||||
Timber.e(t, "Fetching leaderboard statistics failed");
|
||||
onError();
|
||||
}
|
||||
));
|
||||
}
|
||||
catch (Exception e){
|
||||
Timber.d(e+"success");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the views
|
||||
* @param response Leaderboard Response Object
|
||||
*/
|
||||
private void setViews(LeaderboardResponse response, String duration, String category, int limit, int offset) {
|
||||
viewModel = new ViewModelProvider(this, viewModelFactory).get(LeaderboardListViewModel.class);
|
||||
viewModel.setParams(duration, category, limit, offset);
|
||||
LeaderboardListAdapter leaderboardListAdapter = new LeaderboardListAdapter();
|
||||
UserDetailAdapter userDetailAdapter= new UserDetailAdapter(response);
|
||||
MergeAdapter mergeAdapter = new MergeAdapter(userDetailAdapter, leaderboardListAdapter);
|
||||
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext());
|
||||
leaderboardListRecyclerView.setLayoutManager(linearLayoutManager);
|
||||
leaderboardListRecyclerView.setAdapter(mergeAdapter);
|
||||
viewModel.getListLiveData().observe(getViewLifecycleOwner(), leaderboardListAdapter::submitList);
|
||||
viewModel.getProgressLoadStatus().observe(getViewLifecycleOwner(), status -> {
|
||||
if (Objects.requireNonNull(status).equalsIgnoreCase(LOADING)) {
|
||||
showProgressBar();
|
||||
} else if (status.equalsIgnoreCase(LOADED)) {
|
||||
hideProgressBar();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* to hide progressbar
|
||||
*/
|
||||
private void hideProgressBar() {
|
||||
if (progressBar != null) {
|
||||
progressBar.setVisibility(View.GONE);
|
||||
categorySpinner.setVisibility(View.VISIBLE);
|
||||
durationSpinner.setVisibility(View.VISIBLE);
|
||||
leaderboardListRecyclerView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* to show progressbar
|
||||
*/
|
||||
private void showProgressBar() {
|
||||
if (progressBar != null) {
|
||||
progressBar.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* used to hide the layouts while fetching results from api
|
||||
*/
|
||||
private void hideLayouts(){
|
||||
categorySpinner.setVisibility(View.INVISIBLE);
|
||||
durationSpinner.setVisibility(View.INVISIBLE);
|
||||
leaderboardListRecyclerView.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
|
||||
/**
|
||||
* check to ensure that user is logged in
|
||||
* @return
|
||||
*/
|
||||
private boolean checkAccount(){
|
||||
Account currentAccount = sessionManager.getCurrentAccount();
|
||||
if (currentAccount == null) {
|
||||
Timber.d("Current account is null");
|
||||
ViewUtil.showLongToast(getActivity(), getResources().getString(R.string.user_not_logged_in));
|
||||
sessionManager.forceLogin(getActivity());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows a generic error toast when error occurs while loading leaderboard
|
||||
*/
|
||||
private void onError() {
|
||||
ViewUtil.showLongToast(getActivity(), getResources().getString(R.string.error_occurred));
|
||||
progressBar.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,137 @@
|
|||
package fr.free.nrw.commons.profile.leaderboard;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.DiffUtil;
|
||||
import androidx.recyclerview.widget.DiffUtil.ItemCallback;
|
||||
import com.google.gson.annotations.Expose;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* This class represents the leaderboard API response sub part of i.e. leaderboard list
|
||||
* The leaderboard list will contain the ranking of the users from 1 to n,
|
||||
* avatars, username and count in the selected category.
|
||||
*/
|
||||
public class LeaderboardList {
|
||||
|
||||
/**
|
||||
* Username of the user
|
||||
* Example value - Syced
|
||||
*/
|
||||
@SerializedName("username")
|
||||
@Expose
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* Count in the category
|
||||
* Example value - 10
|
||||
*/
|
||||
@SerializedName("category_count")
|
||||
@Expose
|
||||
private Integer categoryCount;
|
||||
|
||||
/**
|
||||
* URL of the avatar of user
|
||||
* Example value = https://upload.wikimedia.org/wikipedia/commons/thumb/0/0a/Gnome-stock_person.svg/200px-Gnome-stock_person.svg.png
|
||||
*/
|
||||
@SerializedName("avatar")
|
||||
@Expose
|
||||
private String avatar;
|
||||
|
||||
/**
|
||||
* Rank of the user
|
||||
* Example value - 1
|
||||
*/
|
||||
@SerializedName("rank")
|
||||
@Expose
|
||||
private Integer rank;
|
||||
|
||||
/**
|
||||
* @return the username of the user in the leaderboard list
|
||||
*/
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the username of the user in the leaderboard list
|
||||
*/
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the category count of the user in the leaderboard list
|
||||
*/
|
||||
public Integer getCategoryCount() {
|
||||
return categoryCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the category count of the user in the leaderboard list
|
||||
*/
|
||||
public void setCategoryCount(Integer categoryCount) {
|
||||
this.categoryCount = categoryCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the avatar of the user in the leaderboard list
|
||||
*/
|
||||
public String getAvatar() {
|
||||
return avatar;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the avatar of the user in the leaderboard list
|
||||
*/
|
||||
public void setAvatar(String avatar) {
|
||||
this.avatar = avatar;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the rank of the user in the leaderboard list
|
||||
*/
|
||||
public Integer getRank() {
|
||||
return rank;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the rank of the user in the leaderboard list
|
||||
*/
|
||||
public void setRank(Integer rank) {
|
||||
this.rank = rank;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method checks for the diff in the callbacks for paged lists
|
||||
*/
|
||||
public static DiffUtil.ItemCallback<LeaderboardList> DIFF_CALLBACK =
|
||||
new ItemCallback<LeaderboardList>() {
|
||||
@Override
|
||||
public boolean areItemsTheSame(@NonNull LeaderboardList oldItem,
|
||||
@NonNull LeaderboardList newItem) {
|
||||
return newItem == oldItem;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areContentsTheSame(@NonNull LeaderboardList oldItem,
|
||||
@NonNull LeaderboardList newItem) {
|
||||
return newItem.getRank().equals(oldItem.getRank());
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if two objects are equal, false otherwise
|
||||
* @param obj
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
|
||||
LeaderboardList leaderboardList = (LeaderboardList) obj;
|
||||
return leaderboardList.getRank().equals(this.getRank());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
package fr.free.nrw.commons.profile.leaderboard;
|
||||
|
||||
import static fr.free.nrw.commons.profile.leaderboard.LeaderboardConstants.USER_LINK_PREFIX;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.paging.PagedListAdapter;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import com.facebook.drawee.view.SimpleDraweeView;
|
||||
import fr.free.nrw.commons.R;
|
||||
import fr.free.nrw.commons.Utils;
|
||||
|
||||
/**
|
||||
* This class extends RecyclerView.Adapter and creates the List section of the leaderboard
|
||||
*/
|
||||
public class LeaderboardListAdapter extends PagedListAdapter<LeaderboardList, LeaderboardListAdapter.ListViewHolder> {
|
||||
|
||||
protected LeaderboardListAdapter() {
|
||||
super(LeaderboardList.DIFF_CALLBACK);
|
||||
}
|
||||
|
||||
public class ListViewHolder extends RecyclerView.ViewHolder {
|
||||
TextView rank;
|
||||
SimpleDraweeView avatar;
|
||||
TextView username;
|
||||
TextView count;
|
||||
|
||||
public ListViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
this.rank = itemView.findViewById(R.id.user_rank);
|
||||
this.avatar = itemView.findViewById(R.id.user_avatar);
|
||||
this.username = itemView.findViewById(R.id.user_name);
|
||||
this.count = itemView.findViewById(R.id.user_count);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will return the Context
|
||||
* @return Context
|
||||
*/
|
||||
public Context getContext() {
|
||||
return itemView.getContext();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the onCreateViewHolder and inflates the recyclerview list item layout
|
||||
* @param parent
|
||||
* @param viewType
|
||||
* @return
|
||||
*/
|
||||
@NonNull
|
||||
@Override
|
||||
public LeaderboardListAdapter.ListViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
View view = LayoutInflater.from(parent.getContext())
|
||||
.inflate(R.layout.leaderboard_list_element, parent, false);
|
||||
|
||||
return new ListViewHolder(view);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the onBindViewHolder Set the view at the specific position with the specific value
|
||||
* @param holder
|
||||
* @param position
|
||||
*/
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull LeaderboardListAdapter.ListViewHolder holder, int position) {
|
||||
TextView rank = holder.rank;
|
||||
SimpleDraweeView avatar = holder.avatar;
|
||||
TextView username = holder.username;
|
||||
TextView count = holder.count;
|
||||
|
||||
rank.setText(getItem(position).getRank().toString());
|
||||
|
||||
avatar.setImageURI(Uri.parse(getItem(position).getAvatar()));
|
||||
username.setText(getItem(position).getUsername());
|
||||
count.setText(getItem(position).getCategoryCount().toString());
|
||||
|
||||
/*
|
||||
Open the user profile in a webview when a username is clicked on leaderboard
|
||||
*/
|
||||
holder.itemView.setOnClickListener(view -> Utils.handleWebUrl(holder.getContext(), Uri.parse(
|
||||
String.format("%s%s", USER_LINK_PREFIX, getItem(position).getUsername()))));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,107 @@
|
|||
package fr.free.nrw.commons.profile.leaderboard;
|
||||
|
||||
import static fr.free.nrw.commons.profile.leaderboard.LeaderboardConstants.PAGE_SIZE;
|
||||
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
import androidx.lifecycle.Transformations;
|
||||
import androidx.lifecycle.ViewModel;
|
||||
import androidx.paging.LivePagedListBuilder;
|
||||
import androidx.paging.PagedList;
|
||||
import fr.free.nrw.commons.auth.SessionManager;
|
||||
import fr.free.nrw.commons.mwapi.OkHttpJsonApiClient;
|
||||
import io.reactivex.disposables.CompositeDisposable;
|
||||
|
||||
/**
|
||||
* Extends the ViewModel class and creates the LeaderboardList View Model
|
||||
*/
|
||||
public class LeaderboardListViewModel extends ViewModel {
|
||||
|
||||
private DataSourceFactory dataSourceFactory;
|
||||
private LiveData<PagedList<LeaderboardList>> listLiveData;
|
||||
private CompositeDisposable compositeDisposable = new CompositeDisposable();
|
||||
private LiveData<String> progressLoadStatus = new MutableLiveData<>();
|
||||
|
||||
/**
|
||||
* Constructor for a new LeaderboardListViewModel
|
||||
* @param okHttpJsonApiClient
|
||||
* @param sessionManager
|
||||
*/
|
||||
public LeaderboardListViewModel(OkHttpJsonApiClient okHttpJsonApiClient, SessionManager
|
||||
sessionManager) {
|
||||
|
||||
dataSourceFactory = new DataSourceFactory(okHttpJsonApiClient,
|
||||
compositeDisposable, sessionManager);
|
||||
initializePaging();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initialises the paging
|
||||
*/
|
||||
private void initializePaging() {
|
||||
|
||||
PagedList.Config pagedListConfig =
|
||||
new PagedList.Config.Builder()
|
||||
.setEnablePlaceholders(false)
|
||||
.setInitialLoadSizeHint(PAGE_SIZE)
|
||||
.setPageSize(PAGE_SIZE).build();
|
||||
|
||||
listLiveData = new LivePagedListBuilder<>(dataSourceFactory, pagedListConfig)
|
||||
.build();
|
||||
|
||||
progressLoadStatus = Transformations
|
||||
.switchMap(dataSourceFactory.getMutableLiveData(), DataSourceClass::getProgressLiveStatus);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Refreshes the paged list with the new params and starts the loading of new data
|
||||
* @param duration
|
||||
* @param category
|
||||
* @param limit
|
||||
* @param offset
|
||||
*/
|
||||
public void refresh(String duration, String category, int limit, int offset) {
|
||||
dataSourceFactory.setDuration(duration);
|
||||
dataSourceFactory.setCategory(category);
|
||||
dataSourceFactory.setLimit(limit);
|
||||
dataSourceFactory.setOffset(offset);
|
||||
dataSourceFactory.getMutableLiveData().getValue().invalidate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the new params for the paged list API calls
|
||||
* @param duration
|
||||
* @param category
|
||||
* @param limit
|
||||
* @param offset
|
||||
*/
|
||||
public void setParams(String duration, String category, int limit, int offset) {
|
||||
dataSourceFactory.setDuration(duration);
|
||||
dataSourceFactory.setCategory(category);
|
||||
dataSourceFactory.setLimit(limit);
|
||||
dataSourceFactory.setOffset(offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the loading status of paged list
|
||||
*/
|
||||
public LiveData<String> getProgressLoadStatus() {
|
||||
return progressLoadStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the paged list with live data
|
||||
*/
|
||||
public LiveData<PagedList<LeaderboardList>> getListLiveData() {
|
||||
return listLiveData;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCleared() {
|
||||
super.onCleared();
|
||||
compositeDisposable.clear();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,237 @@
|
|||
package fr.free.nrw.commons.profile.leaderboard;
|
||||
|
||||
import java.util.List;
|
||||
import com.google.gson.annotations.Expose;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* GSON Response Class for Leaderboard API response
|
||||
*/
|
||||
public class LeaderboardResponse {
|
||||
|
||||
/**
|
||||
* Status Code returned from the API
|
||||
* Example value - 200
|
||||
*/
|
||||
@SerializedName("status")
|
||||
@Expose
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* Username returned from the API
|
||||
* Example value - Syced
|
||||
*/
|
||||
@SerializedName("username")
|
||||
@Expose
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* Category count returned from the API
|
||||
* Example value - 10
|
||||
*/
|
||||
@SerializedName("category_count")
|
||||
@Expose
|
||||
private Integer categoryCount;
|
||||
|
||||
/**
|
||||
* Limit returned from the API
|
||||
* Example value - 10
|
||||
*/
|
||||
@SerializedName("limit")
|
||||
@Expose
|
||||
private int limit;
|
||||
|
||||
/**
|
||||
* Avatar returned from the API
|
||||
* Example value - https://upload.wikimedia.org/wikipedia/commons/thumb/0/0a/Gnome-stock_person.svg/200px-Gnome-stock_person.svg.png
|
||||
*/
|
||||
@SerializedName("avatar")
|
||||
@Expose
|
||||
private String avatar;
|
||||
|
||||
/**
|
||||
* Offset returned from the API
|
||||
* Example value - 0
|
||||
*/
|
||||
@SerializedName("offset")
|
||||
@Expose
|
||||
private int offset;
|
||||
|
||||
/**
|
||||
* Duration returned from the API
|
||||
* Example value - yearly
|
||||
*/
|
||||
@SerializedName("duration")
|
||||
@Expose
|
||||
private String duration;
|
||||
|
||||
/**
|
||||
* Leaderboard list returned from the API
|
||||
* Example value - [{
|
||||
* "username": "Fæ",
|
||||
* "category_count": 107147,
|
||||
* "avatar": "https://upload.wikimedia.org/wikipedia/commons/thumb/0/0a/Gnome-stock_person.svg/200px-Gnome-stock_person.svg.png",
|
||||
* "rank": 1
|
||||
* }]
|
||||
*/
|
||||
@SerializedName("leaderboard_list")
|
||||
@Expose
|
||||
private List<LeaderboardList> leaderboardList = null;
|
||||
|
||||
/**
|
||||
* Category returned from the API
|
||||
* Example value - upload
|
||||
*/
|
||||
@SerializedName("category")
|
||||
@Expose
|
||||
private String category;
|
||||
|
||||
/**
|
||||
* Rank returned from the API
|
||||
* Example value - 1
|
||||
*/
|
||||
@SerializedName("rank")
|
||||
@Expose
|
||||
private Integer rank;
|
||||
|
||||
/**
|
||||
* @return the status code
|
||||
*/
|
||||
public Integer getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the status code
|
||||
*/
|
||||
public void setStatus(Integer status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the username
|
||||
*/
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the username
|
||||
*/
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the category count
|
||||
*/
|
||||
public Integer getCategoryCount() {
|
||||
return categoryCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the category count
|
||||
*/
|
||||
public void setCategoryCount(Integer categoryCount) {
|
||||
this.categoryCount = categoryCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the limit
|
||||
*/
|
||||
public int getLimit() {
|
||||
return limit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the limit
|
||||
*/
|
||||
public void setLimit(int limit) {
|
||||
this.limit = limit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the avatar
|
||||
*/
|
||||
public String getAvatar() {
|
||||
return avatar;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the avatar
|
||||
*/
|
||||
public void setAvatar(String avatar) {
|
||||
this.avatar = avatar;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the offset
|
||||
*/
|
||||
public int getOffset() {
|
||||
return offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the offset
|
||||
*/
|
||||
public void setOffset(int offset) {
|
||||
this.offset = offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the duration
|
||||
*/
|
||||
public String getDuration() {
|
||||
return duration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the duration
|
||||
*/
|
||||
public void setDuration(String duration) {
|
||||
this.duration = duration;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the leaderboard list
|
||||
*/
|
||||
public List<LeaderboardList> getLeaderboardList() {
|
||||
return leaderboardList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the leaderboard list
|
||||
*/
|
||||
public void setLeaderboardList(List<LeaderboardList> leaderboardList) {
|
||||
this.leaderboardList = leaderboardList;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the category
|
||||
*/
|
||||
public String getCategory() {
|
||||
return category;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the category
|
||||
*/
|
||||
public void setCategory(String category) {
|
||||
this.category = category;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the rank
|
||||
*/
|
||||
public Integer getRank() {
|
||||
return rank;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the rank
|
||||
*/
|
||||
public void setRank(Integer rank) {
|
||||
this.rank = rank;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
package fr.free.nrw.commons.profile.leaderboard;
|
||||
|
||||
import com.google.gson.annotations.Expose;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* GSON Response Class for Update Avatar API response
|
||||
*/
|
||||
public class UpdateAvatarResponse {
|
||||
|
||||
/**
|
||||
* Status Code returned from the API
|
||||
* Example value - 200
|
||||
*/
|
||||
@SerializedName("status")
|
||||
@Expose
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* Message returned from the API
|
||||
* Example value - Avatar Updated
|
||||
*/
|
||||
@SerializedName("message")
|
||||
@Expose
|
||||
private String message;
|
||||
|
||||
/**
|
||||
* Username returned from the API
|
||||
* Example value - Syced
|
||||
*/
|
||||
@SerializedName("user")
|
||||
@Expose
|
||||
private String user;
|
||||
|
||||
/**
|
||||
* @return the status code
|
||||
*/
|
||||
public String getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the status code
|
||||
*/
|
||||
public void setStatus(String status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the message
|
||||
*/
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the message
|
||||
*/
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the username
|
||||
*/
|
||||
public String getUser() {
|
||||
return user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the username
|
||||
*/
|
||||
public void setUser(String user) {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
package fr.free.nrw.commons.profile.leaderboard;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
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 com.facebook.drawee.view.SimpleDraweeView;
|
||||
import fr.free.nrw.commons.R;
|
||||
|
||||
/**
|
||||
* This class extends RecyclerView.Adapter and creates the UserDetail section of the leaderboard
|
||||
*/
|
||||
public class UserDetailAdapter extends RecyclerView.Adapter<UserDetailAdapter.DataViewHolder> {
|
||||
|
||||
private LeaderboardResponse leaderboardResponse;
|
||||
|
||||
public UserDetailAdapter(LeaderboardResponse leaderboardResponse) {
|
||||
this.leaderboardResponse = leaderboardResponse;
|
||||
}
|
||||
|
||||
public class DataViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
private TextView rank;
|
||||
private SimpleDraweeView avatar;
|
||||
private TextView username;
|
||||
private TextView count;
|
||||
|
||||
public DataViewHolder(@NonNull View itemView) {
|
||||
super(itemView);
|
||||
this.rank = itemView.findViewById(R.id.rank);
|
||||
this.avatar = itemView.findViewById(R.id.avatar);
|
||||
this.username = itemView.findViewById(R.id.username);
|
||||
this.count = itemView.findViewById(R.id.count);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will return the Context
|
||||
* @return Context
|
||||
*/
|
||||
public Context getContext() {
|
||||
return itemView.getContext();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the onCreateViewHolder and sets the view with leaderboard user element layout
|
||||
* @param parent
|
||||
* @param viewType
|
||||
* @return
|
||||
*/
|
||||
@NonNull
|
||||
@Override
|
||||
public UserDetailAdapter.DataViewHolder onCreateViewHolder(@NonNull ViewGroup parent,
|
||||
int viewType) {
|
||||
View view = LayoutInflater.from(parent.getContext())
|
||||
.inflate(R.layout.leaderboard_user_element, parent, false);
|
||||
return new DataViewHolder(view);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the onBindViewHolder Set the view at the specific position with the specific value
|
||||
* @param holder
|
||||
* @param position
|
||||
*/
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull UserDetailAdapter.DataViewHolder holder, int position) {
|
||||
TextView rank = holder.rank;
|
||||
SimpleDraweeView avatar = holder.avatar;
|
||||
TextView username = holder.username;
|
||||
TextView count = holder.count;
|
||||
|
||||
rank.setText(String.format("%s %d",
|
||||
holder.getContext().getResources().getString(R.string.rank_prefix),
|
||||
leaderboardResponse.getRank()));
|
||||
|
||||
avatar.setImageURI(
|
||||
Uri.parse(leaderboardResponse.getAvatar()));
|
||||
username.setText(leaderboardResponse.getUsername());
|
||||
count.setText(String.format("%s %d",
|
||||
holder.getContext().getResources().getString(R.string.count_prefix),
|
||||
leaderboardResponse.getCategoryCount()));
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
package fr.free.nrw.commons.profile.leaderboard;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.lifecycle.ViewModel;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import fr.free.nrw.commons.auth.SessionManager;
|
||||
import fr.free.nrw.commons.mwapi.OkHttpJsonApiClient;
|
||||
import javax.inject.Inject;
|
||||
|
||||
/**
|
||||
* This class extends the ViewModelProvider.Factory and creates a ViewModelFactory class
|
||||
* for leaderboardListViewModel
|
||||
*/
|
||||
public class ViewModelFactory implements ViewModelProvider.Factory {
|
||||
|
||||
private OkHttpJsonApiClient okHttpJsonApiClient;
|
||||
private SessionManager sessionManager;
|
||||
|
||||
|
||||
@Inject
|
||||
public ViewModelFactory(OkHttpJsonApiClient okHttpJsonApiClient, SessionManager sessionManager) {
|
||||
this.okHttpJsonApiClient = okHttpJsonApiClient;
|
||||
this.sessionManager = sessionManager;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creats a new LeaderboardListViewModel
|
||||
* @param modelClass
|
||||
* @param <T>
|
||||
* @return
|
||||
*/
|
||||
@NonNull
|
||||
@Override
|
||||
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
|
||||
if (modelClass.isAssignableFrom(LeaderboardListViewModel.class)) {
|
||||
return (T) new LeaderboardListViewModel(okHttpJsonApiClient, sessionManager);
|
||||
}
|
||||
throw new IllegalArgumentException("Unknown class name");
|
||||
}
|
||||
}
|
||||
|
|
@ -26,6 +26,7 @@ import androidx.drawerlayout.widget.DrawerLayout;
|
|||
|
||||
import com.google.android.material.navigation.NavigationView;
|
||||
|
||||
import fr.free.nrw.commons.profile.ProfileActivity;
|
||||
import org.wikipedia.dataclient.Service;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
|
@ -37,7 +38,6 @@ import fr.free.nrw.commons.BuildConfig;
|
|||
import fr.free.nrw.commons.CommonsApplication;
|
||||
import fr.free.nrw.commons.R;
|
||||
import fr.free.nrw.commons.WelcomeActivity;
|
||||
import fr.free.nrw.commons.achievements.AchievementsActivity;
|
||||
import fr.free.nrw.commons.auth.LoginActivity;
|
||||
import fr.free.nrw.commons.auth.LogoutClient;
|
||||
import fr.free.nrw.commons.bookmarks.BookmarksActivity;
|
||||
|
|
@ -140,7 +140,7 @@ public abstract class NavigationBaseActivity extends BaseActivity
|
|||
LinearLayout userIcon = navHeaderView.findViewById(R.id.user_details);
|
||||
userIcon.setOnClickListener(v -> {
|
||||
drawerLayout.closeDrawer(navigationView);
|
||||
AchievementsActivity.startYourself(NavigationBaseActivity.this);
|
||||
ProfileActivity.startYourself(NavigationBaseActivity.this);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,11 +7,9 @@ import android.graphics.Bitmap;
|
|||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Color;
|
||||
import android.net.Uri;
|
||||
|
||||
import androidx.annotation.IntDef;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.exifinterface.media.ExifInterface;
|
||||
|
||||
import com.facebook.common.executors.CallerThreadExecutor;
|
||||
import com.facebook.common.references.CloseableReference;
|
||||
import com.facebook.datasource.DataSource;
|
||||
|
|
@ -21,13 +19,15 @@ import com.facebook.imagepipeline.datasource.BaseBitmapDataSubscriber;
|
|||
import com.facebook.imagepipeline.image.CloseableImage;
|
||||
import com.facebook.imagepipeline.request.ImageRequest;
|
||||
import com.facebook.imagepipeline.request.ImageRequestBuilder;
|
||||
|
||||
import fr.free.nrw.commons.R;
|
||||
import fr.free.nrw.commons.location.LatLng;
|
||||
import fr.free.nrw.commons.mwapi.OkHttpJsonApiClient;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.CompositeDisposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import java.io.IOException;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
import fr.free.nrw.commons.R;
|
||||
import fr.free.nrw.commons.location.LatLng;
|
||||
import timber.log.Timber;
|
||||
|
||||
/**
|
||||
|
|
@ -69,7 +69,9 @@ public class ImageUtils {
|
|||
public static final int FILE_NAME_EXISTS = -4;
|
||||
static final int NO_CATEGORY_SELECTED = -5;
|
||||
|
||||
private static ProgressDialog progressDialog;
|
||||
private static ProgressDialog progressDialogWallpaper;
|
||||
|
||||
private static ProgressDialog progressDialogAvatar;
|
||||
|
||||
@IntDef(
|
||||
flag = true,
|
||||
|
|
@ -223,28 +225,78 @@ public class ImageUtils {
|
|||
}, CallerThreadExecutor.getInstance());
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the set avatar api to set the image url as user's avatar
|
||||
* @param context
|
||||
* @param url
|
||||
* @param username
|
||||
* @param okHttpJsonApiClient
|
||||
* @param compositeDisposable
|
||||
*/
|
||||
public static void setAvatarFromImageUrl(Context context, String url, String username,
|
||||
OkHttpJsonApiClient okHttpJsonApiClient, CompositeDisposable compositeDisposable) {
|
||||
showSettingAvatarProgressBar(context);
|
||||
|
||||
try {
|
||||
compositeDisposable.add(okHttpJsonApiClient
|
||||
.setAvatar(username, url)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
response -> {
|
||||
if (response != null && response.getStatus().equals("200")) {
|
||||
ViewUtil.showLongToast(context, context.getString(R.string.avatar_set_successfully));
|
||||
if (progressDialogAvatar != null && progressDialogAvatar.isShowing()) {
|
||||
progressDialogAvatar.dismiss();
|
||||
}
|
||||
}
|
||||
},
|
||||
t -> {
|
||||
Timber.e(t, "Setting Avatar Failed");
|
||||
ViewUtil.showLongToast(context, context.getString(R.string.avatar_set_unsuccessfully));
|
||||
if (progressDialogAvatar != null) {
|
||||
progressDialogAvatar.cancel();
|
||||
}
|
||||
}
|
||||
));
|
||||
}
|
||||
catch (Exception e){
|
||||
Timber.d(e+"success");
|
||||
ViewUtil.showLongToast(context, context.getString(R.string.avatar_set_unsuccessfully));
|
||||
if (progressDialogAvatar != null) {
|
||||
progressDialogAvatar.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static void setWallpaper(Context context, Bitmap bitmap) {
|
||||
WallpaperManager wallpaperManager = WallpaperManager.getInstance(context);
|
||||
try {
|
||||
wallpaperManager.setBitmap(bitmap);
|
||||
ViewUtil.showLongToast(context, context.getString(R.string.wallpaper_set_successfully));
|
||||
if (progressDialog != null && progressDialog.isShowing()) {
|
||||
progressDialog.dismiss();
|
||||
if (progressDialogWallpaper != null && progressDialogWallpaper.isShowing()) {
|
||||
progressDialogWallpaper.dismiss();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Timber.e(e, "Error setting wallpaper");
|
||||
ViewUtil.showLongToast(context, context.getString(R.string.wallpaper_set_unsuccessfully));
|
||||
if (progressDialog != null) {
|
||||
progressDialog.cancel();
|
||||
if (progressDialogWallpaper != null) {
|
||||
progressDialogWallpaper.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void showSettingWallpaperProgressBar(Context context) {
|
||||
progressDialog = ProgressDialog.show(context, context.getString(R.string.setting_wallpaper_dialog_title),
|
||||
progressDialogWallpaper = ProgressDialog.show(context, context.getString(R.string.setting_wallpaper_dialog_title),
|
||||
context.getString(R.string.setting_wallpaper_dialog_message), true);
|
||||
}
|
||||
|
||||
private static void showSettingAvatarProgressBar(Context context) {
|
||||
progressDialogAvatar = ProgressDialog.show(context, context.getString(R.string.setting_avatar_dialog_title),
|
||||
context.getString(R.string.setting_avatar_dialog_message), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Result variable is a result of an or operation of all possible problems. Ie. if result
|
||||
* is 0001 means IMAGE_DARK
|
||||
|
|
|
|||
|
|
@ -1,495 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/drawer_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<LinearLayout
|
||||
android:id="@+id/toolbarLayout"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="?attr/actionBarSize">
|
||||
<include layout="@layout/toolbar"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="?attr/actionBarSize"
|
||||
android:layout_below="@id/toolbarLayout">
|
||||
|
||||
<ScrollView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/toolbar"
|
||||
android:background="?attr/achievementBackground"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
style="?android:textAppearanceLarge"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginStart="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginTop="@dimen/activity_margin_horizontal"
|
||||
android:text="@string/level"
|
||||
android:id="@+id/achievement_level"
|
||||
android:textAllCaps="true"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/achievement_info"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/activity_margin_vertical"
|
||||
android:layout_marginRight="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginEnd="@dimen/activity_margin_horizontal"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
app:srcCompat="@drawable/ic_info_outline_24dp"
|
||||
android:tint="@color/black"
|
||||
android:layout_marginVertical="@dimen/activity_margin_vertical" />
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/badge_layout"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/achievement_info"
|
||||
android:layout_centerHorizontal="true">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/achievement_badge_image"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:srcCompat="@drawable/badge" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/achievement_badge_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAlignment="center"
|
||||
android:textColor="@color/achievement_badge_text"
|
||||
android:textSize="75sp"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/achievement_badge_image"
|
||||
app:layout_constraintEnd_toEndOf="@+id/achievement_badge_image"
|
||||
app:layout_constraintStart_toStartOf="@+id/achievement_badge_image"
|
||||
app:layout_constraintTop_toTopOf="@+id/achievement_badge_image"
|
||||
app:layout_constraintVertical_bias="0.58" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/layout_image_uploaded"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/badge_layout"
|
||||
android:layout_marginEnd="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginRight="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginStart="@dimen/activity_margin_horizontal">
|
||||
|
||||
<TextView
|
||||
style="?android:textAppearanceMedium"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginStart="@dimen/activity_margin_horizontal"
|
||||
android:id="@+id/images_upload_text_param"
|
||||
android:layout_marginTop="@dimen/achievements_activity_margin_vertical"
|
||||
android:text="@string/images_uploaded" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="@dimen/quarter_standard_height"
|
||||
android:layout_height="@dimen/quarter_standard_height"
|
||||
android:id="@+id/images_upload_info"
|
||||
android:layout_marginTop="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginRight="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginEnd="@dimen/activity_margin_horizontal"
|
||||
android:layout_toRightOf="@+id/images_upload_text_param"
|
||||
android:layout_toEndOf="@+id/images_upload_text_param"
|
||||
app:srcCompat="@drawable/ic_info_outline_24dp"
|
||||
android:tint="@color/primaryDarkColor"
|
||||
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginStart="@dimen/activity_margin_horizontal"/>
|
||||
|
||||
<com.dinuscxj.progressbar.CircleProgressBar
|
||||
android:layout_width="@dimen/dimen_40"
|
||||
android:layout_height="@dimen/dimen_40"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_marginEnd="@dimen/large_gap"
|
||||
android:layout_marginRight="@dimen/large_gap"
|
||||
android:id="@+id/images_uploaded_progressbar"
|
||||
android:progress="50"
|
||||
app:progress_text_size="@dimen/progressbar_text"
|
||||
app:progress_end_color="#8C8B98"
|
||||
app:progress_start_color="#3A3381"
|
||||
app:progress_stroke_width="@dimen/progressbar_stroke"
|
||||
app:progress_text_format_pattern="573/110"
|
||||
app:progress_text_color="@color/secondaryColor"
|
||||
app:style="solid_line" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/layout_image_reverts"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/tiny_margin"
|
||||
android:layout_below="@+id/layout_image_uploaded"
|
||||
android:layout_marginEnd="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginRight="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginStart="@dimen/activity_margin_horizontal">
|
||||
|
||||
<TextView
|
||||
style="?android:textAppearanceMedium"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
||||
android:id="@+id/images_reverted_text"
|
||||
android:layout_marginStart="@dimen/activity_margin_horizontal"
|
||||
android:text="@string/image_reverts" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="@dimen/medium_width"
|
||||
android:layout_height="@dimen/medium_height"
|
||||
android:layout_marginTop="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginRight="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginEnd="@dimen/activity_margin_horizontal"
|
||||
android:id="@+id/images_reverted_info"
|
||||
android:layout_toRightOf="@+id/images_reverted_text"
|
||||
android:layout_toEndOf="@+id/images_reverted_text"
|
||||
app:srcCompat="@drawable/ic_info_outline_24dp"
|
||||
android:tint="@color/primaryDarkColor"
|
||||
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginStart="@dimen/activity_margin_horizontal"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/achievements_revert_limit_message"
|
||||
android:textSize="@dimen/small_text"
|
||||
android:id="@+id/images_revert_limit_text"
|
||||
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginStart="@dimen/activity_margin_horizontal"
|
||||
android:layout_below="@+id/images_reverted_text"/>
|
||||
|
||||
<com.dinuscxj.progressbar.CircleProgressBar
|
||||
android:layout_width="@dimen/dimen_40"
|
||||
android:layout_height="@dimen/dimen_40"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_marginRight="@dimen/large_gap"
|
||||
android:layout_marginEnd="@dimen/large_gap"
|
||||
android:progress="50"
|
||||
android:id="@+id/image_reverts_progressbar"
|
||||
app:progress_end_color="#8C8B98"
|
||||
app:progress_start_color="#3A3381"
|
||||
app:progress_text_size="@dimen/progressbar_text"
|
||||
app:progress_stroke_width="@dimen/progressbar_stroke"
|
||||
app:progress_text_format_pattern="92%%"
|
||||
app:progress_text_color="@color/secondaryColor"
|
||||
app:style="solid_line" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/layout_image_used_by_wiki"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/tiny_margin"
|
||||
android:layout_below="@+id/layout_image_reverts"
|
||||
android:layout_marginBottom="@dimen/activity_margin_vertical"
|
||||
android:layout_marginEnd="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginRight="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginStart="@dimen/activity_margin_horizontal">
|
||||
|
||||
<TextView
|
||||
style="?android:textAppearanceMedium"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/images_used_by_wiki_text"
|
||||
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginStart="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginTop="@dimen/achievements_activity_margin_vertical"
|
||||
android:text="@string/images_used_by_wiki" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="@dimen/medium_width"
|
||||
android:layout_height="@dimen/medium_height"
|
||||
android:id="@+id/images_used_by_wiki_info"
|
||||
android:layout_marginTop="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginRight="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginEnd="@dimen/activity_margin_horizontal"
|
||||
android:layout_toRightOf="@+id/images_used_by_wiki_text"
|
||||
android:layout_toEndOf="@+id/images_used_by_wiki_text"
|
||||
app:srcCompat="@drawable/ic_info_outline_24dp"
|
||||
android:tint="@color/primaryDarkColor"
|
||||
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginStart="@dimen/activity_margin_horizontal"/>
|
||||
|
||||
<com.dinuscxj.progressbar.CircleProgressBar
|
||||
android:layout_width="@dimen/dimen_40"
|
||||
android:layout_height="@dimen/dimen_40"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_marginRight="@dimen/large_gap"
|
||||
android:layout_marginEnd="@dimen/large_gap"
|
||||
android:progress="50"
|
||||
app:progress_text_size="@dimen/progressbar_text"
|
||||
android:id="@+id/images_used_by_wiki_progress_bar"
|
||||
app:progress_end_color="#8C8B98"
|
||||
app:progress_start_color="#3A3381"
|
||||
app:progress_stroke_width="2.5dp"
|
||||
app:progress_text_color="@color/secondaryColor"
|
||||
app:progress_text_format_pattern="12/24"
|
||||
app:style="solid_line" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progressBar"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/layout_statistics"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/statistics"
|
||||
style="?android:textAppearanceLarge"
|
||||
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginStart="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginTop="@dimen/activity_margin_vertical"
|
||||
android:textAllCaps="true"/>
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginRight="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginEnd="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginStart="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginTop="@dimen/activity_margin_horizontal">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_toStartOf="@+id/wikidata_edits"
|
||||
android:layout_toLeftOf="@+id/wikidata_edits"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="@dimen/overflow_icon_dimen"
|
||||
android:layout_height="@dimen/overflow_icon_dimen"
|
||||
android:id="@+id/wikidata_edits_icon"
|
||||
app:srcCompat="@drawable/ic_custom_map_marker" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
style="?android:textAppearanceMedium"
|
||||
android:layout_marginStart="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginEnd="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginRight="@dimen/activity_margin_horizontal"
|
||||
android:text="@string/statistics_wikidata_edits" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="@dimen/medium_width"
|
||||
android:layout_height="@dimen/medium_height"
|
||||
android:id="@+id/images_nearby_info"
|
||||
android:layout_marginTop="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginRight="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginEnd="@dimen/activity_margin_horizontal"
|
||||
android:layout_gravity="top"
|
||||
app:srcCompat="@drawable/ic_info_outline_24dp"
|
||||
android:tint="@color/primaryDarkColor" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
style="?android:textAppearanceMedium"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginEnd="@dimen/half_standard_height"
|
||||
android:layout_marginTop="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginStart="@dimen/activity_margin_horizontal"
|
||||
android:layout_centerVertical="true"
|
||||
tools:text="2"
|
||||
android:id="@+id/wikidata_edits"
|
||||
android:layout_marginRight="@dimen/half_standard_height" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginRight="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginEnd="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginStart="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginTop="@dimen/activity_margin_horizontal">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_toStartOf="@+id/image_featured"
|
||||
android:layout_toLeftOf="@+id/image_featured"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="@dimen/overflow_icon_dimen"
|
||||
android:layout_height="@dimen/overflow_icon_dimen"
|
||||
android:id="@+id/featured_image_icon"
|
||||
app:srcCompat="@drawable/featured"
|
||||
android:scaleType="centerCrop" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
style="?android:textAppearanceMedium"
|
||||
android:layout_marginStart="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginEnd="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginRight="@dimen/activity_margin_horizontal"
|
||||
android:text="@string/statistics_featured" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="@dimen/medium_width"
|
||||
android:layout_height="@dimen/medium_height"
|
||||
android:id="@+id/images_featured_info"
|
||||
android:layout_marginTop="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginRight="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginEnd="@dimen/activity_margin_horizontal"
|
||||
android:layout_gravity="top"
|
||||
app:srcCompat="@drawable/ic_info_outline_24dp"
|
||||
android:tint="@color/primaryDarkColor" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
style="?android:textAppearanceMedium"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_marginTop="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginStart="@dimen/activity_margin_horizontal"
|
||||
android:layout_centerVertical="true"
|
||||
tools:text="2"
|
||||
android:id="@+id/image_featured"
|
||||
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginEnd="@dimen/half_standard_height"
|
||||
android:layout_marginRight="@dimen/half_standard_height" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginRight="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginStart="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginTop="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginEnd="@dimen/activity_margin_horizontal">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_toStartOf="@+id/thanks_received"
|
||||
android:layout_toLeftOf="@+id/thanks_received"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="@dimen/overflow_icon_dimen"
|
||||
android:layout_height="@dimen/overflow_icon_dimen"
|
||||
android:id="@+id/thanks_image_icon"
|
||||
app:srcCompat="@drawable/ic_thanks"
|
||||
android:scaleType="centerCrop" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
style="?android:textAppearanceMedium"
|
||||
android:layout_marginStart="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginEnd="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginRight="@dimen/activity_margin_horizontal"
|
||||
android:text="@string/statistics_thanks" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="@dimen/medium_width"
|
||||
android:layout_height="@dimen/medium_height"
|
||||
android:id="@+id/thanks_received_info"
|
||||
android:layout_marginTop="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginRight="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginEnd="@dimen/activity_margin_horizontal"
|
||||
android:layout_gravity="top"
|
||||
app:srcCompat="@drawable/ic_info_outline_24dp"
|
||||
android:tint="@color/primaryDarkColor" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
style="?android:textAppearanceMedium"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_marginTop="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginStart="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
||||
android:layout_centerVertical="true"
|
||||
tools:text="2"
|
||||
android:id="@+id/thanks_received"
|
||||
android:layout_marginEnd="@dimen/half_standard_height"
|
||||
android:layout_marginRight="@dimen/half_standard_height" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
</LinearLayout>
|
||||
|
||||
<include layout="@layout/drawer_view" />
|
||||
|
||||
</androidx.drawerlayout.widget.DrawerLayout>
|
||||
41
app/src/main/res/layout/activity_profile.xml
Normal file
41
app/src/main/res/layout/activity_profile.xml
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/drawer_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/toolbar_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/primaryDarkColor">
|
||||
|
||||
<include layout="@layout/toolbar"/>
|
||||
|
||||
<com.google.android.material.tabs.TabLayout
|
||||
android:id="@+id/tab_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/toolbar"
|
||||
android:background="?attr/tabBackground"
|
||||
app:tabIndicatorColor="?attr/tabIndicatorColor"
|
||||
app:tabMode="fixed"
|
||||
app:tabSelectedTextColor="?attr/tabSelectedTextColor"
|
||||
app:tabTextColor="?attr/tabTextColor" />
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<androidx.viewpager.widget.ViewPager
|
||||
android:id="@+id/viewPager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_below="@id/toolbar_layout" />
|
||||
</RelativeLayout>
|
||||
|
||||
<include layout="@layout/drawer_view" />
|
||||
|
||||
</androidx.drawerlayout.widget.DrawerLayout>
|
||||
482
app/src/main/res/layout/fragment_achievements.xml
Normal file
482
app/src/main/res/layout/fragment_achievements.xml
Normal file
|
|
@ -0,0 +1,482 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/drawer_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ScrollView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/toolbar"
|
||||
android:background="?attr/achievementBackground"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
style="?android:textAppearanceLarge"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginStart="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginTop="@dimen/activity_margin_horizontal"
|
||||
android:text="@string/level"
|
||||
android:id="@+id/achievement_level"
|
||||
android:textAllCaps="true"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/achievement_info"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/activity_margin_vertical"
|
||||
android:layout_marginRight="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginEnd="@dimen/activity_margin_horizontal"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
app:srcCompat="@drawable/ic_info_outline_24dp"
|
||||
android:tint="@color/black"
|
||||
android:layout_marginVertical="@dimen/activity_margin_vertical" />
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/badge_layout"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/achievement_info"
|
||||
android:layout_centerHorizontal="true">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/achievement_badge_image"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:srcCompat="@drawable/badge" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/achievement_badge_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAlignment="center"
|
||||
android:textColor="@color/achievement_badge_text"
|
||||
android:textSize="75sp"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/achievement_badge_image"
|
||||
app:layout_constraintEnd_toEndOf="@+id/achievement_badge_image"
|
||||
app:layout_constraintStart_toStartOf="@+id/achievement_badge_image"
|
||||
app:layout_constraintTop_toTopOf="@+id/achievement_badge_image"
|
||||
app:layout_constraintVertical_bias="0.58" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/layout_image_uploaded"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/badge_layout"
|
||||
android:layout_marginEnd="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginRight="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginStart="@dimen/activity_margin_horizontal">
|
||||
|
||||
<TextView
|
||||
style="?android:textAppearanceMedium"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginStart="@dimen/activity_margin_horizontal"
|
||||
android:id="@+id/images_upload_text_param"
|
||||
android:layout_marginTop="@dimen/achievements_activity_margin_vertical"
|
||||
android:text="@string/images_uploaded" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="@dimen/quarter_standard_height"
|
||||
android:layout_height="@dimen/quarter_standard_height"
|
||||
android:id="@+id/images_upload_info"
|
||||
android:layout_marginTop="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginRight="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginEnd="@dimen/activity_margin_horizontal"
|
||||
android:layout_toRightOf="@+id/images_upload_text_param"
|
||||
android:layout_toEndOf="@+id/images_upload_text_param"
|
||||
app:srcCompat="@drawable/ic_info_outline_24dp"
|
||||
android:tint="@color/primaryDarkColor"
|
||||
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginStart="@dimen/activity_margin_horizontal"/>
|
||||
|
||||
<com.dinuscxj.progressbar.CircleProgressBar
|
||||
android:layout_width="@dimen/dimen_40"
|
||||
android:layout_height="@dimen/dimen_40"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_marginEnd="@dimen/large_gap"
|
||||
android:layout_marginRight="@dimen/large_gap"
|
||||
android:id="@+id/images_uploaded_progressbar"
|
||||
android:progress="50"
|
||||
app:progress_text_size="@dimen/progressbar_text"
|
||||
app:progress_end_color="#8C8B98"
|
||||
app:progress_start_color="#3A3381"
|
||||
app:progress_stroke_width="@dimen/progressbar_stroke"
|
||||
app:progress_text_format_pattern="573/110"
|
||||
app:progress_text_color="@color/secondaryColor"
|
||||
app:style="solid_line" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/layout_image_reverts"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/tiny_margin"
|
||||
android:layout_below="@+id/layout_image_uploaded"
|
||||
android:layout_marginEnd="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginRight="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginStart="@dimen/activity_margin_horizontal">
|
||||
|
||||
<TextView
|
||||
style="?android:textAppearanceMedium"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
||||
android:id="@+id/images_reverted_text"
|
||||
android:layout_marginStart="@dimen/activity_margin_horizontal"
|
||||
android:text="@string/image_reverts" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="@dimen/medium_width"
|
||||
android:layout_height="@dimen/medium_height"
|
||||
android:layout_marginTop="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginRight="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginEnd="@dimen/activity_margin_horizontal"
|
||||
android:id="@+id/images_reverted_info"
|
||||
android:layout_toRightOf="@+id/images_reverted_text"
|
||||
android:layout_toEndOf="@+id/images_reverted_text"
|
||||
app:srcCompat="@drawable/ic_info_outline_24dp"
|
||||
android:tint="@color/primaryDarkColor"
|
||||
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginStart="@dimen/activity_margin_horizontal"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/achievements_revert_limit_message"
|
||||
android:textSize="@dimen/small_text"
|
||||
android:id="@+id/images_revert_limit_text"
|
||||
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginStart="@dimen/activity_margin_horizontal"
|
||||
android:layout_below="@+id/images_reverted_text"/>
|
||||
|
||||
<com.dinuscxj.progressbar.CircleProgressBar
|
||||
android:layout_width="@dimen/dimen_40"
|
||||
android:layout_height="@dimen/dimen_40"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_marginRight="@dimen/large_gap"
|
||||
android:layout_marginEnd="@dimen/large_gap"
|
||||
android:progress="50"
|
||||
android:id="@+id/image_reverts_progressbar"
|
||||
app:progress_end_color="#8C8B98"
|
||||
app:progress_start_color="#3A3381"
|
||||
app:progress_text_size="@dimen/progressbar_text"
|
||||
app:progress_stroke_width="@dimen/progressbar_stroke"
|
||||
app:progress_text_format_pattern="92%%"
|
||||
app:progress_text_color="@color/secondaryColor"
|
||||
app:style="solid_line" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/layout_image_used_by_wiki"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/tiny_margin"
|
||||
android:layout_below="@+id/layout_image_reverts"
|
||||
android:layout_marginBottom="@dimen/activity_margin_vertical"
|
||||
android:layout_marginEnd="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginRight="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginStart="@dimen/activity_margin_horizontal">
|
||||
|
||||
<TextView
|
||||
style="?android:textAppearanceMedium"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/images_used_by_wiki_text"
|
||||
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginStart="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginTop="@dimen/achievements_activity_margin_vertical"
|
||||
android:text="@string/images_used_by_wiki" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="@dimen/medium_width"
|
||||
android:layout_height="@dimen/medium_height"
|
||||
android:id="@+id/images_used_by_wiki_info"
|
||||
android:layout_marginTop="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginRight="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginEnd="@dimen/activity_margin_horizontal"
|
||||
android:layout_toRightOf="@+id/images_used_by_wiki_text"
|
||||
android:layout_toEndOf="@+id/images_used_by_wiki_text"
|
||||
app:srcCompat="@drawable/ic_info_outline_24dp"
|
||||
android:tint="@color/primaryDarkColor"
|
||||
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginStart="@dimen/activity_margin_horizontal"/>
|
||||
|
||||
<com.dinuscxj.progressbar.CircleProgressBar
|
||||
android:layout_width="@dimen/dimen_40"
|
||||
android:layout_height="@dimen/dimen_40"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_marginRight="@dimen/large_gap"
|
||||
android:layout_marginEnd="@dimen/large_gap"
|
||||
android:progress="50"
|
||||
app:progress_text_size="@dimen/progressbar_text"
|
||||
android:id="@+id/images_used_by_wiki_progress_bar"
|
||||
app:progress_end_color="#8C8B98"
|
||||
app:progress_start_color="#3A3381"
|
||||
app:progress_stroke_width="2.5dp"
|
||||
app:progress_text_color="@color/secondaryColor"
|
||||
app:progress_text_format_pattern="12/24"
|
||||
app:style="solid_line" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progressBar"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/layout_statistics"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/statistics"
|
||||
style="?android:textAppearanceLarge"
|
||||
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginStart="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginTop="@dimen/activity_margin_vertical"
|
||||
android:textAllCaps="true"/>
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginRight="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginEnd="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginStart="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginTop="@dimen/activity_margin_horizontal">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_toStartOf="@+id/wikidata_edits"
|
||||
android:layout_toLeftOf="@+id/wikidata_edits"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="@dimen/overflow_icon_dimen"
|
||||
android:layout_height="@dimen/overflow_icon_dimen"
|
||||
android:id="@+id/wikidata_edits_icon"
|
||||
app:srcCompat="@drawable/ic_custom_map_marker" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
style="?android:textAppearanceMedium"
|
||||
android:layout_marginStart="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginEnd="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginRight="@dimen/activity_margin_horizontal"
|
||||
android:text="@string/statistics_wikidata_edits" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="@dimen/medium_width"
|
||||
android:layout_height="@dimen/medium_height"
|
||||
android:id="@+id/images_nearby_info"
|
||||
android:layout_marginTop="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginRight="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginEnd="@dimen/activity_margin_horizontal"
|
||||
android:layout_gravity="top"
|
||||
app:srcCompat="@drawable/ic_info_outline_24dp"
|
||||
android:tint="@color/primaryDarkColor" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
style="?android:textAppearanceMedium"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginEnd="@dimen/half_standard_height"
|
||||
android:layout_marginTop="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginStart="@dimen/activity_margin_horizontal"
|
||||
android:layout_centerVertical="true"
|
||||
tools:text="2"
|
||||
android:id="@+id/wikidata_edits"
|
||||
android:layout_marginRight="@dimen/half_standard_height" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginRight="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginEnd="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginStart="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginTop="@dimen/activity_margin_horizontal">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_toStartOf="@+id/image_featured"
|
||||
android:layout_toLeftOf="@+id/image_featured"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="@dimen/overflow_icon_dimen"
|
||||
android:layout_height="@dimen/overflow_icon_dimen"
|
||||
android:id="@+id/featured_image_icon"
|
||||
app:srcCompat="@drawable/featured"
|
||||
android:scaleType="centerCrop" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
style="?android:textAppearanceMedium"
|
||||
android:layout_marginStart="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginEnd="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginRight="@dimen/activity_margin_horizontal"
|
||||
android:text="@string/statistics_featured" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="@dimen/medium_width"
|
||||
android:layout_height="@dimen/medium_height"
|
||||
android:id="@+id/images_featured_info"
|
||||
android:layout_marginTop="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginRight="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginEnd="@dimen/activity_margin_horizontal"
|
||||
android:layout_gravity="top"
|
||||
app:srcCompat="@drawable/ic_info_outline_24dp"
|
||||
android:tint="@color/primaryDarkColor" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
style="?android:textAppearanceMedium"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_marginTop="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginStart="@dimen/activity_margin_horizontal"
|
||||
android:layout_centerVertical="true"
|
||||
tools:text="2"
|
||||
android:id="@+id/image_featured"
|
||||
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginEnd="@dimen/half_standard_height"
|
||||
android:layout_marginRight="@dimen/half_standard_height" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginRight="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginStart="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginTop="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginEnd="@dimen/activity_margin_horizontal">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_toStartOf="@+id/thanks_received"
|
||||
android:layout_toLeftOf="@+id/thanks_received"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="@dimen/overflow_icon_dimen"
|
||||
android:layout_height="@dimen/overflow_icon_dimen"
|
||||
android:id="@+id/thanks_image_icon"
|
||||
app:srcCompat="@drawable/ic_thanks"
|
||||
android:scaleType="centerCrop" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
style="?android:textAppearanceMedium"
|
||||
android:layout_marginStart="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginEnd="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginRight="@dimen/activity_margin_horizontal"
|
||||
android:text="@string/statistics_thanks" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="@dimen/medium_width"
|
||||
android:layout_height="@dimen/medium_height"
|
||||
android:id="@+id/thanks_received_info"
|
||||
android:layout_marginTop="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginRight="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginEnd="@dimen/activity_margin_horizontal"
|
||||
android:layout_gravity="top"
|
||||
app:srcCompat="@drawable/ic_info_outline_24dp"
|
||||
android:tint="@color/primaryDarkColor" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
style="?android:textAppearanceMedium"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_marginTop="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginStart="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
||||
android:layout_centerVertical="true"
|
||||
tools:text="2"
|
||||
android:id="@+id/thanks_received"
|
||||
android:layout_marginEnd="@dimen/half_standard_height"
|
||||
android:layout_marginRight="@dimen/half_standard_height" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
|
||||
<include layout="@layout/drawer_view" />
|
||||
|
||||
</androidx.drawerlayout.widget.DrawerLayout>
|
||||
56
app/src/main/res/layout/fragment_leaderboard.xml
Normal file
56
app/src/main/res/layout/fragment_leaderboard.xml
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/filters"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:weightSum="1"
|
||||
android:layout_margin="20dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<Spinner
|
||||
android:layout_marginStart="50dp"
|
||||
android:id="@+id/duration_spinner"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_weight="0.5"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
<Spinner
|
||||
android:layout_marginEnd="50dp"
|
||||
android:id="@+id/category_spinner"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_weight="0.5"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/leaderboard_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginTop="10dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/filters" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progressBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@+id/leaderboard_list" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
50
app/src/main/res/layout/leaderboard_list_element.xml
Normal file
50
app/src/main/res/layout/leaderboard_list_element.xml
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:fresco="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:layout_marginStart="15dp"
|
||||
android:layout_marginEnd="15dp"
|
||||
android:weightSum="1">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/user_rank"
|
||||
style="?android:textAppearanceMedium"
|
||||
android:gravity="center_vertical|center_horizontal"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="0.1"
|
||||
android:layout_height="match_parent"/>
|
||||
|
||||
<com.facebook.drawee.view.SimpleDraweeView
|
||||
android:id="@+id/user_avatar"
|
||||
android:layout_weight="0.1"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="20dp"
|
||||
fresco:roundAsCircle="true"
|
||||
fresco:viewAspectRatio="1"
|
||||
android:gravity="center_vertical|start"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/user_name"
|
||||
style="?android:textAppearanceMedium"
|
||||
android:gravity="center_vertical|start"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="0.6"
|
||||
android:layout_height="match_parent"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/user_count"
|
||||
style="?android:textAppearanceSmall"
|
||||
android:gravity="center_vertical|end"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="0.2"
|
||||
android:layout_height="match_parent"/>
|
||||
|
||||
</LinearLayout>
|
||||
86
app/src/main/res/layout/leaderboard_user_element.xml
Normal file
86
app/src/main/res/layout/leaderboard_user_element.xml
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:fresco="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.facebook.drawee.view.SimpleDraweeView
|
||||
android:id="@+id/avatar"
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="100dp"
|
||||
android:layout_margin="20dp"
|
||||
fresco:roundAsCircle="true"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/username"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
style="?android:textAppearanceMedium"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/avatar" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/rank"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
style="?android:textAppearanceMedium"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/username" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/count"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
style="?android:textAppearanceMedium"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/rank" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/column_names"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:layout_margin="15dp"
|
||||
android:weightSum="1"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/count">
|
||||
|
||||
<TextView
|
||||
style="?android:textAppearanceButton"
|
||||
android:gravity="center_vertical|start"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="0.2"
|
||||
android:text="@string/leaderboard_column_rank"
|
||||
android:layout_height="match_parent"/>
|
||||
|
||||
<TextView
|
||||
style="?android:textAppearanceButton"
|
||||
android:gravity="center_vertical|start"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="0.6"
|
||||
android:text="@string/leaderboard_column_user"
|
||||
android:layout_height="match_parent"/>
|
||||
|
||||
<TextView
|
||||
style="?android:textAppearanceButton"
|
||||
android:gravity="center_vertical|end"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="0.2"
|
||||
android:text="@string/leaderboard_column_count"
|
||||
android:layout_height="match_parent"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
@ -25,5 +25,9 @@
|
|||
android:id="@+id/menu_set_as_wallpaper"
|
||||
android:title="@string/menu_set_wallpaper"
|
||||
app:showAsAction="never" />
|
||||
<item
|
||||
android:id="@+id/menu_set_as_avatar"
|
||||
android:title="@string/menu_set_avatar"
|
||||
app:showAsAction="never" />
|
||||
|
||||
</menu>
|
||||
|
|
@ -46,4 +46,29 @@
|
|||
<item>1</item>
|
||||
<item>0</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="leaderboard_categories">
|
||||
<item>@string/leaderboard_upload</item>
|
||||
<item>@string/leaderboard_used</item>
|
||||
<item>@string/leaderboard_nearby</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="leaderboard_category_values">
|
||||
<item>upload</item>
|
||||
<item>used</item>
|
||||
<item>nearby</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="leaderboard_durations">
|
||||
<item>@string/leaderboard_weekly</item>
|
||||
<item>@string/leaderboard_yearly</item>
|
||||
<item>@string/leaderboard_all_time</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="leaderboard_duration_values">
|
||||
<item>weekly</item>
|
||||
<item>yearly</item>
|
||||
<item>all_time</item>
|
||||
</string-array>
|
||||
|
||||
</resources>
|
||||
|
|
@ -399,6 +399,7 @@
|
|||
<string name="nominate_delete">Nominate For Deletion</string>
|
||||
<string name="delete">Delete</string>
|
||||
<string name="Achievements">Achievements</string>
|
||||
<string name="Profile">Profile</string>
|
||||
<string name="statistics">Statistics</string>
|
||||
<string name="statistics_thanks">Thanks Received</string>
|
||||
<string name="statistics_featured">Featured Images</string>
|
||||
|
|
@ -669,4 +670,22 @@ Upload your first media by tapping on the add button.</string>
|
|||
<string name="pause">pause</string>
|
||||
<string name="resume">resume</string>
|
||||
<string name="paused">Paused</string>
|
||||
<string name="achievements_tab_title">Achievements</string>
|
||||
<string name="leaderboard_tab_title">Leaderboard</string>
|
||||
<string name="rank_prefix">Rank:</string>
|
||||
<string name="count_prefix">Count:</string>
|
||||
<string name="leaderboard_column_rank">Rank</string>
|
||||
<string name="leaderboard_column_user">User</string>
|
||||
<string name="leaderboard_column_count">Count</string>
|
||||
<string name="setting_avatar_dialog_title">Set as leaderboard avatar</string>
|
||||
<string name="setting_avatar_dialog_message">Setting as avatar, please wait</string>
|
||||
<string name="avatar_set_successfully">Avatar set</string>
|
||||
<string name="avatar_set_unsuccessfully">Error setting new avatar, please try again</string>
|
||||
<string name="menu_set_avatar">Set as avatar</string>
|
||||
<string name="leaderboard_yearly">Yearly</string>
|
||||
<string name="leaderboard_weekly">Weekly</string>
|
||||
<string name="leaderboard_all_time">All time</string>
|
||||
<string name="leaderboard_upload">Upload</string>
|
||||
<string name="leaderboard_nearby">Nearby</string>
|
||||
<string name="leaderboard_used">Used</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -3,10 +3,13 @@ package fr.free.nrw.commons.delete
|
|||
import android.content.Context
|
||||
import android.content.res.Resources
|
||||
import fr.free.nrw.commons.Media
|
||||
import fr.free.nrw.commons.achievements.FeedbackResponse
|
||||
import fr.free.nrw.commons.auth.SessionManager
|
||||
import fr.free.nrw.commons.mwapi.OkHttpJsonApiClient
|
||||
import fr.free.nrw.commons.profile.achievements.FeedbackResponse
|
||||
import fr.free.nrw.commons.profile.leaderboard.LeaderboardResponse
|
||||
import fr.free.nrw.commons.profile.leaderboard.UpdateAvatarResponse
|
||||
import fr.free.nrw.commons.utils.ViewUtilWrapper
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.Single
|
||||
import media
|
||||
import org.junit.Before
|
||||
|
|
@ -54,6 +57,10 @@ class ReasonBuilderTest {
|
|||
`when`(sessionManager?.doesAccountExist()).thenReturn(true)
|
||||
`when`(okHttpJsonApiClient!!.getAchievements(anyString()))
|
||||
.thenReturn(Single.just(mock(FeedbackResponse::class.java)))
|
||||
`when`(okHttpJsonApiClient!!.getLeaderboard(anyString(), anyString(), anyString(), anyString(), anyString()))
|
||||
.thenReturn(Observable.just(mock(LeaderboardResponse::class.java)))
|
||||
`when`(okHttpJsonApiClient!!.setAvatar(anyString(), anyString()))
|
||||
.thenReturn(Single.just(mock(UpdateAvatarResponse::class.java)))
|
||||
|
||||
val media = media(filename="test_file", dateUploaded = Date())
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,116 @@
|
|||
package fr.free.nrw.commons.leaderboard;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import fr.free.nrw.commons.profile.leaderboard.LeaderboardResponse;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import okhttp3.HttpUrl;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Request.Builder;
|
||||
import okhttp3.Response;
|
||||
import okhttp3.mockwebserver.MockResponse;
|
||||
import okhttp3.mockwebserver.MockWebServer;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* This class tests the Leaderboard API calls
|
||||
*/
|
||||
public class LeaderboardApiTest {
|
||||
|
||||
MockWebServer server;
|
||||
private static final String TEST_USERNAME = "user";
|
||||
private static final String TEST_AVATAR = "avatar";
|
||||
private static final int TEST_USER_RANK = 1;
|
||||
private static final int TEST_USER_COUNT = 0;
|
||||
|
||||
private static final String FILE_NAME = "leaderboard_sample_response.json";
|
||||
private static final String ENDPOINT = "/leaderboard.py";
|
||||
|
||||
/**
|
||||
* This method initialises a Mock Server
|
||||
*/
|
||||
@Before
|
||||
public void initTest() {
|
||||
server = new MockWebServer();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will setup a Mock Server and load Test JSON Response File
|
||||
* @throws Exception
|
||||
*/
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
|
||||
String testResponseBody = convertStreamToString(getClass().getClassLoader().getResourceAsStream(FILE_NAME));
|
||||
|
||||
server.enqueue(new MockResponse().setBody(testResponseBody));
|
||||
server.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method converts a Input Stream to String
|
||||
* @param is takes Input Stream of JSON File as Parameter
|
||||
* @return a String with JSON data
|
||||
* @throws Exception
|
||||
*/
|
||||
private static String convertStreamToString(InputStream is) throws Exception {
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
|
||||
StringBuilder sb = new StringBuilder();
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
sb.append(line).append("\n");
|
||||
}
|
||||
reader.close();
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will call the Mock Server and Test it with sample values.
|
||||
* It will test the Leaderboard API call functionality and check if the object is
|
||||
* being created with the correct values
|
||||
* @throws IOException
|
||||
*/
|
||||
@Test
|
||||
public void apiTest() throws IOException {
|
||||
HttpUrl httpUrl = server.url(ENDPOINT);
|
||||
LeaderboardResponse response = sendRequest(new OkHttpClient(), httpUrl);
|
||||
|
||||
Assert.assertEquals(TEST_AVATAR, response.getAvatar());
|
||||
Assert.assertEquals(TEST_USERNAME, response.getUsername());
|
||||
Assert.assertEquals(Integer.valueOf(TEST_USER_RANK), response.getRank());
|
||||
Assert.assertEquals(Integer.valueOf(TEST_USER_COUNT), response.getCategoryCount());
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will call the Mock API and returns the Leaderboard Response Object
|
||||
* @param okHttpClient
|
||||
* @param httpUrl
|
||||
* @return Leaderboard Response Object
|
||||
* @throws IOException
|
||||
*/
|
||||
private LeaderboardResponse sendRequest(OkHttpClient okHttpClient, HttpUrl httpUrl)
|
||||
throws IOException {
|
||||
Request request = new Builder().url(httpUrl).build();
|
||||
Response response = okHttpClient.newCall(request).execute();
|
||||
if (response.isSuccessful()) {
|
||||
Gson gson = new Gson();
|
||||
return gson.fromJson(response.body().string(), LeaderboardResponse.class);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method shuts down the Mock Server
|
||||
* @throws IOException
|
||||
*/
|
||||
@After
|
||||
public void shutdown() throws IOException {
|
||||
server.shutdown();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,117 @@
|
|||
package fr.free.nrw.commons.leaderboard;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import fr.free.nrw.commons.profile.leaderboard.UpdateAvatarResponse;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import okhttp3.HttpUrl;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Request.Builder;
|
||||
import okhttp3.Response;
|
||||
import okhttp3.mockwebserver.MockResponse;
|
||||
import okhttp3.mockwebserver.MockWebServer;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
public class UpdateAvatarApiTest {
|
||||
|
||||
private static final String TEST_USERNAME = "user";
|
||||
private static final String TEST_STATUS = "200";
|
||||
private static final String TEST_MESSAGE = "Avatar Updated";
|
||||
private static final String FILE_NAME = "update_leaderboard_avatar_sample_response.json";
|
||||
private static final String ENDPOINT = "/update_avatar.py";
|
||||
MockWebServer server;
|
||||
|
||||
/**
|
||||
* This method converts a Input Stream to String
|
||||
*
|
||||
* @param is takes Input Stream of JSON File as Parameter
|
||||
* @return a String with JSON data
|
||||
* @throws Exception
|
||||
*/
|
||||
private static String convertStreamToString(final InputStream is) throws Exception {
|
||||
final BufferedReader reader = new BufferedReader(new InputStreamReader(is));
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
sb.append(line).append("\n");
|
||||
}
|
||||
reader.close();
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method initialises a Mock Server
|
||||
*/
|
||||
@Before
|
||||
public void initTest() {
|
||||
server = new MockWebServer();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will setup a Mock Server and load Test JSON Response File
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
|
||||
final String testResponseBody = convertStreamToString(
|
||||
getClass().getClassLoader().getResourceAsStream(FILE_NAME));
|
||||
|
||||
server.enqueue(new MockResponse().setBody(testResponseBody));
|
||||
server.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will call the Mock Server and Test it with sample values. It will test the Update
|
||||
* Avatar API call functionality and check if the object is being created with the correct
|
||||
* values
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
@Test
|
||||
public void apiTest() throws IOException {
|
||||
final HttpUrl httpUrl = server.url(ENDPOINT);
|
||||
final UpdateAvatarResponse response = sendRequest(new OkHttpClient(), httpUrl);
|
||||
|
||||
Assert.assertEquals(TEST_USERNAME, response.getUser());
|
||||
Assert.assertEquals(TEST_STATUS, response.getStatus());
|
||||
Assert.assertEquals(TEST_MESSAGE, response.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will call the Mock API and returns the Update Avatar Response Object
|
||||
*
|
||||
* @param okHttpClient
|
||||
* @param httpUrl
|
||||
* @return Update Avatar Response Object
|
||||
* @throws IOException
|
||||
*/
|
||||
private UpdateAvatarResponse sendRequest(final OkHttpClient okHttpClient, final HttpUrl httpUrl)
|
||||
throws IOException {
|
||||
final Request request = new Builder().url(httpUrl).build();
|
||||
final Response response = okHttpClient.newCall(request).execute();
|
||||
if (response.isSuccessful()) {
|
||||
final Gson gson = new Gson();
|
||||
return gson.fromJson(response.body().string(), UpdateAvatarResponse.class);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method shuts down the Mock Server
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
@After
|
||||
public void shutdown() throws IOException {
|
||||
server.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -442,4 +442,4 @@ class NearbyParentFragmentPresenterTest {
|
|||
verify(nearbyParentFragmentView).isNetworkConnectionEstablished()
|
||||
verifyZeroInteractions(nearbyParentFragmentView)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
19
app/src/test/resources/leaderboard_sample_response.json
Normal file
19
app/src/test/resources/leaderboard_sample_response.json
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"status": 200,
|
||||
"username": "user",
|
||||
"category_count": 0,
|
||||
"limit": null,
|
||||
"avatar": "avatar",
|
||||
"offset": null,
|
||||
"duration": "all_time",
|
||||
"leaderboard_list": [
|
||||
{
|
||||
"username": "user",
|
||||
"category_count": 0,
|
||||
"avatar": "avatar",
|
||||
"rank": 1
|
||||
}
|
||||
],
|
||||
"category": "used",
|
||||
"rank": 1
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"status": "200",
|
||||
"message": "Avatar Updated",
|
||||
"user": "user"
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue