Merge remote-tracking branch 'upstream/develop' into party-invite

This commit is contained in:
Zoe Abrams 2020-04-11 03:52:34 -07:00
commit dca164e6d1
178 changed files with 4589 additions and 2190 deletions

View file

@ -191,7 +191,11 @@
android:windowSoftInputMode="stateHidden" />
<receiver android:name=".receivers.NotificationPublisher" />
<receiver android:name=".receivers.TaskReceiver"/>
<receiver android:name=".receivers.TaskReceiver" android:enabled="true" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.NOTIFY" />
</intent-filter>
</receiver>
<receiver android:name=".receivers.LocalNotificationActionReceiver"
android:exported="false">

View file

@ -17,7 +17,7 @@ buildscript {
jcenter()
}
dependencies {
classpath 'io.fabric.tools:gradle:1.31.0'
classpath 'io.fabric.tools:gradle:1.+'
classpath('com.noveogroup.android:check:1.2.5') {
exclude module: 'checkstyle'
exclude module: 'pmd-java'
@ -102,6 +102,8 @@ dependencies {
}
//Tests
testImplementation 'junit:junit:4.12'
testImplementation 'androidx.test:core:1.0.0'
testImplementation "com.google.truth:truth:1.0.1"
testImplementation 'org.assertj:assertj-core:2.6.0'
testImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.6.2'
testImplementation 'org.robolectric:robolectric:3.8'
@ -115,26 +117,28 @@ dependencies {
debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.6.2'
releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.6.2'
//Push Notifications
implementation 'com.google.firebase:firebase-core:17.2.1'
implementation 'com.google.firebase:firebase-core:17.2.2'
implementation 'com.google.firebase:firebase-messaging:20.1.0'
implementation 'com.google.firebase:firebase-config:19.1.0'
implementation 'com.google.firebase:firebase-perf:19.0.4'
implementation 'com.google.firebase:firebase-config:19.1.1'
implementation 'com.google.firebase:firebase-perf:19.0.5'
implementation 'com.google.android.gms:play-services-auth:17.0.0'
implementation 'io.realm:android-adapters:3.1.0'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'androidx.multidex:multidex:2.0.1'
implementation 'com.nex3z:flow-layout:1.2.2'
implementation 'androidx.core:core-ktx:1.1.0'
implementation "androidx.lifecycle:lifecycle-extensions:2.1.0"
implementation "androidx.lifecycle:lifecycle-common-java8:2.1.0"
implementation 'androidx.navigation:navigation-fragment-ktx:2.1.0'
implementation 'androidx.navigation:navigation-ui-ktx:2.1.0'
implementation 'androidx.core:core-ktx:1.2.0'
implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
implementation "androidx.lifecycle:lifecycle-common-java8:2.2.0"
implementation 'androidx.navigation:navigation-fragment-ktx:2.2.1'
implementation 'androidx.navigation:navigation-ui-ktx:2.2.1'
implementation "androidx.paging:paging-runtime-ktx:2.1.1"
implementation 'com.plattysoft.leonids:LeonidsLib:1.3.2'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.3'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.3'
implementation 'com.willowtreeapps:signinwithapplebutton:0.2'
implementation project(':shared')
}
@ -151,8 +155,8 @@ android {
multiDexEnabled true
resConfigs "en", "bg", "de", "en-rGB", "es", "fr", "hr-rHR", "in", "it", "iw", "ja", "ko", "lt", "nl", "pl", "pt-rBR", "pt-rPT", "ru", "tr", "zh", "zh-rTW"
versionCode 2346
versionName "2.4.2"
versionCode 2396
versionName "2.5"
}
viewBinding {

Binary file not shown.

After

Width:  |  Height:  |  Size: 597 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 904 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 460 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 638 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 788 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/gray_600" />
<corners android:radius="8dp"/>
<padding android:left="0dip" android:top="0dip" android:right="0dip" android:bottom="0dip" />
</shape>

View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval">
<solid android:color="@color/gray_300" />
</shape>

View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="48dp" android:viewportHeight="24.0" android:viewportWidth="24.0" android:width="48dp">
<path android:fillColor="#33878190" android:pathData="M7,14l5,-5 5,5z"/>
</vector>

View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="false" android:drawable="@drawable/ic_arrow_drop_up_gray_48dp_disabled" />
<item android:drawable="@drawable/ic_arrow_drop_up_gray_48dp" />
</selector>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/gray_700" />
<corners android:radius="@dimen/rounded_button_radius"/>
<padding android:left="0dip" android:top="0dip" android:right="0dip" android:bottom="0dip" />
<stroke android:color="@color/brand_300" android:width="2dp" />
</shape>

View file

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<!-- view background color -->
<solid
android:color="@color/brand_300" >
</solid>
<!-- Here is the corner radius -->
<corners
android:radius="5dp" >
</corners>
</shape>

View file

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<!-- view background color -->
<solid
android:color="@color/brand_400" >
</solid>
<!-- Here is the corner radius -->
<corners android:radius="8dp">
</corners>
</shape>

View file

@ -201,7 +201,7 @@
android:layout_marginTop="@dimen/spacing_xlarge"
android:layout_height="@dimen/diamond_button_height"
android:text="@string/login_btn_fb"
android:drawableLeft="@drawable/facebook_icon"
android:drawableStart="@drawable/facebook_icon"
style="@style/LoginButton"/>
<Button
@ -210,9 +210,19 @@
android:layout_marginTop="@dimen/spacing_large"
android:layout_height="@dimen/diamond_button_height"
android:text="@string/login_btn_google"
android:drawableLeft="@drawable/google_icon"
android:drawableStart="@drawable/google_icon"
style="@style/LoginButton"/>
<Button
android:id="@+id/apple_login_button"
android:layout_width="match_parent"
android:layout_marginTop="@dimen/spacing_large"
android:layout_height="@dimen/diamond_button_height"
android:text="@string/login_btn_apple"
android:drawableStart="@drawable/apple_icon"
style="@style/LoginButton"
android:visibility="gone"/>
<Button
android:id="@+id/forgot_password"
android:layout_width="match_parent"
@ -222,7 +232,7 @@
android:text="@string/forgot_pw_btn"
android:layout_gravity="center_horizontal"
android:textColor="@color/white_75_alpha"
android:background="@color/transparent"/>
android:background="@color/transparent" />
</LinearLayout>

View file

@ -83,7 +83,7 @@
android:layout_height="wrap_content"
android:text="@string/cost"
style="@style/TaskFormSectionheader"/>
<com.habitrpg.android.habitica.ui.views.tasks.form.RewardValueFormView
<com.habitrpg.android.habitica.ui.views.tasks.form.StepperValueFormView
android:id="@+id/reward_value"
android:layout_width="match_parent"
android:layout_height="56dp" />

View file

@ -1,37 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/card_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_width="match_parent">
<RelativeLayout
android:id="@+id/linearLayout"
android:layout_width="match_parent"
android:layout_height="90dp"
android:minHeight="60dp"
android:minHeight="60dp">
<LinearLayout
android:id="@+id/wrapper"
android:layout_width="76dp"
android:layout_height="wrap_content"
android:background="@drawable/layout_rounded_bg_gray_700"
android:orientation="vertical"
android:clickable="true"
android:background="@drawable/selection_highlight">
<View
android:id="@+id/purchaseOverlay"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:background="@android:color/black" />
android:layout_gravity="center">
<com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/imageView"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_gravity="center_horizontal"
android:scaleType="fitEnd"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true" />
</RelativeLayout>
</androidx.cardview.widget.CardView>
android:layout_height="76dp"
android:layout_gravity="start"
android:scaleType="fitEnd" />
<FrameLayout
android:id="@+id/buy_button"
android:layout_width="match_parent"
android:layout_height="32dp"
android:background="@drawable/layout_rounded_bg_shopitem_price">
<com.habitrpg.android.habitica.ui.views.CurrencyView
android:id="@+id/price_label"
android:layout_width="wrap_content"
android:layout_height="32dp"
android:textColor="@color/gray_300"
tools:text="150"
style="@style/Body1"
app:hasLightBackground="true"
android:textSize="15sp"
android:layout_gravity="center" />
</FrameLayout>
</LinearLayout>
</FrameLayout>

View file

@ -1,21 +1,42 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal" android:layout_width="match_parent"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="65dp"
android:paddingTop="16dp">
android:paddingTop="16dp"
android:gravity="bottom"
android:layout_marginStart="20dp"
android:layout_marginEnd="20dp">
<TextView
android:id="@+id/label"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="bottom"
android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_marginLeft="@dimen/section_leftright_padding"
android:layout_marginRight="@dimen/section_leftright_padding"/>
android:textAppearance="?android:attr/textAppearanceMedium"/>
<Button
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_height="40dp"
android:id="@+id/purchaseSetButton"
android:visibility="gone" />
android:visibility="gone"
android:orientation="horizontal"
android:gravity="center"
tools:visibility="visible"
android:paddingStart="@dimen/spacing_medium"
android:paddingEnd="@dimen/spacing_medium"
android:background="@drawable/layout_rounded_bg_gray_700">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/buy_all"
android:textAllCaps="true"
android:textColor="@color/brand_300"
style="@style/Body1"
android:layout_marginEnd="@dimen/spacing_medium"/>
<com.habitrpg.android.habitica.ui.views.CurrencyView
android:id="@+id/set_price_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>

View file

@ -1,10 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="20dp"
android:paddingRight="20dp">
android:paddingRight="20dp"
android:gravity="center_horizontal">
<TextView
android:layout_width="match_parent"
@ -18,4 +20,23 @@
android:id="@+id/uuidEditText" android:layout_gravity="center_horizontal"
android:focusable="true"
android:maxLines="1"/>
<ProgressBar
android:id="@+id/progress_circular"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:visibility="visible"
android:visibility="gone" />
<TextView
android:id="@+id/error_text_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/spacing_medium"
android:layout_marginBottom="@dimen/spacing_medium"
android:text="@string/could_not_find_user"
android:textColor="@color/red_50"
tools:visibility="visible"
android:gravity="center_horizontal"
android:visibility="gone"/>
</LinearLayout>

View file

@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="@dimen/shopitem_dialog_content_inset"
android:paddingRight="@dimen/shopitem_dialog_content_inset"
android:gravity="center_horizontal"
tools:parentTag="LinearLayout"
tools:orientation="vertical">
<TextView
android:id="@+id/titleTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/Headline"
tools:text="This is the Title"
android:gravity="center"
android:layout_marginBottom="4dp"/>
<TextView
android:text="@string/rewards"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginBottom="4dp"
android:gravity="center_horizontal"
/>
<LinearLayout
android:id="@+id/rewardsList"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"/>
<TextView
android:id="@+id/ownerRewardsTitle"
android:text="@string/quest_owner_rewards"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginBottom="4dp"
android:gravity="center_horizontal"
/>
<LinearLayout
android:id="@+id/ownerRewardsList"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"/>
<com.habitrpg.android.habitica.ui.views.WrapContentDraweeView
android:id="@+id/imageView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/spacing_large"
android:layout_marginStart="@dimen/spacing_large"
android:layout_marginEnd="@dimen/spacing_large"
android:layout_marginBottom="@dimen/spacing_large"/>
<TextView
android:id="@+id/notesTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/Body2"
android:textColor="@color/black_50_alpha"
tools:text="These are the notes"
android:gravity="center"/>
</merge>

View file

@ -57,6 +57,7 @@
android:paddingStart="@dimen/alert_side_padding"
android:paddingEnd="@dimen/alert_side_padding"
android:textColor="?textColorSecondary"
android:scrollbars = "vertical"
style="@style/Body2"
/>
<androidx.core.widget.NestedScrollView

View file

@ -100,4 +100,13 @@
android:textColor="@color/green_50"/>
</TableRow>
</TableLayout>
<TextView
android:id="@+id/amount_error_label"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:text="@string/purchase_amount_error"
android:textSize="12sp"
android:textColor="@color/gray_200"
android:layout_marginTop="@dimen/spacing_medium"
android:gravity="center_horizontal"/>
</merge>

View file

@ -31,4 +31,13 @@
android:textColor="@color/black_50_alpha"
tools:text="These are the notes"
android:gravity="center"/>
<TextView
android:id="@+id/amount_error_label"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:text="@string/purchase_amount_error"
android:textSize="12sp"
android:textColor="@color/gray_200"
android:layout_marginTop="@dimen/spacing_medium"
android:gravity="center_horizontal"/>
</merge>

View file

@ -179,4 +179,13 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"/>
<TextView
android:id="@+id/amount_error_label"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:text="@string/purchase_amount_error"
android:textSize="12sp"
android:textColor="@color/gray_200"
android:layout_marginTop="@dimen/spacing_medium"
android:gravity="center_horizontal"/>
</merge>

View file

@ -4,10 +4,11 @@
android:layout_height="wrap_content">
<com.facebook.drawee.view.SimpleDraweeView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_width="@dimen/avatar_width"
android:layout_height="@dimen/avatar_height"
android:id="@+id/imageView"
android:layout_gravity="center_horizontal" />
android:layout_gravity="center_horizontal"
android:scaleType="center"/>
<LinearLayout
android:orientation="horizontal"
@ -29,5 +30,14 @@
android:id="@+id/gem_icon"
android:layout_gravity="center"/>
</LinearLayout>
<TextView
android:id="@+id/amount_error_label"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:text="@string/purchase_amount_error"
android:textSize="12sp"
android:textColor="@color/gray_200"
android:layout_marginTop="@dimen/spacing_medium"
android:gravity="center_horizontal"/>
</LinearLayout>

View file

@ -0,0 +1,54 @@
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="@dimen/shopitem_dialog_content_inset"
android:paddingRight="@dimen/shopitem_dialog_content_inset"
android:gravity="center_horizontal"
tools:parentTag="LinearLayout"
tools:background="@color/white"
tools:orientation="vertical">
<com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/imageView"
android:layout_width="@dimen/shopitem_image_size"
android:layout_height="@dimen/shopitem_image_size" />
<TextView
android:id="@+id/titleTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/Headline"
tools:text="This is the Title"
android:gravity="center"
android:layout_marginTop="14dp"
android:layout_marginBottom="4dp"/>
<TextView
android:id="@+id/notesTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/Body2"
android:textColor="@color/black_50_alpha"
tools:text="These are the notes"
android:gravity="center"/>
<com.habitrpg.android.habitica.ui.views.tasks.form.StepperValueFormView
android:id="@+id/stepper_view"
android:layout_width="match_parent"
android:layout_height="56dp"
android:layout_marginTop="@dimen/spacing_large"
app:defaultValue="1"
app:minValue="1"
/>
<TextView
android:id="@+id/amount_error_label"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:text="@string/purchase_amount_error"
android:textSize="12sp"
android:textColor="@color/gray_200"
android:layout_marginTop="@dimen/spacing_medium"
android:gravity="center_horizontal"/>
</merge>

View file

@ -20,7 +20,7 @@
android:layout_width="56dp"
android:layout_height="match_parent"
android:background="@color/gray_600"
android:src="@drawable/ic_arrow_drop_up_gray_48dp"
android:src="@drawable/ic_arrow_drop_up_gray_48dp_states"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
/>

View file

@ -115,18 +115,6 @@
android:textColor="@color/white"
android:textSize="@dimen/card_medium_text" />
<Button
android:id="@+id/sendFeedback"
android:layout_width="250dp"
android:layout_height="35dp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="20sp"
android:background="@drawable/rounded_purple_square"
android:text="@string/about_give_us_feedback"
android:textAllCaps="false"
android:textColor="@color/white"
android:textSize="@dimen/card_medium_text" />
<TextView
android:id="@+id/sourceCodeLink"
android:layout_width="match_parent"

View file

@ -33,7 +33,8 @@
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="50dp">
android:layout_height="50dp"
android:gravity="center_vertical">
<TextView
android:layout_width="0dp"
@ -52,7 +53,6 @@
android:layout_height="match_parent"
android:id="@+id/avatarSizeSpinner"
android:spinnerMode="dropdown"
android:layout_marginRight="8dp"
android:layout_marginEnd="8dp"
android:entries="@array/avatar_sizes"/>
</LinearLayout>
@ -66,11 +66,57 @@
android:layout_height="wrap_content"
android:id="@+id/avatarSkinView"
app:equipmentTitle="@string/avatar_skin"/>
</LinearLayout>
</androidx.cardview.widget.CardView>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/avatar_extras"
android:textAppearance="?android:attr/textAppearanceMedium"
style="@style/SectionTitle"/>
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/CardView.Default">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:divider="?android:listDivider"
android:showDividers="middle">
<com.habitrpg.android.habitica.ui.views.EquipmentItemRow
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/avatar_glasses_view"
app:equipmentTitle="@string/avatar_glasses"/>
<com.habitrpg.android.habitica.ui.views.EquipmentItemRow
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/avatarChairView"
app:equipmentTitle="@string/avatar_wheelchair"/>
<com.habitrpg.android.habitica.ui.views.EquipmentItemRow
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/avatar_accent_view"
app:equipmentTitle="@string/avatar_accent" />
<com.habitrpg.android.habitica.ui.views.EquipmentItemRow
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/avatar_animal_ears_view"
android:visibility="gone"
app:equipmentTitle="@string/animal_ears"/>
<com.habitrpg.android.habitica.ui.views.EquipmentItemRow
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/avatar_animal_tail_view"
android:visibility="gone"
app:equipmentTitle="@string/animal_tail"/>
<com.habitrpg.android.habitica.ui.views.EquipmentItemRow
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/avatar_headband_view"
app:equipmentTitle="@string/avatar_headband"/>
</LinearLayout>
</androidx.cardview.widget.CardView>
<TextView
@ -105,11 +151,6 @@
android:layout_height="wrap_content"
android:id="@+id/avatarHairBangsView"
app:equipmentTitle="@string/avatar_bangs" />
<com.habitrpg.android.habitica.ui.views.EquipmentItemRow
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/avatarHairFlowerView"
app:equipmentTitle="@string/avatar_flower" />
<com.habitrpg.android.habitica.ui.views.EquipmentItemRow
android:layout_width="match_parent"
android:layout_height="wrap_content"

View file

@ -1,36 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbarSize="3dp"
android:scrollbarThumbVertical="@color/scrollbarThumb"
android:scrollbars="vertical">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:id="@+id/questionTextView"
android:layout_gravity="center_horizontal"
android:padding="@dimen/card_padding"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/answerTextView"
android:layout_gravity="center_horizontal"
android:paddingLeft="@dimen/card_padding"
android:paddingStart="@dimen/card_padding"
android:paddingEnd="@dimen/card_padding"
android:paddingRight="@dimen/card_padding"
android:textAppearance="?android:attr/textAppearanceMedium"
/>
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbarSize="3dp"
android:scrollbarThumbVertical="@color/scrollbarThumb"
android:scrollbars="vertical">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:id="@+id/questionTextView"
android:layout_gravity="center_horizontal"
android:padding="@dimen/card_padding"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/answerTextView"
android:layout_gravity="center_horizontal"
android:paddingLeft="@dimen/card_padding"
android:paddingStart="@dimen/card_padding"
android:paddingEnd="@dimen/card_padding"
android:paddingRight="@dimen/card_padding"
android:textAppearance="?android:attr/textAppearanceMedium"
/>
</LinearLayout>
</androidx.core.widget.NestedScrollView>

View file

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView 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="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="@color/white">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/game_mechanics"
style="@style/SectionHeaderCaps"
android:layout_marginTop="@dimen/spacing_large"/>
<com.habitrpg.android.habitica.ui.views.SupportCollapsibleSection
android:id="@+id/health_section"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:subtitle="HP"
app:title="@string/health_points"
app:titleColor="@color/red_10"
android:layout_marginStart="@dimen/spacing_medium"
android:layout_marginEnd="@dimen/spacing_medium"
android:layout_marginBottom="@dimen/spacing_medium"
android:layout_marginTop="@dimen/spacing_medium"
app:description="@string/health_description"/>
<com.habitrpg.android.habitica.ui.views.SupportCollapsibleSection
android:id="@+id/experience_section"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:subtitle="EXP"
app:title="@string/experience_points"
app:titleColor="@color/yellow_50"
android:layout_marginStart="@dimen/spacing_medium"
android:layout_marginEnd="@dimen/spacing_medium"
android:layout_marginBottom="@dimen/spacing_medium"
app:description="@string/experience_description"/>
<com.habitrpg.android.habitica.ui.views.SupportCollapsibleSection
android:id="@+id/mana_section"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:subtitle="MP"
app:title="@string/mana_points"
app:titleColor="@color/blue_10"
android:layout_marginStart="@dimen/spacing_medium"
android:layout_marginEnd="@dimen/spacing_medium"
android:layout_marginBottom="@dimen/spacing_medium"
app:description="@string/mana_description"/>
<com.habitrpg.android.habitica.ui.views.SupportCollapsibleSection
android:id="@+id/gold_section"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:subtitle="@string/currency"
app:title="@string/gold_capitalilzed"
app:titleColor="@color/orange_10"
android:layout_marginStart="@dimen/spacing_medium"
android:layout_marginEnd="@dimen/spacing_medium"
android:layout_marginBottom="@dimen/spacing_medium"
app:description="@string/gold_description"/>
<com.habitrpg.android.habitica.ui.views.SupportCollapsibleSection
android:id="@+id/gems_section"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:subtitle="@string/premium_currency"
app:title="@string/gems"
app:titleColor="@color/green_10"
android:layout_marginStart="@dimen/spacing_medium"
android:layout_marginEnd="@dimen/spacing_medium"
android:layout_marginBottom="@dimen/spacing_medium"
app:description="@string/gems_description"/>
<com.habitrpg.android.habitica.ui.views.SupportCollapsibleSection
android:id="@+id/hourglasses_section"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:subtitle="@string/subscriber_currency"
app:title="@string/mystic_hourglasses"
app:titleColor="@color/brand_300"
android:layout_marginStart="@dimen/spacing_medium"
android:layout_marginEnd="@dimen/spacing_medium"
android:layout_marginBottom="@dimen/spacing_medium"
app:description="@string/hourglasses_description"/>
<com.habitrpg.android.habitica.ui.views.SupportCollapsibleSection
android:id="@+id/stats_section"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:subtitle="STR, CON, INT, PER"
app:title="@string/stat_allocation"
app:titleColor="#7f3300"
android:layout_marginStart="@dimen/spacing_medium"
android:layout_marginEnd="@dimen/spacing_medium"
android:layout_marginBottom="@dimen/spacing_medium"
app:description="@string/stat_description"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/common_questions"
style="@style/SectionHeaderCaps"
android:layout_marginTop="@dimen/spacing_large"/>
<LinearLayout
android:id="@+id/faq_linear_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" />
<TextView
android:id="@+id/more_help_text_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/spacing_large"
android:paddingTop="@dimen/spacing_large"
android:paddingStart="@dimen/spacing_large"
android:paddingEnd="@dimen/spacing_large"
android:paddingBottom="@dimen/spacing_large"
android:background="@color/gray_700"/>
</LinearLayout>
</ScrollView>

View file

@ -40,7 +40,7 @@
tools:text="@string/intro_2_title"
android:layout_marginBottom="28dp" />
<com.facebook.drawee.view.SimpleDraweeView
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/imageView"

View file

@ -5,56 +5,57 @@
android:id="@+id/refreshLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
android:background="@color/gray_700">
android:background="@color/gray_700"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="@+id/emptyView"
style="@style/EmptyView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="60dp"
android:orientation="vertical"
android:visibility="gone"
tools:visibility="visible">
<ImageView
android:id="@+id/empty_icon_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp" />
<TextView
android:id="@+id/emptyViewTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="6dp"
android:gravity="center"
android:textColor="@color/gray_200"
android:textSize="@dimen/card_medium_text"
tools:text="No Items" />
<TextView
android:id="@+id/emptyViewDescription"
style="@style/Body2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:textColor="@color/gray_200"
tools:text="No Items" />
</LinearLayout>
<com.habitrpg.android.habitica.ui.helpers.RecyclerViewEmptySupport
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:scrollbarSize="3dp"
android:scrollbarThumbVertical="@color/scrollbarThumb"
android:scrollbars="vertical"
android:clipToPadding="false" />
<LinearLayout
android:id="@+id/emptyView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginTop="30dp"
android:gravity="center"
android:visibility="gone"
tools:visibility="visible">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
style="@style/EmptyView">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/emptyViewTitle"
tools:text="No Items"
android:gravity="center"
android:textSize="@dimen/card_medium_text"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/emptyViewDescription"
android:gravity="center"
tools:text="No Items" />
</LinearLayout>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/justin_textbox"
android:layout_marginTop="16dp"
/>
</LinearLayout>
android:scrollbars="vertical" />
</FrameLayout>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

View file

@ -5,5 +5,6 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbarSize="3dp"
android:background="@color/white"
android:scrollbarThumbVertical="@color/scrollbarThumb"
android:scrollbars="vertical" />

View file

@ -0,0 +1,115 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/support_bug_title"
android:textSize="13sp"
android:textColor="@color/gray_200"
android:paddingTop="13dp"
android:paddingBottom="13dp"
android:paddingStart="24dp"
android:paddingEnd="24dp"
android:layout_margin="@dimen/spacing_medium"
android:gravity="center"
android:background="@color/gray_700"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/common_fixes"
android:layout_marginStart="@dimen/spacing_large"
style="@style/SectionHeaderCaps"
/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="12dp"
android:orientation="vertical"
android:background="@drawable/layout_rounded_bg_gray_700"
android:layout_margin="@dimen/spacing_medium">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/clear_cache"
android:textColor="@color/black"
style="@style/Body1"
android:layout_marginBottom="4dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/clear_cache_description"
style="@style/Body2"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="12dp"
android:orientation="vertical"
android:background="@drawable/layout_rounded_bg_gray_700"
android:layout_margin="@dimen/spacing_medium">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/manual_sync_restart"
android:textColor="@color/black"
style="@style/Body1"
android:layout_marginBottom="4dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/manual_sync_restart_description"
style="@style/Body2"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="12dp"
android:orientation="vertical"
android:background="@drawable/layout_rounded_bg_gray_700"
android:layout_margin="@dimen/spacing_medium">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/update_app"
android:textColor="@color/black"
style="@style/Body1"
android:layout_marginBottom="4dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/update_app_description"
style="@style/Body2"/>
</LinearLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/need_more_help"
android:gravity="center"
android:textStyle="bold"
android:textColor="@color/brand_300"
android:textSize="16sp"
android:layout_marginTop="@dimen/spacing_large"
/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/send_bug_prompt"
android:textColor="@color/gray_300"
android:gravity="center"
android:textSize="14sp"
android:layout_marginTop="@dimen/spacing_small"
android:layout_marginBottom="@dimen/spacing_large"/>
<Button
android:id="@+id/report_bug_button"
android:layout_width="match_parent"
android:layout_height="40dp"
style="@style/HabiticaButton.Purple"
android:text="@string/report_bug"
android:elevation="0dp"
android:layout_marginStart="@dimen/spacing_large"
android:layout_marginEnd="@dimen/spacing_large" />
</LinearLayout>

View file

@ -0,0 +1,171 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/layout_rounded_bg_gray_700">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="@color/white"
android:paddingTop="@dimen/spacing_large"
android:paddingBottom="@dimen/spacing_large">
<LinearLayout
android:id="@+id/using_habitica_wrapper"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/spacing_large"
android:layout_marginEnd="@dimen/spacing_large"
android:gravity="center_horizontal"
android:paddingTop="@dimen/spacing_large"
android:background="@drawable/layout_rounded_bg_gray_700"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/habitica_questions"
android:layout_marginStart="@dimen/spacing_large"
android:layout_marginEnd="@dimen/spacing_large"
style="@style/Subheader2"
android:textColor="@color/black"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/using_habitica_description"
style="@style/Body2"
android:textColor="@color/gray_50"
android:layout_marginStart="40dp"
android:layout_marginEnd="40dp"
android:gravity="center"
android:layout_marginTop="6dp"
android:layout_marginBottom="16dp"
/>
<TextView
android:layout_width="match_parent"
android:layout_height="38dp"
android:text="@string/read_more"
android:gravity="center"
android:layout_marginStart="@dimen/spacing_medium"
android:layout_marginEnd="@dimen/spacing_medium"
android:layout_marginBottom="@dimen/spacing_medium"
android:background="@drawable/support_info_lower_bg"
android:textColor="@color/white"
android:textAllCaps="false"
android:textStyle="bold"
android:textSize="12sp"
/>
</LinearLayout>
<LinearLayout
android:id="@+id/bugs_fixes_wrapper"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/spacing_large"
android:layout_marginEnd="@dimen/spacing_large"
android:gravity="center_horizontal"
android:paddingTop="@dimen/spacing_large"
android:layout_marginTop="@dimen/spacing_medium"
android:background="@drawable/layout_rounded_bg_gray_700"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/bugs_fixes"
android:layout_marginStart="@dimen/spacing_large"
android:layout_marginEnd="@dimen/spacing_large"
style="@style/Subheader2"
android:textColor="@color/black"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/bugs_fixes_description"
style="@style/Body2"
android:textColor="@color/gray_50"
android:layout_marginStart="40dp"
android:layout_marginEnd="40dp"
android:gravity="center"
android:layout_marginTop="6dp"
android:layout_marginBottom="16dp"
/>
<TextView
android:layout_width="match_parent"
android:layout_height="38dp"
android:text="@string/get_help"
android:gravity="center"
android:layout_marginStart="@dimen/spacing_medium"
android:layout_marginEnd="@dimen/spacing_medium"
android:layout_marginBottom="@dimen/spacing_medium"
android:background="@drawable/support_info_lower_bg"
android:textColor="@color/white"
android:textAllCaps="false"
android:textStyle="bold"
android:textSize="12sp"
/>
</LinearLayout>
<LinearLayout
android:id="@+id/suggestions_feedback_wrapper"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/spacing_medium"
android:layout_marginStart="@dimen/spacing_large"
android:layout_marginEnd="@dimen/spacing_large"
android:background="@drawable/layout_rounded_bg_gray_700"
android:gravity="center_horizontal"
android:paddingTop="@dimen/spacing_large"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/suggestions_feedback"
android:layout_marginStart="@dimen/spacing_large"
android:layout_marginEnd="@dimen/spacing_large"
style="@style/Subheader2"
android:textColor="@color/black"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/suggestions_feedback_description"
style="@style/Body2"
android:textColor="@color/gray_50"
android:layout_marginStart="40dp"
android:layout_marginEnd="40dp"
android:gravity="center"
android:layout_marginTop="6dp"
android:layout_marginBottom="16dp"
/>
<TextView
android:layout_width="match_parent"
android:layout_height="38dp"
android:text="@string/contact_us"
android:gravity="center"
android:layout_marginStart="@dimen/spacing_medium"
android:layout_marginEnd="@dimen/spacing_medium"
android:layout_marginBottom="@dimen/spacing_medium"
android:background="@drawable/support_info_lower_bg"
android:textColor="@color/white"
android:textStyle="bold"
android:textAllCaps="false"
android:textSize="12sp"
/>
</LinearLayout>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/gray_500"/>
<Button
android:id="@+id/reset_tutorial_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/HabiticaButton.Gray.600"
android:textColor="@color/gray_50"
android:text="@string/reset_walkthrough"
android:layout_margin="@dimen/spacing_large"/>
</LinearLayout>

View file

@ -13,7 +13,7 @@
android:layout_width="@dimen/gear_image_size"
android:layout_height="@dimen/gear_image_size"
actualImageScaleType="fitCenter"
android:layout_marginRight="@dimen/row_padding"/>
android:layout_marginEnd="@dimen/row_padding"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"

View file

@ -25,7 +25,8 @@
<LinearLayout
android:id="@+id/buyButton"
android:layout_width="match_parent"
android:layout_height="32dp"
android:layout_height="wrap_content"
android:minHeight="40dp"
android:gravity="center"
android:background="@drawable/layout_rounded_bg_shopitem_price">
<com.habitrpg.android.habitica.ui.views.CurrencyView
@ -41,11 +42,13 @@
android:id="@+id/unlockLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:layout_gravity="center_horizontal"
android:gravity="center"
android:layout_gravity="center"
style="@style/Body1"
android:textSize="12sp"
android:textSize="11sp"
android:textColor="@color/gray_300"
android:paddingStart="2dp"
android:paddingRight="2dp"
/>
</LinearLayout>
</LinearLayout>

View file

@ -1,17 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
style="@style/RowWrapper"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/layout_rounded_bg_gray_700"
android:clipToPadding="true"
android:clipChildren="true"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_marginTop="4dp"
android:layout_marginBottom="4dp">
<com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/skill_image"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_gravity="center_vertical" />
android:layout_gravity="center_vertical"
android:layout_marginLeft="8dp"/>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
@ -20,7 +30,9 @@
android:layout_marginRight="8dp"
android:layout_weight="1"
android:gravity="center_vertical"
android:orientation="vertical">
android:orientation="vertical"
android:layout_marginTop="12dp"
android:layout_marginBottom="12dp">
<TextView
android:id="@+id/skill_text"
@ -36,20 +48,33 @@
style="@style/Caption2.Regular"
tools:text="This is the spell description"/>
</LinearLayout>
<Button
android:id="@+id/price_button"
android:layout_width="wrap_content"
android:layout_height="32dp"
android:minWidth="64dp"
android:layout_gravity="center_vertical"
android:gravity="left|center_vertical"
android:drawablePadding="5dp"
android:background="@drawable/rounded_purple_square"
android:paddingLeft="12dp"
android:paddingStart="12dp"
android:paddingRight="12dp"
android:paddingEnd="12dp"
<LinearLayout
android:id="@+id/button_wrapper"
android:layout_width="48dp"
android:layout_height="match_parent"
android:background="@color/blue_500"
android:orientation="vertical"
android:gravity="center">
<ImageView
android:id="@+id/button_icon_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/price_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>
<TextView
android:id="@+id/count_label"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_alignParentTop="true"
android:layout_alignParentStart="true"
android:layout_marginStart="13dp"
android:background="@drawable/circle_gray300"
tools:text="1"
android:textColor="@color/white"
tools:text="150"
android:textSize="15sp" />
</LinearLayout>
android:gravity="center"
/>
</RelativeLayout>

View file

@ -0,0 +1,59 @@
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:parentTag="android.widget.LinearLayout">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/spacing_medium"
android:layout_marginBottom="@dimen/spacing_medium"
android:gravity="center_vertical">
<ImageView
android:id="@+id/icon_view"
android:layout_width="28dp"
android:layout_height="28dp"
android:layout_marginStart="@dimen/spacing_large"
android:layout_marginEnd="@dimen/spacing_large"
/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/title_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/Body1"
tools:text="Title"/>
<TextView
android:id="@+id/subtitle_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/gray_200"
style="@style/Body2"
tools:text="Subtitle" />
</LinearLayout>
<Space
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content" />
<ImageView
android:id="@+id/caret_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_keyboard_arrow_down_black_24dp"
android:layout_marginEnd="@dimen/spacing_large"/>
</LinearLayout>
<TextView android:id="@+id/description_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/spacing_large"
android:layout_marginEnd="@dimen/spacing_large"
android:layout_marginTop="@dimen/spacing_medium"
android:layout_marginBottom="12dp"
android:visibility="gone"
/>
</merge>

View file

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:minHeight="40dp">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/support_faq"
android:layout_marginLeft="26dp"
android:layout_marginRight="29dp"/>
<TextView
android:id="@+id/text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="14sp"
android:textColor="@color/gray_100"
tools:text="Title"
android:layout_marginRight="@dimen/spacing_large"
android:layout_marginTop="@dimen/spacing_medium"
android:layout_marginBottom="@dimen/spacing_medium"
/>
</LinearLayout>

View file

@ -0,0 +1,10 @@
<menu 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"
tools:context="com.habitrpg.android.habitica.TaskActivity">
<item android:id="@+id/send_message"
android:icon="@drawable/menu_messages"
android:title="@string/send_message"
app:showAsAction="ifRoom" />
</menu>

View file

@ -0,0 +1,6 @@
<menu 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">
<item android:id="@+id/open_profile" android:title="@string/profile"
android:orderInCategory="100" app:showAsAction="always" />
</menu>

View file

@ -110,7 +110,12 @@
<fragment
android:id="@+id/shopsFragment"
android:name="com.habitrpg.android.habitica.ui.fragments.inventory.shops.ShopsFragment"
android:label="@string/sidebar_shops" />
android:label="@string/sidebar_shops" >
<argument
android:name="selectedTab"
app:argType="integer"
android:defaultValue="0" />
</fragment>
<fragment
android:id="@+id/avatarOverviewFragment"
android:name="com.habitrpg.android.habitica.ui.fragments.inventory.customization.AvatarOverviewFragment"
@ -118,6 +123,9 @@
<action
android:id="@+id/openAvatarDetail"
app:destination="@id/avatarCustomizationFragment" />
<action
android:id="@+id/openAvatarEquipment"
app:destination="@id/avatarEquipmentFragment" />
</fragment>
<fragment
android:id="@+id/itemsFragment"
@ -197,13 +205,21 @@
android:label="@string/sidebar_news" />
<fragment
android:id="@+id/FAQOverviewFragment"
android:name="com.habitrpg.android.habitica.ui.fragments.faq.FAQOverviewFragment"
android:label="@string/sidebar_help" >
android:name="com.habitrpg.android.habitica.ui.fragments.support.FAQOverviewFragment"
android:label="@string/habitica_questions">
<deepLink app:uri="habitica.com/static/faq" />
<action
android:id="@+id/openFAQDetail"
app:destination="@id/FAQDetailFragment" />
</fragment>
<fragment
android:id="@+id/FAQDetailFragment"
android:name="com.habitrpg.android.habitica.ui.fragments.support.FAQDetailFragment"
android:label="@string/sidebar_help" >
<argument
android:name="position"
app:argType="integer" />
</fragment>
<fragment
android:id="@+id/aboutFragment"
android:name="com.habitrpg.android.habitica.ui.fragments.AboutFragment"
@ -241,14 +257,6 @@
android:id="@+id/openGuildDetail"
app:destination="@id/guildFragment" />
</fragment>
<fragment
android:id="@+id/FAQDetailFragment"
android:name="com.habitrpg.android.habitica.ui.fragments.faq.FAQDetailFragment"
android:label="@string/sidebar_help" >
<argument
android:name="position"
app:argType="integer" />
</fragment>
<fragment
android:id="@+id/avatarCustomizationFragment"
android:name="com.habitrpg.android.habitica.ui.fragments.inventory.customization.AvatarCustomizationFragment"
@ -260,6 +268,17 @@
android:name="category"
app:argType="string" />
</fragment>
<fragment
android:id="@+id/avatarEquipmentFragment"
android:name="com.habitrpg.android.habitica.ui.fragments.inventory.customization.AvatarEquipmentFragment"
android:label="@string/sidebar_avatar" >
<argument
android:name="type"
app:argType="string" />
<argument
android:name="category"
app:argType="string" />
</fragment>
<activity
android:id="@+id/prefsActivity"
android:name="com.habitrpg.android.habitica.ui.activities.PrefsActivity"
@ -382,4 +401,32 @@
app:argType="string"
app:nullable="true" />
</fragment>
<fragment
android:id="@+id/marketFragment"
android:name="com.habitrpg.android.habitica.ui.fragments.inventory.shops.MarketFragment"
android:label="@string/market" />
<fragment
android:id="@+id/questShopFragment"
android:name="com.habitrpg.android.habitica.ui.fragments.inventory.shops.QuestShopFragment"
android:label="@string/questShop" />
<fragment
android:id="@+id/seasonalShopFragment"
android:name="com.habitrpg.android.habitica.ui.fragments.inventory.shops.SeasonalShopFragment"
android:label="@string/seasonalShop" />
<fragment
android:id="@+id/timeTravelersShopFragment"
android:name="com.habitrpg.android.habitica.ui.fragments.inventory.shops.TimeTravelersShopFragment"
android:label="@string/timeTravelers" />
<fragment
android:id="@+id/supportMainFragment"
android:name="com.habitrpg.android.habitica.ui.fragments.support.SupportMainFragment"
android:label="@string/support" >
<action
android:id="@+id/showFAQFragment"
app:destination="@id/FAQOverviewFragment" />
</fragment>
<fragment
android:id="@+id/bugFixFragment"
android:name="com.habitrpg.android.habitica.ui.fragments.support.BugFixFragment"
android:label="@string/bugs_fixes" />
</navigation>

View file

@ -1,2 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources></resources>

View file

@ -1,696 +0,0 @@
<?xml version='1.0' encoding='UTF-8'?>
<resources xmlns:tools="http://schemas.android.com/tools">
<string name="action_refresh">Muat Ulang</string>
<string name="XP_default">Pengalaman </string>
<string name="HP_default">Nyawa</string>
<string name="MP_default">Mana</string>
<string name="ERR_pb_barcode">Pengaturan tidak dapat dimuat dari barkode</string>
<!--Prefs-->
<string name="PS_settings_title">Pengaturan</string>
<string name="SP_address_hint">Server kustom anda</string>
<string name="SP_userID_title">ID Pengguna</string>
<string name="SP_userID_summary">ID Penggunamu</string>
<string name="SP_APIToken_title">Token API</string>
<string name="SP_APIToken_summary">Token API-mu</string>
<string name="Language_title">Bahasa</string>
<string name="Language_summary">Ganti bahasa dalam Habitica</string>
<string name="SP_user_qr_code">Kode QR-mu</string>
<string name="PS_contact_title">Kontak saya</string>
<string name="unknown_error">Terjadi kesalahan...</string>
<string name="pref_account_header">Akun</string>
<string name="pref_first_day_of_the_week_title">Hari Pertama dalam Minggu</string>
<string name="pref_first_day_of_the_week_summary">Hari pertama dalam minggu di semua kalender</string>
<string name="pref_reminder_header">Pengingat Harian</string>
<string name="pref_reminder_checkbox">Aktifkan Pengingat</string>
<string name="pref_reminder_picker">Atur Waktu Pengingat</string>
<string name="pref_cds_header">Awal Hari</string>
<string name="pref_cds_picker">Atur Awal Hari</string>
<string name="pref_push_notifications_checkbox">Notifikasi Pengguna</string>
<string name="push_notifications">Notifikasi</string>
<string name="push_notifications_sum">Pengaturan notifikasi</string>
<string name="preference_push_you_won_challenge">Kamu memenangkan sebuah Tantangan!</string>
<string name="preference_push_received_a_private_message">Menerima sebuah Pesan Pribadi</string>
<string name="preference_push_gifted_gems">Mendapat Hadiah Permata</string>
<string name="preference_push_gifted_subscription">Mendapat Hadiah Langganan</string>
<string name="preference_push_invited_to_party">Diundang ke Party</string>
<string name="preference_push_invited_to_guild">Diundang ke Guild</string>
<string name="preference_push_your_quest_has_begun">Misimu telah Dimulai</string>
<string name="preference_push_invited_to_quest">Diundang ke dalam Misi</string>
<!--Adding tasks-->
<string name="task_value">Nilai</string>
<string name="new_todo">To-Do baru</string>
<string name="new_reward">Hadiah baru</string>
<string name="new_daily">Keseharian baru</string>
<string name="new_habit">Kebiasaan baru</string>
<string name="action_edit">Edit</string>
<string name="action_delete">Hapus</string>
<string name="action_cancel">Batal</string>
<string name="login_btn">Masuk</string>
<string name="register_btn">Daftar</string>
<string name="username">Nama Pengguna</string>
<string name="email_username">Email atau Nama Pengguna</string>
<string name="password">Kata Sandi</string>
<string name="emailAddress">Alamat Email</string>
<string name="confirmpassword">Konfirmasi kata sandi</string>
<string name="logout">Keluar</string>
<string name="logout_description">Keluar dari akunmu</string>
<string name="account_details">Detail Akun</string>
<string name="LoginActivityName">Selamat Datang</string>
<string name="string_revive">Pulihkan</string>
<string name="please_connect">Silakan hubungkan melalui aplikasi sebelum menggunakan widget</string>
<string name="about.title">Tentang Kami</string>
<string name="about.libraries">Pustaka</string>
<string name="about.versionhistory">Riwayat Versi</string>
<string name="about.habitica_open_source">Habitica tersedia sebagai perangkat lunak open source pada Github</string>
<string name="about.rate_our_app">Nilai Aplikasi kami</string>
<string name="about.give_us_feedback">Kirimkan kami Feedback!</string>
<string name="about.bugreport">Laporkan Gangguan</string>
<string name="about.source_code">Kode</string>
<string name="repeatEvery">Ulangi Setiap</string>
<!--Network Errors-->
<string name="network_error_title">Koneksi Gagal</string>
<string name="network_error_no_network_body">Kamu tidak terhubung ke internet.</string>
<string name="internal_error_api">Terdapat masalah pada server. Cobalah beberapa saat lagi.</string>
<string name="authentication_error_title">Autentikasi Gagal</string>
<string name="authentication_error_body">Nama Pengguna dan/atau Kata Sandi salah.</string>
<string name="login_validation_error_title">Validasi Gagal</string>
<string name="login_validation_error_fieldsmissing">Kamu harus mengisi semua kolom.</string>
<string name="save_changes">Simpan</string>
<string name="copy">Salin</string>
<string name="notes">Catatan</string>
<string name="text">Teks</string>
<string name="difficulty">Tingkat Kesulitan</string>
<string name="tags">Label</string>
<string name="trivial">Trivial</string>
<string name="easy">Mudah</string>
<string name="medium">Sedang</string>
<string name="hard">Susah</string>
<string name="start_date">Tanggal Mulai</string>
<string name="positive_habit_form">Positif (+)</string>
<string name="negative_habit_form">Negatif (-)</string>
<string name="checklist">Daftar Cek</string>
<string name="reminders">Pengingat</string>
<string name="actions">Aksi</string>
<string name="attributes">Atribut</string>
<string name="physical">Kekuatan</string>
<string name="mental">Kecerdasan</string>
<string name="social">Ketahanan</string>
<string name="other">Persepsi</string>
<string name="frequency">Frekuensi</string>
<string name="frequency_weekly">Pada Hari Tertentu dalam Seminggu</string>
<string name="frequency_daily">Setiap X Hari</string>
<string name="repeatables_summary_title">Ringkasan</string>
<string name="repeatables_title">Ulangi</string>
<string name="repeatables_on_title">Ulangi pada</string>
<string name="repeatables_frequency_daily">Harian</string>
<string name="repeatables_frequency_weekly">Mingguan</string>
<string name="repeatables_frequency_monthly">Bulanan</string>
<string name="repeatables_frequency_yearly">Tahunan</string>
<string name="repeatables_frequency_day_of_month">Hari pada Bulan</string>
<string name="repeatables_frequency_day_of_week">Hari pada Minggu</string>
<string name="monday">Senin</string>
<string name="tuesday">Selasa</string>
<string name="wednesday">Rabu</string>
<string name="thursday">Kamis</string>
<string name="friday">Jumat</string>
<string name="saturday">Sabtu</string>
<string name="sunday">Minggu</string>
<string name="levelup_button">Hore!</string>
<string name="faint_subtitle">Jangan bersedih!</string>
<string name="faint_header">Kamu kehabisan Nyawa!</string>
<string name="faint_button">Isi ulang Nyawa &amp; Ulang Lagi</string>
<string name="filter">Filter</string>
<string name="profile_image">Gambar Profil</string>
<string name="mana_price_button">%d MP</string>
<string name="used_skill">Kamu menggunakan %1$s dengan %2$d mana.</string>
<string name="used_skill_without_mana">Kamu menggunakan %1$s</string>
<string name="new_checklist_item">item cek baru</string>
<string name="add_checklist_item">Tambahkan</string>
<string name="skill_progress_title">Gunakan Kemampuan</string>
<string name="coming_soon">Akan Datang</string>
<string name="chat_flag_confirmation">Apakah kamu yakin kamu ingin melaporkan pesan ini sebagai pelanggaran?</string>
<string name="flag_confirm">Laporkan Pesan</string>
<string name="unlock_lvl_11">Buka pada lvl 11</string>
<string name="no_party_message">Kamu tidak memiliki party. Untuk bergabung dengan party, silakan kunjungi situs.</string>
<string name="forgot_pw_btn">Lupa Kata Sandi</string>
<string name="tavern.inn.checkOut">Aktifkan kembali Keseharianmu</string>
<string name="tavern.inn.rest">Nonaktifkan Keseharianmu</string>
<string name="reward.dialog.buy">Beli</string>
<string name="reward.dialog.dismiss">Tutup</string>
<string name="party">Party</string>
<string name="chat">Obrolan</string>
<string name="members">Anggota</string>
<string name="habits">Kebiasaan</string>
<string name="dailies">Keseharian</string>
<string name="todos">To-Do</string>
<string name="rewards">Hadiah</string>
<string name="taskform.delete.title">Apakah kamu yakin?</string>
<string name="taskform.delete.message">Apakah kamu benar-benar ingin menghapusnya?</string>
<string name="yes">Ya</string>
<string name="no">Tidak</string>
<string name="quest">Misi</string>
<string name="avatar_body">Tubuh</string>
<string name="avatar_hair">Rambut</string>
<string name="avatar_shirt">Baju</string>
<string name="avatar_skin">Kulit</string>
<string name="avatar_ears">Telinga Hewan</string>
<string name="avatar_base">Biasa</string>
<string name="avatar_color">Warna</string>
<string name="avatar_beard">Janggut</string>
<string name="avatar_mustache">Kumis</string>
<string name="avatar_flower">Bunga</string>
<string name="avatar_bangs">Poni</string>
<string name="avatar_nothing">Tidak ada yang digunakan</string>
<string name="avatar_size">Ukuran</string>
<string name="avatar_size_slim">Kurus</string>
<string name="avatar_size_broad">Bidang</string>
<string name="avatar_background">Latar Belakang</string>
<string name="purchase_customization">Beli Item</string>
<string name="purchase_set_button">Buka set seharga %d permata</string>
<string name="purchase_button">Beli</string>
<string name="purchase_set_title">Beli set %s</string>
<string name="due_date">Tenggat Waktu</string>
<string name="quest.accept">Terima</string>
<string name="quest.reject">Tolak</string>
<string name="quest.begin">Mulai Misi</string>
<string name="quest.cancel">Batalkan Undangan</string>
<string name="quest.abort">Batalkan Misi</string>
<string name="quest.leave">Tinggalkan Misi</string>
<string name="quest.pending">Menunggu</string>
<string name="quest.accepted">Diterima</string>
<string name="quest.rejected">Ditolak</string>
<string name="quest.participants">Partisipan</string>
<string name="version_info">Versi %1$s (%2$d)</string>
<string name="sidebar_help">Bantuan &amp; FAQ</string>
<string name="complete_tutorial">Aku mengerti!</string>
<string name="dismiss_tutorial">Ingatkan aku lagi</string>
<string name="intro_1_subtitle">Selamat datang di</string>
<string name="intro_1_title">Habitica</string>
<string name="intro_1_description">Ini saatnya untuk bersenang-senang sambil benar-benar menyelesaikan urusan-urusanmu. Bergabunglah dengan lebih dari %s orang yang memperbaiki aspek hidup mereka satu demi satu.</string>
<string name="intro_2_subtitle">Berkembang di dalam game</string>
<string name="intro_2_title">Berkembang di kehidupan nyata</string>
<string name="intro_2_description">Buka fitur dalam game dengan mengerjakan tugasmu di dunia nyata. Dapatkan baju, peliharaan, dan banyak lagi sebagai hadiahmu mencapai tujuan!</string>
<string name="intro_3_subtitle">Bertarung dengan monster</string>
<string name="intro_3_title">Menjadi lebih sosial</string>
<string name="intro_3_description">Tetaplah berusaha meraih tujuan dengan bantuan teman-teman. Dukung satu sama lain dalam hidup dan bertarunglah sekaligus meningkatkan kehidupan bersama-sama!</string>
<string name="intro_finish_button">Mari mulai!</string>
<string name="previous_button">Sebelumnya</string>
<string name="next_button">Berikutnya</string>
<string name="skip_button">Lewati</string>
<string name="setup_welcome_description">Selamat datang di Habitica, di mana meningkatkan diri dalam permainan akan meningkatkan kehidupan nyata! Seiring kamu menyelesaikan tujuan dunia-nyata, kamu akan membuka perlengkapan, peliharaan, misi, dan banyak lagi.</string>
<string name="setup_welcome_title">Selamat Datang</string>
<string name="avatar_setup_description">Jadi, kamu mau terlihat seperti apa? Jangan khawatir, kamu bisa mengubahnya lagi nanti.</string>
<string name="task_setup_description">Bagus! Sekarang, apa yang menurutmu menarik untuk kamu kembangkan dalam pengembaraan ini?</string>
<string name="setup_group_work">Pekerjaan</string>
<string name="setup_group_exercise">Olahraga</string>
<string name="setup_group_health">Kesehatan</string>
<string name="setup_group_school">Sekolah</string>
<string name="setup_group_teams">Tim</string>
<string name="setup_group_chores">Pekerjaan Rumah Tangga</string>
<string name="setup_group_creativity">Kreativitas</string>
<string name="setup_task_work_1">Proses Email</string>
<string name="setup_task_work_2">Tugas paling penting</string>
<string name="setup_task_work_3">Proyek Kerja</string>
<string name="setup_task_exercise_1">10 menit cardio</string>
<string name="setup_task_exercise_2">Stretching</string>
<string name="setup_task_exercise_3">Atur jadwal olahraga</string>
<string name="setup_task_healthWellness_1">Makan makanan bergizi / cepat saji</string>
<string name="setup_task_healthWellness_2">Gunakan Benang Gigi</string>
<string name="setup_task_healthWellness_3">Periksa Jadwal</string>
<string name="setup_task_school_1">Belajar/Bermalas-malasan</string>
<string name="setup_task_school_2">Mengerjakan PR</string>
<string name="setup_task_school_3">Selesaikan tugas</string>
<string name="setup_task_teams_1">Periksa tim</string>
<string name="setup_task_teams_2">Kabari tim mengenai status terbaru</string>
<string name="setup_task_teams_3">Selesaikan proyek tim</string>
<string name="setup_task_chores_1">10 menit bersih-bersih</string>
<string name="setup_task_chores_2">Cuci Piring</string>
<string name="setup_task_chores_3">Rapikan lemari</string>
<string name="setup_task_creativity_1">Belajar menguasai kerajinan tangan</string>
<string name="setup_task_creativity_2">Mengerjakan proyek kreatif</string>
<string name="setup_task_creativity_3">Menyelesaikan proyek kreatif</string>
<string name="gem.purchase.support">Ingin membantu kami menjaga Habitica tetap berjalan? Kamu dapat mendukung pengembang dengan membeli permata!\n\nDengan permata kamu dapat membeli hal-hal menarik untuk akunmu, termasuk: \n\n - Kostum keren untuk avatarmu\n - Latar belakang keren\n - Misi menarik yang memberimu hadiah telur peliharaan unik\n - Kemampuan untuk mengganti pekerjaan sebelum level 100\n\nTerima kasih banyak untuk bantuan kepada Habitca untuk menjadi yang terbaik. Dukunganmu sangat berarti bagi kami!</string>
<string name="my_guilds">Guild-ku</string>
<string name="public_guilds">Guild Publik</string>
<string name="guild">Guild</string>
<string name="leave">Tinggalkan</string>
<string name="join">Gabung</string>
<string name="leader">Ketua</string>
<string name="gems">Permata</string>
<string name="copy_as_todo">Salin sebagai To-Do</string>
<string name="send_pm">Kirim PM</string>
<string name="flag">Laporkan</string>
<string name="delete">Hapus</string>
<string name="name">Nama </string>
<string name="description">Deskripsi</string>
<string name="add_tag">Tambahkan Label baru</string>
<string name="privacy">Privasi</string>
<string name="write_message">Tulis Pesan</string>
<string name="post">Kirim</string>
<string name="guild_search_hint">Cari guild</string>
<string name="todo_due">Tenggat: %s</string>
<string name="daily_streak">jumlah runtunan: %d</string>
<string name="todo_has_duedate">Tugas memiliki Tenggat Waktu</string>
<string name="battle_gear">Perlengkapan Bertarung</string>
<string name="costume">Kostum</string>
<string name="outfit_head">Kepala</string>
<string name="outfit_headAccessory">Aksesori Kepala</string>
<string name="outfit_eyewear">Aksesori Mata</string>
<string name="outfit_armor">Baju Perang</string>
<string name="outfit_back">Punggung</string>
<string name="outfit_body">Tubuh</string>
<string name="outfit_shield">Perisai</string>
<string name="outfit_weapon">Senjata</string>
<string name="wear_costume">Gunakan Kostum</string>
<string name="equipped">Digunakan</string>
<string name="quest_cancel_message">Apakah kamu yakin kamu ingin membatalkan misi ini? Semua undangan yang disetujui akan hilang. Pemilik misi akan mendapatkan gulungan misi kembali.</string>
<string name="quest.invitation">Undangan Misi</string>
<string name="quest_begin_message">Apakah kamu yakin? Hanya %1$d dari %2$d anggota Party-mu yang sudah ikut misi ini! Misi dimulai secara otomatis ketika semua pemain telah ikut atau menolak undangannya.</string>
<string name="quest.invitation.text">Kamu telah diundang untuk berpartisipasi dalam misi!</string>
<string name="today">Hari Ini</string>
<string name="sidebar_items">Item</string>
<string name="eggs">Telur</string>
<string name="hatching_potions">Ramuan Penetas</string>
<string name="food">Makanan</string>
<string name="quests">Misi</string>
<string name="pets">Peliharaan</string>
<string name="mounts">Tunggangan</string>
<string name="armoireEquipment">Kamu menemukan Perlengkapan langka di dalam Peti Harta Karun: %s! Keren!</string>
<string name="armoireFood">Kamu mengacak-acak Peti Harta Karun dan menemukan %2$s %1$s. Kenapa berada di dalam sini, ya?</string>
<string name="armoireExp">Kamu bergulat dengan Peti Harta Karun dan mendapatkan Pengalaman. Rasakan itu!</string>
<string name="armoireNotesFull">Buka Peti Harta Karun untuk mendapatkan Perlengkapan spesial, Pengalaman, atau makanan secara acak! Perlengkapan yang tersisa: %d</string>
<string name="armoireLastItem">Kamu menemukan Perlengkapan terakhir di dalam Peti Harta Karun.</string>
<string name="armoireNotesEmpty">Peti Harta Karun akan memiliki Perlengkapan baru pada minggu pertama setiap bulan. Sementara itu, tetaplah klik untuk mendapatkan Pengalaman dan Makanan!</string>
<string name="sell">Jual (%d Emas)</string>
<string name="hatch_with_potion">Tetaskan dengan ramuan</string>
<string name="feed_to_pet">Beri makan peliharaan</string>
<string name="hatch_egg">Tetaskan dengan telur</string>
<string name="invite_party">Undang party</string>
<string name="dialog_feeding">Beri makan %s dengan:</string>
<string name="use_animal">Gunakan</string>
<string name="feed">Beri makan</string>
<string name="hatch_with">Tetaskan dengan %s</string>
<string name="hatched_pet_title">Kamu menetaskan seekor %2$s %1$s!</string>
<string name="close">Tutup</string>
<string name="share">Bagikan</string>
<string name="notification_pet_fed">Kamu memberi makan %s!</string>
<string name="notification_purchase_reward">Kamu membeli sebuah hadiah</string>
<string name="world_quest">Misi Dunia</string>
<string name="inn_description">Perlu istirahat? Masuk ke dalam Penginapan Daniel untuk sementara menghentikan mekanika game Habitica yang lebih susah:\n\n
• Keseharian yang terlewat tidak akan menyakitimu\n
• Tugas tidak akan putus runtunannya atau berkurang warnanya\n
• Boss tidak akan menyerangmu untuk Keseharian yang terlewat\n
• Damage-mu kepada Boss atau item misi mengumpulkanmu akan tetap menunggu hingga kamu keluar</string>
<string name="empty_items">Kamu tidak memiliki %s</string>
<string name="user_level">Lvl %d</string>
<string name="user_level_with_class">Lvl %1$d %2$s</string>
<string name="warrior">Warrior</string>
<string name="rogue">Rogue</string>
<string name="mage">Mage</string>
<string name="healer">Healer</string>
<string name="mage_description">Penyihir belajar dengan cepat, mendapatkan Pengalaman dan Level lebih cepat daripada kelas lainnya. Mereka juga mendapatkan Mana yang besar dengan menggunakan kemampuan spesial. Mainkan penyihir jika kamu menyukai aspek taktis dari permainan Kebiasaan, atau jika kamu begitu termotivasi dengan meningkatkan level dan membuka fitur baru!</string>
<string name="rogue_description">Perampok senang mengumpulkan kekayaan, mendapatkan banyak Emas daripada yang lainnya, dan mahir menemukan item acak. Kemampuan Bersembunyi mereka yang terkenal membuat mereka mampu menghindari konsekuensi dari Keseharian yang terlewat. Mainkan Perampok jika kamu termotivasi dengan Hadiah dan Pencapaian, juga mendapatkan banyak barang jarahan dan lencana!</string>
<string name="healer_description">Penyembuh tahan terhadap serangan, dan dapat membagi perlindungannya pada sesama. Keseharian yang terlewat dan kebiasaan buruk tidak terlalu banyak mengganggu mereka, dan mereka memiliki cara untuk mengembalikan nyawa dari kesalahan mereka. Mainkan seorang Penyembuh jika kamu senang membantu teman dalam kelompok, atau ide mencurangi kematian dengan kerja keras membuatmu terinspirasi!</string>
<string name="select_class">Pilih Profesi</string>
<string name="opt_out_class">Matikan Fitur</string>
<string name="opt_out_description">Tidak ingin diganggu dengan profesi? Ingin memilih nanti saja? Matikan fitur - kamu akan menjadi seorang Prajurit tanpa kemampuan spesial. Kamu dapat membaca mengenai sistem profesi nanti di wiki dan mengaktifkan fitur profesi kapan saja.</string>
<string name="class_confirmation">Apakah kamu yakin ingin menjadi seorang %s?</string>
<string name="class_changed">Kamu sekarang seorang %s! </string>
<string name="class_changed_description">Kamu memiliki Baju Perang baru yang dapat diganti pada menu Perlengkapan! </string>
<string name="choose_class">Pilih Kelas</string>
<string name="dialog_go_back">Kembali</string>
<string name="opt_out_confirmation">Apakah kamu yakin kamu ingin mematikan fitur?</string>
<string name="change_class">Ganti profesi</string>
<string name="change_class_description">Ubah kelasmu dan terima kembali poin atribut seharga 3 Permata.</string>
<string name="enable_class">Aktifkan Sistem Profesi</string>
<string name="changing_class_progress">Ganti Profesi</string>
<string name="by_email">Melalui Email</string>
<string name="invite_existing_users">Undang Pengguna yang telah ada</string>
<string name="send">Kirim</string>
<string name="invite">Undang Teman</string>
<string name="invite_id_description">Jika kamu memiliki teman yang telah menggunakan Habitica, undang melalui ID Pengguna di sini.</string>
<string name="invite_email_description">Jika seorang teman bergabung dengan Habitica melalui emailmu, mereka otomatis akan diundang ke dalam kelompokmu!</string>
<string name="add_invites">Tambahkan Undangan</string>
<string name="user_id">ID Pengguna</string>
<string name="email">Email</string>
<string name="invite_users">Undang sebagai Teman</string>
<string name="share_using">Bagikan dengan</string>
<string name="share_levelup">Aku mencapai level %d di Habitica dengan memperbaiki kebiasaanku di kehidupan nyata!</string>
<string name="share_hatched">Saya menetaskan peliharaan seekor %2$s %1$s di Habitica dengan menyelesaikan tugas kehidupan-nyata saya! </string>
<string name="share_raised">Saya baru mendapatkan tunggangan seekor %s di Habitica dengan menyelesaikan tugas kehidupan-nyata saya!</string>
<string name="open_in_store">Buka di Play Store</string>
<string name="change_class_confirmation">Apa kamu yakin untuk mengubah kelas? Ini akan membutuhkan 3 permata.</string>
<string name="change_class_equipment_warning">Peringatan: Kamu tidak akan dapat membeli perlengkapan untuk profesi %s. </string>
<string name="leaderMessage">Pesan dari %1$s</string>
<string name="leaderName">Ketua: %1$s</string>
<string name="confirm">Pastikan</string>
<string name="market">Pasar</string>
<string name="timeTravelers">Penjelajah Waktu</string>
<string name="seasonalShop">Toko Musiman</string>
<string name="empty_inbox">Kamu tidak punya pesan apapun. Kamu bisa mengirim pesan baru ke pengguna lain dari obrolan publik mereka!</string>
<string name="party_invite">Buka dengan mengundang teman</string>
<string name="login_incentive">Buka dengan cara login ke Habitica secara teratur</string>
<string name="create_account">Buka dengan membuat sebuah akun</string>
<string name="no_gold">Koin Emas tidak cukup</string>
<string name="no_potion">Kamu tidak perlu membeli ramuan kesehatan</string>
<string name="successful_purchase">%1$s telah dibeli</string>
<string name="purchase_confirmation_title">Pastikan belian</string>
<string name="confirm_purchase_text">Membeli %1$s untuk %2$s %3$s</string>
<string name="gem">Permata</string>
<string name="hourglass">Jam Pasir</string>
<string name="hourglasses">Jam-jam Pasir</string>
<string name="gold_singular">Koin Emas</string>
<string name="gold_plural">Koin Emas</string>
<string name="chat_message_copied">Pesan telah tersalin di Papan pencatat</string>
<string name="copy_chat_message">Salin di Papan pencatat</string>
<string name="edit_tag_title">Rubah Label</string>
<string name="edit_tag_btn_edit">Rubah</string>
<string name="edit_tag_btn_done">Selesai</string>
<string name="edit_tag_btn_delete">Hapus</string>
<string name="confirm_delete_tag_title">Kamu yakin?</string>
<string name="confirm_delete_tag_message">Apa kamu yakin ingin menghapus?</string>
<string name="filter_drawer_edit_tags">Rubah Label</string>
<string name="filter_drawer_filter_tags">Saring berdasarkan Label</string>
<!--QR Strings-->
<string name="qr_section_title">Pinta seseorang untuk mengundangmu melalui Kode QR</string>
<string name="qr_save_message">Kode QR tersimpan pada</string>
<string name="qr_dialogue_title">Kode QR-mu</string>
<string name="download">Unduh</string>
<string name="send_new_message">Kirim pesan baru</string>
<string name="choose_recipient_title">Pilih Penerima Pesan</string>
<string name="action_continue">Lanjutkan</string>
<string name="scan_qr_code">Pindai Kode QR</string>
<string name="enter_recipient_uuid">Masukan User ID Penerima</string>
<string name="invited_to_party">Kamu telah diundang untuk bergabung dalam sebuah party!</string>
<string name="stats_widget_label">Status Habitica</string>
<string name="add_task">Tambah Tugas</string>
<string name="add_habit">Tambah Kebiasaan</string>
<string name="add_daily">Tambah Kegiatan Harian</string>
<string name="add_todo">Tambah Untuk Dilakukan</string>
<string name="add_reward">Tambah Hadiah</string>
<string name="all_dailies_completed">Anda telah menyelesaikan semua keseharianmu. Selamat!</string>
<string name="widget_habit_button">Habitica Melakukan Kebiasaan</string>
<string name="widget_dailies">Keseharian Habitica</string>
<string name="widget_todo_list">Daftar To-Do Habitica</string>
<string name="widget_add_task">Habitica Menambahkan Tugas</string>
<string name="google_services_missing">Google play services tidak dapat ditemukan.</string>
<string name="gem.purchase.toolbartitle">Bayar</string>
<string name="gem.purchase.title">Membeli gem dapat mendukung pengembang dan menjaga Habitica tetap berjalan</string>
<string name="gem.purchase.subtitle">Permata membuatmu dapat membeli tambahan yang menyenangkan untuk akunmu, termasuk:</string>
<string name="gem.purchase.listitem1">Kostum keren untuk avatarmu</string>
<string name="gem.purchase.listitem2">Latar belakang yang keren</string>
<string name="gem.purchase.listitem3">Misi yang memberikanmu hadiah telur</string>
<string name="gem.purchase.listitem4">Kemampuan untuk mengganti profesi sebelum level 100</string>
<string name="support_habitica">Dukung Habitica</string>
<string name="skill_transformation_use">gunakan</string>
<string name="hatching_market_info">Tidak mendapatkan item yang diinginkan? Beli di Market!</string>
<string name="feeding_market_info">Butuh makanan yang berbeda? Beli lebih dari pasar!</string>
<string name="open_market">Buka Pasar</string>
<string name="cds_description">Keseharianmu akan reset pada saat kamu membuka Habitica di atas %1$s. Pastikan kamu telah menyelesaikan Keseharianmu sebelum jam tersebut!</string>
<string name="AudioTheme_title">Tema Nada</string>
<string name="AudioTheme_summary">Ganti Tema Nada Habitica</string>
<!--Login Incentives-->
<string name="see_you_tomorrow">Sampai jumpa besok! </string>
<string name="belongs_to_challenge">Milik Tantangan</string>
<string name="has_reminder">Memiliki Pengingat</string>
<string name="has_tag">Memiliki Label</string>
<string name="subscribe.title">Berlangganan mendukung para pengembang dan membantu menjaga Habitica terus berjalan</string>
<string name="subscribe_prompt">Jadilah seorang pelanggan dan kamu akan mendapat keuntungan berikut:</string>
<string name="subscribe.listitem1">Beli permata dengan koin emas</string>
<string name="subscribe.listitem2">Item bulanan eksklusif</string>
<string name="subscribe.listitem3">Simpan lebih banyak riwayat masukan</string>
<string name="subscribe.listitem4">Batas drop harian didobel</string>
<string name="subscriptions">Langganan</string>
<string name="subscription_duration">Berulang setiap %s</string>
<string name="subscribe">Berlangganan</string>
<string name="subscribe.listitem1.description">Alexander sang Saudagar akan menjual permata kepadamu masing-masing seharga 20 koin emas!\n\nPengiriman bulanannya dibatasi di 25 Permata per bulan, tapi bisa meningkat berdasarkan lama berlangganan-mu. \n\nBatasnya meningkat sebanyak 5 Permata setiap tiga bulan berturut-turut kamu berlangganan, hingga batas maksimal 50 Permata per bulan!</string>
<string name="subscribe.listitem2.description">Setiap bulan kamu akan menerima sebuah item kosmetik unik untuk avatarmu!\n\nPlus, setiap tiga bulan berturut-turut kamu berlangganan, sang Penjelajah Waktu Misterius akan memberimu akses kepada item kosmetik bersejarah (atau futuristik!).</string>
<string name="subscribe.listitem3.description">Buat To-Do yang telah diselesaikan dan riwayat tugas tersedia lebih lama.</string>
<string name="subscribe.listitem4.description">Dua kali lipat batas drop akan mengizinkanmu mendapat lebih banyak item untuk tugas yang terselesaikan setiap hari, membantumu melengkapi istalmu lebih cepat!</string>
<string name="subscription_hourglasses">+%d Jam Pasir Mistis</string>
<string name="payment_method">Metode Pembayaran</string>
<string name="subscription">Langganan</string>
<string name="active">Aktif</string>
<string name="cancel_subscription">Batalkan Langganan</string>
<string name="cancel_subscription_google.description">Tidak mau berlangganan lagi? Kamu bisa menemukan opsi untuk berhenti berlangganan di bagin \"Aplikasi Saya\" dari Google Play Store.</string>
<string name="cancel_subscription_notgoogle.description">Tidak mau berlangganan lagi? Karena metode pembayaranmu, kamu hanya bisa berhenti berlangganan dari situs Habitica. Klik tombol di bawah, untuk membuka situs Habitica di browsermu!</string>
<string name="visit_habitica_website">Kunjungi Situs Habitica</string>
<string name="current_bonuses">Bonus Sekarang</string>
<string name="months_subscribed">Bulan Berlangganan</string>
<string name="current_hourclasses">Jam Pasir Mistis Sekarang</string>
<string name="monthly_gem_cap">Batas permata bulanan</string>
<string name="inactive">Tidak aktif</string>
<string name="one_month">1 Bulan</string>
<string name="months">%d Bulan</string>
<string name="month">bulan</string>
<string name="three_months">3 bulan</string>
<string name="six_months">6 bulan</string>
<string name="twelve_months">12 bulan</string>
<string name="subscribe_prompt_thanks">Dengan Berlangganan kamu menerima keuntungan bermanfaat berikut:</string>
<string name="subscription_status">Status Langganan</string>
<string name="byLeader">oleh %s</string>
<string name="challenge_details">Detail Tantangan</string>
<string name="challenge_leave_title">Tinggalkan Tantangan</string>
<string name="challenge_leave_text">Apakah kamu yakin ingin meninggalkan Tantangan \"%s\"?</string>
<string name="challenge_remove_tasks_title">Hapus tugas</string>
<string name="challenge_remove_tasks_text">Apakah kamu mau menghapus tugas ini?</string>
<string name="remove_tasks">Hapus</string>
<string name="keep_tasks">Simpan</string>
<string name="my_challenges">Tantangan Saya</string>
<string name="public_challenges">Publik</string>
<string name="challenges">Tantangan</string>
<string name="daily">Keseharian</string>
<string name="habit">Kebiasaan</string>
<string name="reward">Hadiah</string>
<string name="todo">To-Do</string>
<string name="official">Resmi</string>
<string name="participating">Berpartisipasi</string>
<string name="challenge">Tantangan</string>
<string name="go_to_challenge">Pergi ke Tantangan</string>
<string name="not_part_of_a_challenge">Kamu tidak mengambil bagian dalam Tantangan apapun saat ini!</string>
<string name="join_a_challenge">Ikut sebuah tantangan untuk menambahkan sekumpulan tugas yang telah didesain secara khusus, lalu bersainglah dengan sesama Habitican untuk memenangkan sebuah pencapaian dan bahkan permata!</string>
<string name="check_the_public_challenge_tab">Tekan tab \"Publik\" untuk menemukan Tantangan buatan pengguna yang paling cocok untukmu!</string>
<string name="add_reminder">Tambahkan Pengingat</string>
<string name="warning">Peringatan</string>
<string name="open_settings">Buka Pengaturan</string>
<string name="dont_keep_activities_warning">Sepertinya kamu mengaktifkan opsi PEngembang \\"Jangan menyimpan Aktifitas\\". Saat ini opsi ini menyebabkan isu dengan aplikasi Habitica, jadi kami sarankan untuk menonaktifkannya.</string>
<string name="inbox">Pesan</string>
<string name="FAQ">Pertanyaan yang Sering Ditanyakan</string>
<string name="special">Spesial</string>
<string name="gem_for_gold_description">Karena kamu berlangganan Habitica, kamu bisa membeli sejumlah Permata setiap bulan menggunakan Koin Emas.</string>
<string name="limited_count">%d tersisa</string>
<string name="gem_shop">Permata</string>
<string name="mystery_item">Item Misterius</string>
<string name="myster_item_notes">Setiap bulan, pelanggan akan menerima sebuah item misterius. Ini biasanya dirilis sekitar seminggu sebelum akhir bulan.</string>
<string name="open">Buka</string>
<string name="notification_mystery_item">Kamu membuka kotak ini dan menemukan %s!</string>
<string name="checkInRewardEarned">Kamu mendapatkan %1$s sebagai hadiah untuk kesetiaanmu untuk memperbaiki hidupmu.</string>
<string name="nextPrizeUnlocks" tools:ignore="PluralsCandidate">Hadiahmu selanjutnya akan terbuka setelah %1$d kali Cek In</string>
<string name="pending_approval">menunggu persetujuan</string>
<string name="filters">Filter</string>
<string name="done">Selesai</string>
<string name="group_tasks_edit_description">Tugas grup tidak bisa disunting.</string>
<string name="group_tasks_edit_title">Tidak bisa menyunting tugas ini</string>
<string name="groups">Grup</string>
<string name="all">Semua</string>
<string name="none">Tidak Ada</string>
<string name="owned">Dimiliki</string>
<string name="not_owned">Tidak Dimiliki</string>
<string name="new_game">Permainan\nBaru</string>
<string name="login_btn_fb">Login dengan Facebook</string>
<string name="login_btn_google">Login dengan Google</string>
<string name="action_back">Kembali</string>
<string name="randomize">Sembarang</string>
<string name="avatar_extras">Tambahan</string>
<string name="avatar_skin_color">Warna Kulit</string>
<string name="avatar_hair_color">Warna Rambut</string>
<string name="avatar_hair_bangs">Poni</string>
<string name="avatar_hair_ponytail">Kucir</string>
<string name="avatar_glasses">Kacamata</string>
<string name="avatar_wheelchair">Kursi Roda</string>
<string name="weak">Lemah</string>
<string name="strong">Kuat</string>
<string name="gray">Abu-Abu</string>
<string name="dated">Terjadwal</string>
<string name="completed">Selesai</string>
<string name="setuP_group_other">Lainnya</string>
<string name="clear">Hapus</string>
<string name="empty_title_habits">Kamu tidak punya Kebiasaan apapun</string>
<string name="empty_description_habits">Kebiasaan adalah tugas yang tidak memerlukan jadwal ketat. Kamu bisa menyelesaikannya beberapa kali sehari, atau tidak sama sekali.</string>
<string name="empty_title_dailies">Kamu tidak punya Keseharian apapun</string>
<string name="empty_description_dailies">Keseharian adalah tugas yang berulang setiap waktu tertentu secara teratur. Pilih jadwal yang bekerja untukmu!</string>
<string name="empty_title_todos">Kamu tidak punya To-Do apapun</string>
<string name="empty_description_todos">To-Do adalah tugas yang hanya perlu diselesaikan sekali. Tambahkan ceklis kepada To-Do-mu untuk meningkatkan harganya.</string>
<string name="empty_title_rewards">Kamu tidak punya Hadiah apapun</string>
<string name="reset_walkthrough">Ulang Panduan Justin</string>
<string name="read_community_guidelines">Tolong baca Pedoman Komunitas kami sebelum posting</string>
<string name="maintenance">Perbaikan</string>
<string name="reload_content">Muat Ulang Isi</string>
<string name="dailyDueDefaultView">Atur Keseharian secara otomatis di tab \'harus dikerjakan\'</string>
<string name="dailyDueDefaultViewDescription">Dengan opsi ini dipilih, tugas Keseharianmu akan secara otomatis di tab \'harus dikerjakan\' dan bukan \'semua\'</string>
<string name="repeat_summary">Diulang %1$s setiap %2$s%3$s%4$s</string>
<string name="no_billing_gems">Perangkatmu tidak punya metode pembayaran terdukung apapun. Silahkan gunakan situs Habitica jika kamu mau membeli permata.</string>
<string name="no_billing_subscriptions">Perangkatmu tidak punya metode pembayaran terdukung apapun. Silahkan gunakan situs Habitica jika kamu mau berlangganan.</string>
<string name="save">Simpan</string>
<string name="location">Lokasi</string>
<string name="tasks">Tugas</string>
<string name="challenge_create_error_enough_gems">Kamu tidak punya cukup Permata untuk membuat sebuah Tantangan.</string>
<string name="challenge_create_error_no_tasks">Kamu perlu menambah setidaknya sebuah tugas untuk membuat Tantangan ini.</string>
<string name="challenge_create_error_title">Kamu perlu sebuah judul untuk membuat Tantangan ini.</string>
<string name="description_optional">Deskripsi (tidak wajib)</string>
<string name="new_challenge_title">Judul tantangan baru</string>
<string name="ownership">Kepemilikan</string>
<string name="inn">Penginapan</string>
<string name="system">Sistem</string>
<string name="start_quest">Mulai Misi Baru</string>
<string name="leave_party">Tinggalkan Party</string>
<string name="party_description">Deskripsi Party</string>
<string name="abort_confirmation">Apakah kamu yakin ingin membatalkan misi ini? Ini akan membatalkannya untuk semua orang di Party dan semua progress akan hilang. Gulungan misi akan dikembalikan kepada pemilik misi tersebut.</string>
<string name="leave_quest_confirmation">Apakah kamu yakin ingin meninggalkan misi aktif ini? Semua progres misimu akan hilang.</string>
<string name="number_participants">%1$d Partisipan</string>
<string name="welcome_back">Selamat Datang Kembali</string>
<string name="yesterdaililes_prompt">Apakah kamu melakukan Keseharian berikut ini kemarin?</string>
<string name="start_day">Mulai Hariku</string>
<string name="leave_party_confirmation">Apakah kamu yakin ingin meninggalkan Party ini?</string>
<string name="nextPrizeUnlocksIn" formatted="false">Hadiah selanjutnya setelah %d kali Cek In</string>
<string name="pending">Menunggu</string>
<string name="accepted">Menerima</string>
<string name="declined">Menolak</string>
<string name="participants">Partisipan</string>
<string name="invitations">Undangan</string>
<string name="quest_leader_header" formatted="false">Dimulai oleh %s</string>
<string name="quest_abort_message">Apakah kamu yakin ingin membatalkan misi ini? Ini akan membatalkannya untuk semua orang di Party dan semua progress akan hilang. Gulungan misi akan dikembalikan kepada pemilik misi tersebut.</string>
<string name="reloading_content">Memuat Ulang Isi</string>
<string name="thousand_abbrev">rb</string>
<string name="million_abbrev">jt</string>
<string name="billion_abbrev">mil</string>
<string name="your_balance">Saldomu:</string>
<string name="available_until" formatted="false">Tersedia hingga %s</string>
<string name="gems_left_max" formatted="false">Permata Bulanan: %1$d/%2$d Tersisa</string>
<string name="gems_left_nomax" formatted="false">Permata Bulanan: %d Tersisa</string>
<string name="health">Nyawa</string>
<string name="collect">Kumpulkan</string>
<string name="rage_meter">Tingkat Kemarahan</string>
<string name="boss_quest">Misi Boss</string>
<string name="collection_quest">Misi Mengumpulkan</string>
<string name="quest_reward_count" formatted="false">%1$s x%2$d</string>
<string name="experience_reward" formatted="false">%d poin Pengalaman</string>
<string name="gold_reward" formatted="false">%d Koin Emas</string>
<string name="quest_owner_rewards">Hadiah Pemilik Misi</string>
<string name="str_abbrv">Kek</string>
<string name="per_abbrv">Per</string>
<string name="int_abbrv">Kec</string>
<string name="con_abbrv">Ket</string>
<string name="reset_account">Reset Akun</string>
<string name="delete_account">Hapus Akun</string>
<string name="delete_account_description">Apakah kamu yakin? Ini akan menghapus akunmu untuk selamanya, dan tidak akan bisa dikembalikan! Kamu perlu mendaftarkan akun baru untuk menggunakan Habitica lagi. Permata di bank atau yang telah digunakan tidak akan diuangkan kembali. Jika kamu sepenuhnya yakin, ketik kata sandimu di kotak teks di bawah.</string>
<string name="reset_account_confirmation">reset akun-ku</string>
<string name="delete_account_confirmation">hapus akunku</string>
<string name="danger_zone">Zona Berbahaya</string>
<string name="nevermind">Tidak jadi</string>
<string name="resetting_account">Me-reset Akun</string>
<string name="deleting_account">Menghapus Akun</string>
<string name="insufficientGold">Kamu perlu menyelesaikan lebih banyak tugas sebelum bisa membeli item ini!</string>
<string name="insufficientGems">Kamu perlu lebih banyak Permata untuk membeli item ini!</string>
<string name="purchase_gems">Beli permata</string>
<string name="insufficientHourglasses">Kamu perlu lebih banyak Jam Pasir Mistis untuk membeli item ini!</string>
<string name="get_hourglasses">Dapatkan jam pasir</string>
<string name="subscribe_for_hourglasses">Berlangganan untuk Jam Pasir</string>
<string name="timetravelers_closed_description">Dapatkan satu Jam Pasir Mistis setiap tiga bulan berturut-turut kamu berlangganan, lalu gunakan untuk membuka item-item edisi terbatas, peliharaan, dan tunggangan dari masa lalu... dan masa depan!</string>
<string name="want_to_subscribe">Aku mau Berlangganan</string>
<string name="seasonal_closed_description">Grand Gala diadakan dekat dengan titik balik matahari dan ekuinoks, jadi cek kembali nanti untuk menemukan sekumpulan seru item musiman yang spesial!</string>
<string name="come_back_soon">Datang kembali nanti!</string>
<string name="level">Level</string>
<string name="streak_label">Rentetan 21 Hari</string>
<string name="stats">Status</string>
<string name="fix_character_description">Jika kamu menemukan sebuah gangguan atau melakukan kesalahan yang mengubah karaktermu secara tidak adil, kamu bisa memperbaiki angka-angka tersebut secara manual di sini.</string>
<string name="fix_character_values">Atur Angka Karakter</string>
<string name="saving">Menyimpan</string>
<string name="forgot_password_title">Email sebuah Tautan Mengatur Ulang Kata Sandi</string>
<string name="forgot_password_description">Masukan alamat email yang kamu gunakan untuk mendaftarkan akun Habitica-mu.</string>
<string name="forgot_password_confirmation">Jika kami punya data email-mu, instruksi untuk mengatur kata sandi baru telah dikirim ke email-mu.</string>
<string name="ok">OK</string>
<string name="profile">Profil</string>
<string name="profile_summary">Sunting profil publikmu.</string>
<string name="display_name">Nama Tampilan</string>
<string name="photo_url">Tautan Foto</string>
<string name="login_name">Nama Login</string>
<string name="about">Tentang</string>
<string name="app_settings">Pengaturan Aplikasi</string>
<string name="authentication">Autentikasi</string>
<string name="authentication_summary">Ganti opsi autentikasi-mu.</string>
<string name="change_password">Ganti Kata Sandi</string>
<string name="change_email">Ganti Alamat Email</string>
<string name="change_login_name">Ganti Nama Login</string>
<string name="change">Ganti</string>
<string name="character_level">Level Karakter</string>
<string name="auto_allocate_points">Pembagian Poin Otomatis</string>
<string name="stat_guide">Panduan Status</string>
<string name="character_build">Bentuk Tubuh Karakter</string>
<string name="character_build_description">Setiap level memberimu sebuah poin untuk ditaruh kepada sebuah atribut pilihanmu. Kamu bisa melakukannya secara manual, atau biarkan game ini mengaturnya untukmu menggunakan salah satu opsi Pembagian Otomatis.</string>
<string name="strength">Kekuatan</string>
<string name="strength_description">Meningkatkan bonus dari serangan kritikal dan buat itu lebih sering terjadi sewaktu menyelesaikan tugas. Juga meningkatkan damage yang kamu lakukan kepada boss.</string>
<string name="intelligence">Kecerdasan</string>
<string name="intelligence_description">Meningkatkan EXP yang dihasilkan dari menyelesaikan tugas. Juga meningkatkan batas mana-mu dan seberapa cepat mana bertambah dari waktu ke waktu.</string>
<string name="constitution">Ketahanan</string>
<string name="constitution_description">Mengurangi jumlah damage yang kamu terima dari tugasmu. Tidak mengurangi damage yang diterima dari boss.</string>
<string name="perception">Persepsi</string>
<string name="perception_description">Meningkatkan kecenderungan untuk menemukan item sewaktu menyelesaikan Tugas, batas drop harian, Bonus Rentetan, dan jumlah koin emas yang dihadiahkan dari Tugas.</string>
<string name="buffs">Buff</string>
<string name="allocated">Teralokasi</string>
<string name="distribute_evenly">Bagikan Merata</string>
<string name="distribute_class">Bagikan berdasarkan pekerjaan</string>
<string name="distribute_task">Bagikan berdasarkan aktifitas tugas</string>
<string name="no_points_to_allocate">Tidak ada Poin untuk Dibagikan</string>
<string name="points_to_allocate" formatted="false">%d Poin untuk Dibagikan</string>
<string name="distribute_evenly_help">Bagikan jumlah poin yang sama kepada setiap atribut.</string>
<string name="distribute_class_help">Bagikan lebih banyak poin kepada atribut yang penting untuk Pekerjaanmu.</string>
<string name="distribute_task_help">Bagikan poin berdasarkan kepada kategori Kekuatan, Kecerdasan, Ketahanan, dan Persepsi yang dihubungkan kepada tugas yang kamu selesaikan.</string>
<string name="allocating_points">Membagikan Poin</string>
<string name="class_equipment">Perlengkapan</string>
<string name="equipment_empty">Kamu sudah punya semua perlengkapan! Lebih banyak lagi tersedia sewaktu Grand Gala, dekat titik balik matahari dan ekuinoks.</string>
<string name="classless">Tanpa Pekerjaan</string>
<string name="class_equipment_shop_dialog">Item ini hanya tersedia untuk pekerjaan tetentu. \nKamu bisa menggantu pekerjaanmu dari Pengaturan.</string>
<string name="class_gear_disclaimer">Kamu hanya bisa membeli perlengkapan untuk pekerjaanmu yang sekarang</string>
<string name="available_stats" formatted="false">%d poin</string>
<string name="toogle_emojis">Atur Emoji</string>
<string name="tavern_description">Selamat datang di Penginapan! Tarik kursi dan mari mengobrol, atau beristirahat dari tugas-tugasmu.</string>
<string name="check_into_inn">Masuk ke Penginapan</string>
<string name="community_guidelines">Pedoman Komunitas</string>
<string name="view_community_guidelines">Lihat Pedoman Komunitas</string>
<string name="guidelines_description">Habitica coba membuat sebuah lingkungan yang ramah untuk pengguna segala usia dan latar belakang, khususnya di tempat umum seperti Kedai Minuman. Jika kamu ada pertanyaan, silahkan periksa pedoman kami.</string>
<string name="helpful_links">Tautan Berguna</string>
<string name="view_faq">Lihat FAQ</string>
<string name="report_bug">Laporkan Gangguan</string>
<string name="player_tiers">Tingkatan Pemain</string>
<string name="staff_moderators">Staf dan Moderator</string>
<string name="navigation_drawer_open">Buka laci navigasi</string>
<string name="navigation_drawer_close">Tutup laci navigasi</string>
<string name="world_boss">Bos Dunia</string>
<string name="world_boss_art">Seni Bos</string>
<string name="boss_art">Seni Bos</string>
<string name="world_boss_description">Deskripsi Bos Dunia</string>
<string name="rage_strike_count" formatted="false">Tingkat Kemarahan 1%d/1%d</string>
<string name="pending_strike_description">Serangan ini belum terjadi!\nWorld Boss akan mengamuk dan menyerang salah satu dari penjaga toko bersahabat kita sewaktu tingkat kemarahannya telah penuh. Kerjakan sebanyak mungkin Keseharian-mu untuk mencoba mencegah serangan itu!</string>
<string name="pending_strike_title">Serangan Tertunda</string>
<string name="strike_description_title">Apakah itu Tingkatan Kemarahan?</string>
<string name="strike_description_subtitle">Ada 3 potensi Serangan peningkat Kemarahan</string>
<string name="strike_description_description">Pengukur ini terisi sewaktu Habitican tidak menyelesaikan Keseharian mereka. Sewaktu terisi penuh, sang DysHeartener akan mengerahkan Shattering Heartbreak kepada salah satu dari penjaga toko Habitica, jadi pastikan kamu melakukan tugas-tugasmu!</string>
<string name="pending_strike_subtitle">Serangan ini belum terjadi!</string>
<string name="strike_active_title" formatted="false">Sang %s telah Diserang!</string>
<string name="strike_active_subtitle" formatted="false">%s sekarang Patah Hati!</string>
<string name="strike_active_description" formatted="false">%s kita yang tercinta hancur sewaktu sang %s meremukkan %s. Cepat, kalahkan tugas-tugasmu untuk mengalahkan sang monster dan bantu membangun kembali!!</string>
<string name="questShop">Toko Misi</string>
<string name="market_owner_long">Alex sang Pedagang</string>
<string name="tavern_owner_long">Daniel sang penjaga penginapan</string>
<string name="stable_owner_long">Matt sang penguasa hewan buas</string>
<string name="hide_boss_art">Sembunyikan Seni Bos</string>
<string name="active_world_boss">Bos Dunia aktif</string>
<string name="no_party_description">Selesaikan misi bersama teman-temanmu atau sendirian. Bertarung melawan monster, buat Tantangan, dan bantu dirimu untuk tetap bertanggung jawab melalui Party.</string>
<string name="no_party_title">Mainkan Habitica dalam Party</string>
<string name="join_party_title">Ingin bergabung ke Party?</string>
<string name="create_party_website">Buka website untuk membuat Party</string>
<string name="id_copied">ID tersalin ke clipboard</string>
<string name="insufficientSubscriberGems">Kamu telah membeli semua Permata yang tersedia bulan ini. Lebih banyak akan ditambahkan dalam tiga hari pertama pada setiap bulan. Terima kasih sudah berlangganan!</string>
<string name="insufficientSubscriberGemsTitle">Batas Permata Bulanan Telah Tercapai</string>
</resources>

View file

@ -14,6 +14,7 @@
<attr name="statsColor" format="color" />
<attr name="statsTitle" format="string" />
<attr name="title" format="string" />
<attr name="description" format="string" />
<attr name="iconDrawable" format="integer" />
<attr name="identifier" format="string" />
<attr name="hasLightBackground" format="boolean" />
@ -61,7 +62,7 @@
<attr name="barIconDrawable" format="integer" />
<attr name="barHeight" format="dimension" />
<attr name="lightBackground" format="boolean" />
<attr name="description" format="string" />
<attr name="description" />
<attr name="labelSpacing" format="dimension" />
</declare-styleable>
<declare-styleable name="HabiticaProgressBar">
@ -129,4 +130,17 @@
<declare-styleable name="EquipmentOverviewItem">
<attr name="title" />
</declare-styleable>
<declare-styleable name="SupportCollapsibleSection">
<attr name="title" />
<attr name="titleColor" format="color" />
<attr name="subtitle" format="string" />
<attr name="description" />
<attr name="iconDrawable" />
</declare-styleable>
<declare-styleable name="StepperValueFormView">
<attr name="defaultValue" />
<attr name="iconDrawable" />
<attr name="maxValue" format="integer" />
<attr name="minValue" format="integer" />
</declare-styleable>
</resources>

View file

@ -125,6 +125,7 @@
<color name="black_20_alpha">#33000000</color>
<color name="black_50_alpha">#89000000</color>
<color name="gray_20_alpha">#331a181d</color>
<color name="blue_500_24">#3CA9DCF6</color>
<color name="light_gray_bg">#F6F4F8</color>
<color name="skin_ddc994">#ddc994</color>

View file

@ -50,7 +50,7 @@
<dimen name="grid_item_margin">6dp</dimen>
<dimen name="avatar_small_width">90dp</dimen>
<dimen name="avatar_small_height">90dp</dimen>
<dimen name="customization_width">100dp</dimen>
<dimen name="customization_width">76dp</dimen>
<dimen name="gear_image_size">68dp</dimen>
<dimen name="row_padding">12dp</dimen>
<dimen name="row_title_size">16sp</dimen>

View file

@ -25,7 +25,7 @@
<string name="pref_cds_header">Custom Day Start</string>
<string name="pref_push_notifications_checkbox">User Push Notifications</string>
<string name="pref_push_notifications_checkbox">Use Push Notifications</string>
<string name="push_notifications">Push Notifications</string>
<string name="push_notifications_sum">Set your push notifications settings</string>
<string name="preference_push_you_won_challenge">You won a Challenge!</string>
@ -323,9 +323,9 @@
<string name="add_invites">Add Invites</string>
<string name="email">Email</string>
<string name="share_using">Share using</string>o
<string name="share_levelup">I got to level %d in Habitica by improving my real-life habits!</string>
<string name="share_hatched">I just hatched a %1$s %2$s pet in Habitica by completing my real-life tasks!</string>
<string name="share_raised">I just gained a %1$s mount in Habitica by completing my real-life tasks!</string>
<string name="share_levelup">I got to level %d in #Habitica by improving my real-life habits!</string>
<string name="share_hatched">I just hatched a %1$s %2$s pet in #Habitica by completing my real-life tasks!</string>
<string name="share_raised">I just gained a %1$s mount in #Habitica by completing my real-life tasks!</string>
<string name="open_in_store">Open in play store</string>
<string name="change_class_confirmation">Are you sure you want to change your class? This will cost 3 gems.</string>
<string name="change_class_equipment_warning">Warning: You will no longer be able to buy equipment from the %s class.</string>
@ -336,9 +336,15 @@
<string name="empty_inbox">You don\'t have any messages. You can send a user a new message from their public chat messages!</string>
<string name="party_invite">Unlock by inviting friends</string>
<string name="login_incentive">Unlock by logging into Habitica regularly</string>
<string name="login_incentive_count">Unlock by checking into Habitica %d times.</string>
<string name="create_account">Unlock by creating an account</string>
<string name="party_invite_short">Invite Friends</string>
<string name="login_incentive_short">log into Habitica regularly</string>
<string name="login_incentive_short_count">%d Checkins</string>
<string name="create_account_short">create an account</string>
<string name="successful_purchase">Purchased %1$s</string>
<string name="gold_plural">gold</string>
<string name="gold_capitalilzed">Gold</string>
<string name="chat_message_copied">Message copied to Clipboard</string>
<string name="edit_tag_btn_edit">Edit</string>
<string name="confirm_delete_tag_title">Are you sure?</string>
@ -367,7 +373,7 @@
<string name="gem_purchase_listitem3">Quests that reward you with pet eggs</string>
<string name="gem_purchase_listitem4">The ability to change your class before level 100</string>
<string name="support_habitica">Support Habitica</string>
<string name="skill_transformation_use">use</string>
<string name="skill_transformation_use">Use</string>
<string name="hatching_market_info">Not getting the right drops? Check out the Market!</string>
<string name="feeding_market_info">Need different food? Buy more from the market!</string>
<string name="open_market">Open Market</string>
@ -461,6 +467,7 @@
<string name="not_owned">Not owned</string>
<string name="login_btn_fb">Login with Facebook</string>
<string name="login_btn_google">Login with Google</string>
<string name="login_btn_apple">Sign in with Apple</string>
<string name="register_btn_fb">Sign up with Facebook</string>
<string name="register_btn_google">Sign up with Google</string>
<string name="action_back">Back</string>
@ -487,6 +494,13 @@
<string name="empty_title_todos">You don\'t have any To-Dos</string>
<string name="empty_description_todos">To-Dos are tasks that only need to be completed once. Add checklists to your To-Dos to increase their value.</string>
<string name="empty_title_rewards">You don\'t have any Rewards</string>
<string name="empty_title_habits_filtered">No Habits</string>
<string name="empty_description_habits_filtered">There aren\'t any Habits visible with your current filters.</string>
<string name="empty_title_dailies_filtered">No Dailies</string>
<string name="empty_description_dailies_filtered">There aren\'t any Dailies visible with your current filters.</string>
<string name="empty_title_todos_filtered">No To-Dos</string>
<string name="empty_description_todos_filtered">There aren\'t any To-Dos visible with your current filters.</string>
<string name="empty_title_rewards_filtered">No Rewards</string>
<string name="reset_walkthrough">Reset Tutorials</string>
<string name="read_community_guidelines">Review our <u>Community Guidelines</u> before posting</string>
<string name="maintenance">Maintenance</string>
@ -550,8 +564,8 @@
<string name="reset_account">Reset Account</string>
<string name="reset_account_description">WARNING! This resets many parts of your account. This is highly discouraged, but some people find it useful in the beginning after playing with the site for a short time.\n\nYou will lose all your levels, gold, and experience points. All your tasks (except those from challenges) will be deleted permanently and you will lose all of their historical data. You will lose all your equipment but you will be able to buy it all back, including all limited edition equipment or subscriber Mystery items that you already own (you will need to be in the correct class to re-buy class-specific gear). You will keep your current class and your pets and mounts. You might prefer to use an Orb of Rebirth instead, which is a much safer option and which will preserve your tasks and equipment.</string>
<string name="delete_account">Delete Account</string>
<string name="delete_account_description">Are you sure? This will delete your account forever, and it can never be restored! You will need to register a new account to use Habitica again. Banked or spent Gems will not be refunded. If you\'re absolutely certain, type your password into the text box below.</string>
<string name="delete_oauth_account_description">Are you sure? This will delete your account forever, and it can never be restored! You will need to register a new account to use Habitica again. Banked or spent Gems will not be refunded. If you\'re absolutely certain, type DELETE into the text box below.</string>
<string name="delete_account_description">This will delete your account forever, and it can never be restored! Banked or spent Gems will not be refunded. If youre absolutely certain, type your password into the text box below.</string>
<string name="delete_oauth_account_description">This will delete your account forever, and it can never be restored! Banked or spent Gems will not be refunded. If youre absolutely certain, type DELETE into the text box below.</string>
<string name="reset_account_confirmation">Reset my Account</string>
<string name="delete_account_confirmation">Delete my Account</string>
<string name="danger_zone">Danger Zone</string>
@ -928,4 +942,68 @@
<string name="learn_more">Learn more</string>
<string name="purchase_from_timetravel_shop">You can purchase this customization from the Time Travelers shop</string>
<string name="go_shopping">Go shopping</string>
<string name="emails">Email Notifications</string>
<string name="pref_emails_checkbox">Use Email Notifications</string>
<string name="preference_email_subscription_reminder">Subscription Reminders</string>
<string name="preference_email_kicked_group">Kicked from group</string>
<string name="preference_email_onboarding">Guidance with setting up your Habitica Account</string>
<string name="skill_unlocks_at">Skill unlocks at level %d</string>
<string name="locked">Locked</string>
<string name="unlock_previous">Unlock by finishing Quest %d</string>
<string name="unlock_level">Unlock by reaching level %d</string>
<string name="unlock_previous_short">Finish Quest %d</string>
<string name="unlock_level_short">Level %d</string>
<string name="not_participating">You are not participating</string>
<string name="quest_completed">Quest completed!</string>
<string name="using_habitica">Using Habitica</string>
<string name="using_habitica_description">Confused? Well go over the basics to get you up to speed.</string>
<string name="suggestions_feedback_description">Have input on how features could work better or an idea for something new? Tell us!</string>
<string name="contact_us">Contact Us</string>
<string name="get_help">Get Help</string>
<string name="suggestions_feedback"><![CDATA[Suggestions & Feedback]]></string>
<string name="bugs_fixes"><![CDATA[Bugs & Fixes]]></string>
<string name="bugs_fixes_description">Did something go wrong? Check for answers here or reach out to us for help.</string>
<string name="lets_go">Let\'s Go</string>
<string name="support_bug_title">Were constantly trying to make our apps better based on player feedback but sometimes a few bugs pop up…</string>
<string name="common_fixes">Common Fixes</string>
<string name="send_bug_prompt">Send a bug report to us and well get back to you!</string>
<string name="overview">Overview</string>
<string name="how_best_habitica">Not sure how to best use Habitica?</string>
<string name="stats_currency"><![CDATA[Stats & Currency]]></string>
<string name="health_points">Health Points</string>
<string name="health_description">This represents your avatars life. Missing a Daily or doing a negative Habit **reduces your HP**.\n\n**Regain HP** by completing tasks, using a Health Potion, or a healing ability.\n\nIf your **HP reaches 0** your avatar will pass out (lose a level, all Gold, and one piece of equipment). Lost equipment can be re-purchased.</string>
<string name="experience_points">Experience Points</string>
<string name="experience_description">Experience points represent your progress and allows you to level up. Youll mainly **gain EXP** from completing tasks or quests.\n\nHigher difficulty or red colored tasks will give you **more EXP**. The **Intelligence** stat also raises your EXP gain.</string>
<string name="mana_points">Mana Points</string>
<string name="gold_description">Gold is the **main form of currency** within Habitica and allows you to buy certain gear, quests, items, or even custom rewards you make for yourself.\n\n**Earn Gold** through completing tasks or quests. **Perception** raises the amount of Gold you earn. Rogues can also use an ability to get more Gold.\n\nIf you subscribe to Habitica, you can even use Gold to purchase Gems.</string>
<string name="mana_description">Mana points are unlocked with the class system at level 10 and allow you to **use Skills**.\n\nSome **MP is restored** naturally every day, but you can regain more by completing tasks or using a Mage ability.</string>
<string name="stat_allocation">Stat Allocation</string>
<string name="stat_description">All Habitica characters have four stats that affect the gameplay aspects of Habitica.\n\n**Strength (STR)** affects critical hits and raises damage done to a Quest Boss. Mainly for Warriors and Rogues.\n\n**Constitution (CON)** raises your HP and makes you take less damage. Mainly for Healers and Warriors.\n\n**Intelligence (INT)** raises the amount of EXP you earn and gives you more Mana. Mainly for Mages and Healers.\n\n**Perception (PER)** increases the gold you earn and the rate of finding items. Mainly for Rogues and Mages.\nnAfter level 10, you earn 1 Stat Point every level you gain that you can put into any stat youd like. You can also equip gear that has different combinations of stat boosts.</string>
<string name="standard"> Standard </string>
<string name="premium_currency">Premium Currency</string>
<string name="currency">Currency</string>
<string name="gems_description">Gems are a currency purchased with real money that allow you to buy extra content within Habitica and are one of the main source of financial support for the Habitica team alongside subscriptions.\n\nAll content purchased through Gems is purely cosmetic or can be obtained for free with time.\n\nYou can also receive Gems through gifts, Challenge prizes, contributing work to Habitica, or subscribing.</string>
<string name="common_questions">Common Questions</string>
<string name="game_mechanics">Game Mechanics</string>
<string name="subscriber_currency">Subscriber Currency</string>
<string name="mystic_hourglasses">Mystic Hourglasses</string>
<string name="hourglasses_description">Mystic Hourglasses are an extremely rare form of currency you can only receive for subscribing to Habitica. They are used in the Time Travelers shop to buy past gear sets, pets, mounts, animated backgrounds, or even special quests.\n\nYou can receive up to four Mystic Hourglasses a year. The time they are rewarded is based on your subscription renewal schedule. They are sent out on the first day of a new month after your last subscription payment that qualified you for an hourglass. See the [Subscription] page for more details.</string>
<string name="clear_cache">Clear your Cache</string>
<string name="clear_cache_description"><![CDATA[To clear your cache, open your phones Settings app. Go to Storage > Apps > Habitica, then tap Clear Cache.]]></string>
<string name="manual_sync_restart">Manual Sync or Restart</string>
<string name="manual_sync_restart_description">Sometimes the app wont automatically update content. Try pulling to refresh or force closing the app and reopening it.</string>
<string name="update_app">Update the App</string>
<string name="update_app_description">Were constantly pushing out new fixes, so be sure to check the Play Store to see if there are any updates available.</string>
<string name="support">Support</string>
<string name="wacky"> Wacky </string>
<string name="habitica_questions">Habitica Questions</string>
<string name="could_not_find_user">Could not find user</string>
<string name="animal_ears">Animal Ears</string>
<string name="animal_tail">Animal Tail</string>
<string name="avatar_headband">Headband</string>
<string name="avatar_accent">Accent</string>
<string name="buy_all">Buy All</string>
<string name="read_more">Read More</string>
<string name="purchase_amount_error">You are unable to buy that amount.</string>
</resources>

View file

@ -272,11 +272,11 @@
</style>
<style name="AlertDialogTheme" parent="Theme.AppCompat.Light.Dialog.Alert">
<item name="colorAccent">@color/brand_100</item>
<item name="colorAccent">@color/brand_400</item>
</style>
<style name="HabiticaAlertDialogTheme" parent="Theme.AppCompat.Light.Dialog.Alert">
<item name="colorAccent">@color/brand_100</item>
<item name="colorAccent">@color/brand_400</item>
<item name="android:windowFrame">@null</item>
<item name="android:windowIsFloating">true</item>
<item name="android:windowContentOverlay">@null</item>
@ -293,6 +293,13 @@
<item name="android:paddingTop">@dimen/section_top_padding</item>
</style>
<style name="SectionHeaderCaps">
<item name="android:textSize">10sp</item>
<item name="android:textColor">@color/gray_200</item>
<item name="android:textAllCaps">true</item>
<item name="android:layout_marginStart">@dimen/spacing_large</item>
</style>
<style name="BottomMenu">
<item name="android:divider">?android:listDivider</item>
<item name="android:showDividers">middle</item>
@ -310,9 +317,7 @@
<style name="EmptyView">
<item name="android:padding">@dimen/section_top_padding</item>
<item name="android:layout_gravity">center</item>
<item name="android:gravity">center</item>
<item name="android:background">@color/white</item>
<item name="android:layout_marginLeft">20dp</item>
<item name="android:layout_marginRight">20dp</item>
</style>

View file

@ -89,6 +89,14 @@
<item>Rosstavo\'s Theme</item>
<item>Dewin\'s Theme</item>
<item>Airu\'s Theme</item>
<item>Beatscribe\'s NES Theme</item>
<item>Arashi\'s Theme</item>
<item>Triumph Theme</item>
<item>Lunasol Theme</item>
<item>SpacePenguin\'s Theme</item>
<item>MAFL Theme</item>
<item>Pizilden\'s Theme</item>
<item>Farvoid Theme</item>
</string-array>
<string-array name="AudioValues">
@ -100,6 +108,14 @@
<item>rosstavoTheme</item>
<item>dewinTheme</item>
<item>airuTheme</item>
<item>beatscribeNesTheme</item>
<item>arashiTheme</item>
<item>triumphTheme</item>
<item>lunasolTheme</item>
<item>spacePenguinTheme</item>
<item>maflTheme</item>
<item>pizildenTheme</item>
<item>farvoidTheme</item>
</string-array>

View file

@ -273,9 +273,88 @@
android:title="@string/preference_push_unjoined_guild_mention"
android:layout="@layout/preference_child_summary"/>
</PreferenceCategory>
</PreferenceScreen>
</PreferenceCategory>
<PreferenceCategory
android:title="@string/emails"
android:layout="@layout/preference_category">
<CheckBoxPreference
android:key="useEmails"
android:defaultValue="true"
android:title="@string/pref_emails_checkbox"
android:layout="@layout/preference_child_summary"/>
<PreferenceScreen
android:key="emailNotifications"
android:title="@string/emails"
android:layout="@layout/preference_child_summary">
<PreferenceCategory android:title="@string/emails">
<CheckBoxPreference
android:key="preference_email_you_won_challenge"
android:defaultValue="true"
android:title="@string/preference_push_you_won_challenge"
android:layout="@layout/preference_child_summary"/>
<CheckBoxPreference
android:key="preference_email_onboarding"
android:defaultValue="true"
android:title="@string/preference_email_onboarding"
android:layout="@layout/preference_child_summary"/>
<CheckBoxPreference
android:key="preference_email_received_a_private_message"
android:defaultValue="true"
android:title="@string/preference_push_received_a_private_message"
android:layout="@layout/preference_child_summary"/>
<CheckBoxPreference
android:key="preference_email_gifted_gems"
android:defaultValue="true"
android:title="@string/preference_push_gifted_gems"
android:layout="@layout/preference_child_summary"/>
<CheckBoxPreference
android:key="preference_email_gifted_subscription"
android:defaultValue="true"
android:title="@string/preference_push_gifted_subscription"
android:layout="@layout/preference_child_summary"/>
<CheckBoxPreference
android:key="preference_email_invited_to_party"
android:defaultValue="true"
android:title="@string/preference_push_invited_to_party"
android:layout="@layout/preference_child_summary"/>
<CheckBoxPreference
android:key="preference_email_invited_to_guild"
android:defaultValue="true"
android:title="@string/preference_push_invited_to_guild"
android:layout="@layout/preference_child_summary"/>
<CheckBoxPreference
android:key="preference_email_kicked_group"
android:defaultValue="true"
android:title="@string/preference_email_kicked_group"
android:layout="@layout/preference_child_summary"/>
<CheckBoxPreference
android:key="preference_email_your_quest_has_begun"
android:defaultValue="true"
android:title="@string/preference_push_your_quest_has_begun"
android:layout="@layout/preference_child_summary"/>
<CheckBoxPreference
android:key="preference_email_invited_to_quest"
android:defaultValue="true"
android:title="@string/preference_push_invited_to_quest"
android:layout="@layout/preference_child_summary"/>
<CheckBoxPreference
android:key="preference_email_important_announcements"
android:defaultValue="true"
android:title="@string/preference_push_important_announcements"
android:layout="@layout/preference_child_summary"/>
<CheckBoxPreference
android:key="preference_email_subscription_reminder"
android:defaultValue="true"
android:title="@string/preference_email_subscription_reminder"
android:layout="@layout/preference_child_summary"/>
</PreferenceCategory>
</PreferenceScreen>
</PreferenceCategory>
<PreferenceCategory

View file

@ -72,5 +72,9 @@
<key>insufficientGemPurchaseAdjust</key>
<value>false</value>
</entry>
<entry>
<key>raiseShops</key>
<value>false</value>
</entry>
</defaultsMap>
<!-- END xml_defaults -->

View file

@ -62,10 +62,10 @@ interface ApiService {
fun equipItem(@Path("type") type: String, @Path("key") itemKey: String): Flowable<HabitResponse<Items>>
@POST("user/buy/{key}")
fun buyItem(@Path("key") itemKey: String): Flowable<HabitResponse<BuyResponse>>
fun buyItem(@Path("key") itemKey: String, @Body quantity: Map<String, Int>): Flowable<HabitResponse<BuyResponse>>
@POST("user/purchase/{type}/{key}")
fun purchaseItem(@Path("type") type: String, @Path("key") itemKey: String): Flowable<HabitResponse<Void>>
fun purchaseItem(@Path("type") type: String, @Path("key") itemKey: String, @Body quantity: Map<String, Int>): Flowable<HabitResponse<Void>>
@POST("user/purchase-hourglass/{type}/{key}")
fun purchaseHourglassItem(@Path("type") type: String, @Path("key") itemKey: String): Flowable<HabitResponse<Void>>
@ -138,6 +138,8 @@ interface ApiService {
@POST("user/auth/social")
fun connectSocial(@Body auth: UserAuthSocial): Flowable<HabitResponse<UserAuthResponse>>
@POST("user/auth/apple")
fun loginApple(@Body auth: Map<String, Any>): Flowable<HabitResponse<UserAuthResponse>>
@POST("user/sleep")
fun sleep(): Flowable<HabitResponse<Boolean>>
@ -248,6 +250,9 @@ interface ApiService {
@POST("/iap/android/subscribe")
fun validateSubscription(@Body request: SubscriptionValidationRequest): Flowable<HabitResponse<Void>>
@GET("/iap/android/subscribe/cancel")
fun cancelSubscription(): Flowable<HabitResponse<Void>>
@POST("/iap/android/norenew-subscribe")
fun validateNoRenewSubscription(@Body request: PurchaseValidationRequest): Flowable<HabitResponse<Void>>

View file

@ -42,16 +42,11 @@ import com.habitrpg.android.habitica.ui.adapter.tasks.RewardsRecyclerViewAdapter
import com.habitrpg.android.habitica.ui.adapter.tasks.TodosRecyclerViewAdapter;
import com.habitrpg.android.habitica.ui.fragments.AboutFragment;
import com.habitrpg.android.habitica.ui.fragments.AchievementsFragment;
import com.habitrpg.android.habitica.ui.fragments.purchases.GemsPurchaseFragment;
import com.habitrpg.android.habitica.ui.fragments.NavigationDrawerFragment;
import com.habitrpg.android.habitica.ui.fragments.NewsFragment;
import com.habitrpg.android.habitica.ui.fragments.StatsFragment;
import com.habitrpg.android.habitica.ui.fragments.purchases.GiftBalanceGemsFragment;
import com.habitrpg.android.habitica.ui.fragments.purchases.GiftPurchaseGemsFragment;
import com.habitrpg.android.habitica.ui.fragments.purchases.SubscriptionFragment;
import com.habitrpg.android.habitica.ui.fragments.faq.FAQDetailFragment;
import com.habitrpg.android.habitica.ui.fragments.faq.FAQOverviewFragment;
import com.habitrpg.android.habitica.ui.fragments.inventory.customization.AvatarCustomizationFragment;
import com.habitrpg.android.habitica.ui.fragments.inventory.customization.AvatarEquipmentFragment;
import com.habitrpg.android.habitica.ui.fragments.inventory.customization.AvatarOverviewFragment;
import com.habitrpg.android.habitica.ui.fragments.inventory.equipment.EquipmentDetailFragment;
import com.habitrpg.android.habitica.ui.fragments.inventory.equipment.EquipmentOverviewFragment;
@ -65,9 +60,14 @@ import com.habitrpg.android.habitica.ui.fragments.inventory.stable.StableFragmen
import com.habitrpg.android.habitica.ui.fragments.inventory.stable.StableRecyclerFragment;
import com.habitrpg.android.habitica.ui.fragments.preferences.APIPreferenceFragment;
import com.habitrpg.android.habitica.ui.fragments.preferences.AuthenticationPreferenceFragment;
import com.habitrpg.android.habitica.ui.fragments.preferences.EmailNotificationsPreferencesFragment;
import com.habitrpg.android.habitica.ui.fragments.preferences.PreferencesFragment;
import com.habitrpg.android.habitica.ui.fragments.preferences.ProfilePreferencesFragment;
import com.habitrpg.android.habitica.ui.fragments.preferences.PushNotificationsPreferencesFragment;
import com.habitrpg.android.habitica.ui.fragments.purchases.GemsPurchaseFragment;
import com.habitrpg.android.habitica.ui.fragments.purchases.GiftBalanceGemsFragment;
import com.habitrpg.android.habitica.ui.fragments.purchases.GiftPurchaseGemsFragment;
import com.habitrpg.android.habitica.ui.fragments.purchases.SubscriptionFragment;
import com.habitrpg.android.habitica.ui.fragments.setup.AvatarSetupFragment;
import com.habitrpg.android.habitica.ui.fragments.setup.IntroFragment;
import com.habitrpg.android.habitica.ui.fragments.setup.TaskSetupFragment;
@ -76,12 +76,12 @@ import com.habitrpg.android.habitica.ui.fragments.skills.SkillTasksRecyclerViewF
import com.habitrpg.android.habitica.ui.fragments.skills.SkillsFragment;
import com.habitrpg.android.habitica.ui.fragments.social.ChatFragment;
import com.habitrpg.android.habitica.ui.fragments.social.ChatListFragment;
import com.habitrpg.android.habitica.ui.fragments.social.NoPartyFragmentFragment;
import com.habitrpg.android.habitica.ui.fragments.social.GuildDetailFragment;
import com.habitrpg.android.habitica.ui.fragments.social.GuildFragment;
import com.habitrpg.android.habitica.ui.fragments.social.GuildsOverviewFragment;
import com.habitrpg.android.habitica.ui.fragments.social.InboxOverviewFragment;
import com.habitrpg.android.habitica.ui.fragments.social.InboxMessageListFragment;
import com.habitrpg.android.habitica.ui.fragments.social.InboxOverviewFragment;
import com.habitrpg.android.habitica.ui.fragments.social.NoPartyFragmentFragment;
import com.habitrpg.android.habitica.ui.fragments.social.PublicGuildsFragment;
import com.habitrpg.android.habitica.ui.fragments.social.QuestDetailFragment;
import com.habitrpg.android.habitica.ui.fragments.social.TavernDetailFragment;
@ -92,6 +92,10 @@ import com.habitrpg.android.habitica.ui.fragments.social.challenges.ChallengesOv
import com.habitrpg.android.habitica.ui.fragments.social.party.PartyDetailFragment;
import com.habitrpg.android.habitica.ui.fragments.social.party.PartyFragment;
import com.habitrpg.android.habitica.ui.fragments.social.party.PartyInviteFragment;
import com.habitrpg.android.habitica.ui.fragments.support.BugFixFragment;
import com.habitrpg.android.habitica.ui.fragments.support.FAQDetailFragment;
import com.habitrpg.android.habitica.ui.fragments.support.FAQOverviewFragment;
import com.habitrpg.android.habitica.ui.fragments.support.SupportMainFragment;
import com.habitrpg.android.habitica.ui.fragments.tasks.TaskRecyclerViewFragment;
import com.habitrpg.android.habitica.ui.fragments.tasks.TasksFragment;
import com.habitrpg.android.habitica.ui.viewmodels.GroupViewModel;
@ -145,8 +149,6 @@ public interface UserComponent {
void inject(TasksFragment tasksFragment);
void inject(FAQDetailFragment faqDetailFragment);
void inject(FAQOverviewFragment faqOverviewFragment);
void inject(AvatarCustomizationFragment avatarCustomizationFragment);
@ -328,4 +330,14 @@ public interface UserComponent {
void inject(@NotNull GiftPurchaseGemsFragment giftPurchaseGemsFragment);
void inject(@NotNull GiftBalanceGemsFragment giftBalanceGemsFragment);
void inject(@NotNull EmailNotificationsPreferencesFragment emailNotificationsPreferencesFragment);
void inject(@NotNull SupportMainFragment supportMainFragment);
void inject(@NotNull BugFixFragment bugFixFragment);
void inject(@NotNull AvatarEquipmentFragment avatarEquipmentFragment);
void inject(@NotNull FAQDetailFragment faqDetailFragment);
}

View file

@ -52,9 +52,9 @@ interface ApiClient {
fun equipItem(type: String, itemKey: String): Flowable<Items>
fun buyItem(itemKey: String): Flowable<BuyResponse>
fun buyItem(itemKey: String, purchaseQuantity: Int): Flowable<BuyResponse>
fun purchaseItem(type: String, itemKey: String): Flowable<Any>
fun purchaseItem(type: String, itemKey: String, purchaseQuantity: Int): Flowable<Any>
fun purchaseHourglassItem(type: String, itemKey: String): Flowable<Any>
@ -63,6 +63,7 @@ interface ApiClient {
fun purchaseQuest(key: String): Flowable<Any>
fun validateSubscription(request: SubscriptionValidationRequest): Flowable<Any>
fun validateNoRenewSubscription(request: PurchaseValidationRequest): Flowable<Any>
fun cancelSubscription(): Flowable<Any>
fun sellItem(itemType: String, itemKey: String): Flowable<User>
@ -103,6 +104,8 @@ interface ApiClient {
fun connectUser(username: String, password: String): Flowable<UserAuthResponse>
fun connectSocial(network: String, userId: String, accessToken: String): Flowable<UserAuthResponse>
fun loginApple(authToken: String): Flowable<UserAuthResponse>
fun sleep(): Flowable<Boolean>
fun revive(): Flowable<User>

View file

@ -31,6 +31,7 @@ interface InventoryRepository : BaseRepository {
fun retrieveInAppRewards(): Flowable<List<ShopItem>>
fun getOwnedEquipment(type: String): Flowable<RealmResults<Equipment>>
fun getEquipmentType(type: String, set: String): Flowable<RealmResults<Equipment>>
fun getOwnedItems(itemType: String): Flowable<RealmResults<OwnedItem>>
fun getOwnedItems(): Flowable<Map<String, OwnedItem>>
@ -59,7 +60,7 @@ interface InventoryRepository : BaseRepository {
fun inviteToQuest(quest: QuestContent): Flowable<Quest>
fun buyItem(user: User?, id: String, value: Double): Flowable<BuyResponse>
fun buyItem(user: User?, id: String, value: Double, purchaseQuantity: Int): Flowable<BuyResponse>
fun retrieveShopInventory(identifier: String): Flowable<Shop>
fun retrieveMarketGear(): Flowable<Shop>
@ -70,7 +71,7 @@ interface InventoryRepository : BaseRepository {
fun purchaseQuest(key: String): Flowable<Any>
fun purchaseItem(purchaseType: String, key: String): Flowable<Any>
fun purchaseItem(purchaseType: String, key: String, purchaseQuantity: Int): Flowable<Any>
fun togglePinnedItem(item: ShopItem): Flowable<List<ShopItem>>
fun getItems(itemClass: Class<out Item>, keys: Array<String>, user: User?): Flowable<out RealmResults<out Item>>

View file

@ -174,6 +174,10 @@ class ApiClientImpl//private OnHabitsAPIResult mResultListener;
return this.apiService.connectSocial(auth).compose(configureApiCallObserver())
}
override fun loginApple(authToken: String): Flowable<UserAuthResponse> {
return apiService.loginApple(mapOf(Pair("code", authToken))).compose(configureApiCallObserver())
}
override fun accept(throwable: Throwable) {
val throwableClass = throwable.javaClass
if (SocketTimeoutException::class.java.isAssignableFrom(throwableClass)) {
@ -317,12 +321,12 @@ class ApiClientImpl//private OnHabitsAPIResult mResultListener;
return apiService.equipItem(type, itemKey).compose(configureApiCallObserver())
}
override fun buyItem(itemKey: String): Flowable<BuyResponse> {
return apiService.buyItem(itemKey).compose(configureApiCallObserver())
override fun buyItem(itemKey: String, purchaseQuantity: Int): Flowable<BuyResponse> {
return apiService.buyItem(itemKey, mapOf(Pair("quantity", purchaseQuantity))).compose(configureApiCallObserver())
}
override fun purchaseItem(type: String, itemKey: String): Flowable<Any> {
return apiService.purchaseItem(type, itemKey).compose(configureApiCallObserver())
override fun purchaseItem(type: String, itemKey: String, purchaseQuantity: Int): Flowable<Any> {
return apiService.purchaseItem(type, itemKey, mapOf(Pair("quantity", purchaseQuantity))).compose(configureApiCallObserver())
}
override fun validateSubscription(request: SubscriptionValidationRequest): Flowable<Any> {
@ -343,6 +347,10 @@ class ApiClientImpl//private OnHabitsAPIResult mResultListener;
}
}
override fun cancelSubscription(): Flowable<Any> {
return apiService.cancelSubscription().compose(configureApiCallObserver())
}
override fun purchaseHourglassItem(type: String, itemKey: String): Flowable<Any> {
return apiService.purchaseHourglassItem(type, itemKey).compose(configureApiCallObserver())
}

View file

@ -46,6 +46,10 @@ class InventoryRepositoryImpl(localRepository: InventoryLocalRepository, apiClie
return localRepository.getOwnedEquipment()
}
override fun getEquipmentType(type: String, set: String): Flowable<RealmResults<Equipment>> {
return localRepository.getEquipmentType(type, set)
}
override fun getOwnedItems(itemType: String): Flowable<RealmResults<OwnedItem>> {
return localRepository.getOwnedItems(itemType, userID)
}
@ -224,8 +228,8 @@ class InventoryRepositoryImpl(localRepository: InventoryLocalRepository, apiClie
.doOnNext { localRepository.changeOwnedCount("quests", quest.key, userID, -1) }
}
override fun buyItem(user: User?, id: String, value: Double): Flowable<BuyResponse> {
return apiClient.buyItem(id)
override fun buyItem(user: User?, id: String, value: Double, purchaseQuantity: Int): Flowable<BuyResponse> {
return apiClient.buyItem(id, purchaseQuantity)
.doOnNext { buyResponse ->
if (user == null) {
return@doOnNext
@ -247,7 +251,7 @@ class InventoryRepositoryImpl(localRepository: InventoryLocalRepository, apiClie
if (buyResponse.gp != null) {
copiedUser.stats?.gp = buyResponse.gp
} else {
copiedUser.stats?.gp = copiedUser.stats?.gp ?: 0 - value
copiedUser.stats?.gp = copiedUser.stats?.gp ?: 0 - (value * purchaseQuantity)
}
if (buyResponse.lvl != null) {
copiedUser.stats?.lvl = buyResponse.lvl
@ -276,8 +280,8 @@ class InventoryRepositoryImpl(localRepository: InventoryLocalRepository, apiClie
return apiClient.purchaseQuest(key)
}
override fun purchaseItem(purchaseType: String, key: String): Flowable<Any> {
return apiClient.purchaseItem(purchaseType, key)
override fun purchaseItem(purchaseType: String, key: String, purchaseQuantity: Int): Flowable<Any> {
return apiClient.purchaseItem(purchaseType, key, purchaseQuantity)
}
override fun togglePinnedItem(item: ShopItem): Flowable<List<ShopItem>> {

View file

@ -10,6 +10,7 @@ import com.habitrpg.android.habitica.models.responses.TaskDirection
import com.habitrpg.android.habitica.models.responses.TaskDirectionData
import com.habitrpg.android.habitica.models.responses.TaskScoringResult
import com.habitrpg.android.habitica.models.tasks.*
import com.habitrpg.android.habitica.models.user.OwnedItem
import com.habitrpg.android.habitica.models.user.User
import io.reactivex.Flowable
import io.reactivex.Maybe
@ -137,6 +138,23 @@ class TaskRepositoryImpl(localRepository: TaskLocalRepository, apiClient: ApiCli
}
}
}
res._tmp?.drop?.key?.let { key ->
val type = when(res._tmp?.drop?.type?.toLowerCase(Locale.US)) {
"hatchingpotion" -> "hatchingPotions"
"egg" -> "eggs"
else -> res._tmp?.drop?.type?.toLowerCase(Locale.US)
}
var item = it.where(OwnedItem::class.java).equalTo("itemType", type).equalTo("key", key).findFirst()
if (item == null) {
item = OwnedItem()
item.key = key
item.itemType = type
item.userID = user.id
}
item.numberOwned += 1
it.insertOrUpdate(item)
}
val stats = bgUser.stats
stats?.hp = res.hp
stats?.exp = res.exp

View file

@ -141,7 +141,7 @@ class UserRepositoryImpl(localRepository: UserLocalRepository, apiClient: ApiCli
copiedUser.preferences = unlockResponse.preferences
copiedUser.purchased = unlockResponse.purchased
copiedUser.items = unlockResponse.items
copiedUser.balance = copiedUser.balance - customization.price / 4.0
copiedUser.balance = copiedUser.balance - (customization.price ?: 0) / 4.0
localRepository.saveUser(copiedUser)
}
}
@ -352,6 +352,10 @@ class UserRepositoryImpl(localRepository: UserLocalRepository, apiClient: ApiCli
if (newUser.profile != null) {
copiedUser.profile = newUser.profile
}
if (newUser.party != null) {
copiedUser.party = newUser.party
}
copiedUser.needsCron = newUser.needsCron
copiedUser.versionNumber = newUser.versionNumber
localRepository.saveUser(copiedUser)

View file

@ -33,6 +33,7 @@ interface InventoryLocalRepository : ContentLocalRepository {
fun getItems(itemClass: Class<out Item>, keys: Array<String>, user: User?): Flowable<out RealmResults<out Item>>
fun getOwnedItems(itemType: String, userID: String): Flowable<RealmResults<OwnedItem>>
fun getOwnedItems(userID: String): Flowable<Map<String, OwnedItem>>
fun getEquipmentType(type: String, set: String): Flowable<RealmResults<Equipment>>
fun getEquipment(key: String): Flowable<Equipment>
fun getMounts(type: String, group: String, color: String?): Flowable<RealmResults<Mount>>

View file

@ -27,12 +27,10 @@ class RealmCustomizationLocalRepository(realm: Realm) : RealmContentLocalReposit
.isNull("availableFrom")
.isNull("availableUntil")
.endGroup()
.or()
.equalTo("purchased", true)
.endGroup()
}
return query
.sort("customizationSet")
.sort("customizationSetName")
.findAll()
.asFlowable()
.filter { it.isLoaded }

View file

@ -70,6 +70,15 @@ class RealmInventoryLocalRepository(realm: Realm, private val context: Context)
.filter { it.isLoaded }
}
override fun getEquipmentType(type: String, set: String): Flowable<RealmResults<Equipment>> {
return realm.where(Equipment::class.java)
.equalTo("type", type)
.equalTo("gearSet", set)
.findAll()
.asFlowable()
.filter { it.isLoaded }
}
override fun getOwnedItems(itemType: String, userID: String): Flowable<RealmResults<OwnedItem>> {
return realm.where(OwnedItem::class.java)
.greaterThan("numberOwned", 0)
@ -316,7 +325,7 @@ class RealmInventoryLocalRepository(realm: Realm, private val context: Context)
override fun getLatestMysteryItem(): Flowable<Equipment> {
return realm.where(Equipment::class.java)
.contains("key", "mystery_2")
.sort("key", Sort.DESCENDING)
.sort("mystery", Sort.DESCENDING)
.findAll()
.asFlowable()
.filter { it.isLoaded && it.size > 0}

View file

@ -132,7 +132,6 @@ class RealmUserLocalRepository(realm: Realm) : RealmBaseLocalRepository(realm),
val habitClass = if (user.preferences?.disableClasses == true) "none" else user.stats?.habitClass
return realm.where(Skill::class.java)
.equalTo("habitClass", habitClass)
.lessThanOrEqualTo("lvl", user.stats?.lvl ?: 0)
.findAll()
.asFlowable()
.filter { it.isLoaded }

View file

@ -0,0 +1,23 @@
package com.habitrpg.android.habitica.extensions
import android.content.Context
import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.models.inventory.Animal
fun Animal.getTranslatedType(c: Context?): String {
if (c == null) {
return type
}
var currType: String = when (type) {
"drop" -> c?.getString(R.string.standard).toString()
"quest" -> c?.getString(R.string.quest).toString()
"wacky" -> c?.getString(R.string.wacky).toString()
"special" -> c?.getString(R.string.special).toString()
else -> {
type
}
}
return currType
}

View file

@ -79,7 +79,7 @@ class AppConfigManager {
return remoteConfig.getLong("minimumPasswordLength")
}
fun useNewMysteryBenefits(): Boolean {
return remoteConfig.getBoolean("useNewMysteryBenefits")
fun raiseShops(): Boolean {
return remoteConfig.getBoolean("raiseShops")
}
}

View file

@ -115,6 +115,27 @@ class PurchaseHandler(activity: Activity, val crashlyticsProxy: CrashlyticsProxy
}
}
fun checkForSubscription(onSubscriptionFound: ((Purchase) -> Unit)) {
billingRequests?.getPurchases(ProductTypes.SUBSCRIPTION, null, object : RequestListener<Purchases> {
override fun onSuccess(result: Purchases) {
var lastPurchase: Purchase? = null
for (purchase in result.list) {
if (lastPurchase != null && lastPurchase.time > purchase.time) {
continue
} else {
lastPurchase = purchase
}
}
if (lastPurchase != null) {
onSubscriptionFound(lastPurchase)
}
}
override fun onError(response: Int, e: java.lang.Exception) {
}
})
}
private fun checkIfPendingPurchases() {
billingRequests?.getAllPurchases(ProductTypes.IN_APP, object : RequestListener<Purchases> {
override fun onSuccess(purchases: Purchases) {

View file

@ -0,0 +1,71 @@
package com.habitrpg.android.habitica.helpers
import android.net.Uri
import android.os.Build
import android.util.Log
import android.webkit.WebResourceRequest
import android.webkit.WebResourceResponse
import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.annotation.RequiresApi
import com.habitrpg.android.habitica.BuildConfig
class SignInWebViewClient(
private val attempt: SignInWithAppleService.AuthenticationAttempt,
private val callback: (SignInWithAppleResult) -> Unit
) : WebViewClient() {
// for API levels < 24
override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean {
return isUrlOverridden(view, Uri.parse(url))
}
@RequiresApi(Build.VERSION_CODES.N)
override fun shouldOverrideUrlLoading(view: WebView?, request: WebResourceRequest?): Boolean {
return isUrlOverridden(view, request?.url)
}
override fun shouldInterceptRequest(view: WebView?, request: WebResourceRequest?): WebResourceResponse? {
request?.requestHeaders?.let { it["Authorization"] = "Basic " + BuildConfig.STAGING_KEY }
return super.shouldInterceptRequest(view, request)
}
private fun isUrlOverridden(view: WebView?, url: Uri?): Boolean {
return when {
url == null -> {
false
}
url.toString().contains("appleid.apple.com") -> {
view?.loadUrl(url.toString())
true
}
(url.toString().contains(attempt.redirectUri) || url.toString().contains("userID")) -> {
Log.d("Apple Sign in", "Web view was forwarded to redirect URI")
val userID = url.getQueryParameter("userID")
val apiKey = url.getQueryParameter("key")
when {
userID == null || apiKey == null -> {
callback(SignInWithAppleResult.Failure(IllegalArgumentException("data not returned")))
}
else -> {
callback(SignInWithAppleResult.Success(userID, apiKey, url.getQueryParameter("newUser") == "true"))
}
}
true
}
else -> {
false
}
}
}
}
sealed class SignInWithAppleResult {
data class Success(val userID: String, val apiKey: String, val newUser: Boolean) : SignInWithAppleResult()
data class Failure(val error: Throwable) : SignInWithAppleResult()
object Cancel : SignInWithAppleResult()
}

View file

@ -0,0 +1,103 @@
package com.habitrpg.android.habitica.helpers
import android.content.DialogInterface
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.webkit.WebView
import androidx.fragment.app.DialogFragment
import com.habitrpg.android.habitica.R
class SignInWebViewDialogFragment : DialogFragment() {
companion object {
private const val AUTHENTICATION_ATTEMPT_KEY = "authenticationAttempt"
private const val WEB_VIEW_KEY = "webView"
fun newInstance(authenticationAttempt: SignInWithAppleService.AuthenticationAttempt): SignInWebViewDialogFragment {
val fragment = SignInWebViewDialogFragment()
fragment.arguments = Bundle().apply {
putParcelable(AUTHENTICATION_ATTEMPT_KEY, authenticationAttempt)
}
return fragment
}
}
private lateinit var authenticationAttempt: SignInWithAppleService.AuthenticationAttempt
private var callback: ((SignInWithAppleResult) -> Unit)? = null
private val webViewIfCreated: WebView?
get() = view as? WebView
fun configure(callback: (SignInWithAppleResult) -> Unit) {
this.callback = callback
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
authenticationAttempt = arguments?.getParcelable(AUTHENTICATION_ATTEMPT_KEY)!!
setStyle(STYLE_NORMAL, R.style.sign_in_with_apple_button_DialogTheme)
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
super.onCreateView(inflater, container, savedInstanceState)
val webView = WebView(context).apply {
settings.apply {
javaScriptEnabled = true
javaScriptCanOpenWindowsAutomatically = true
}
}
webView.webViewClient = SignInWebViewClient(authenticationAttempt, ::onCallback)
if (savedInstanceState != null) {
savedInstanceState.getBundle(WEB_VIEW_KEY)?.run {
webView.restoreState(this)
}
} else {
webView.loadUrl(authenticationAttempt.authenticationUri)
}
return webView
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putBundle(
WEB_VIEW_KEY,
Bundle().apply {
webViewIfCreated?.saveState(this)
}
)
}
override fun onStart() {
super.onStart()
dialog?.window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)
}
override fun onCancel(dialog: DialogInterface) {
super.onCancel(dialog)
onCallback(SignInWithAppleResult.Cancel)
}
// SignInWithAppleCallback
private fun onCallback(result: SignInWithAppleResult) {
dialog?.dismiss()
val callback = callback
if (callback == null) {
Log.e("Apple Sign in", "Callback is not configured")
return
}
callback(result)
}
}

View file

@ -0,0 +1,89 @@
package com.habitrpg.android.habitica.helpers
import android.net.Uri
import android.os.Parcel
import android.os.Parcelable
import androidx.fragment.app.FragmentManager
import com.willowtreeapps.signinwithapplebutton.SignInWithAppleConfiguration
import java.util.*
class SignInWithAppleService(
private val fragmentManager: FragmentManager,
private val fragmentTag: String,
private val configuration: SignInWithAppleConfiguration,
private val callback: (SignInWithAppleResult) -> Unit
) {
init {
val fragmentIfShown =
fragmentManager.findFragmentByTag(fragmentTag) as? SignInWebViewDialogFragment
fragmentIfShown?.configure(callback)
}
data class AuthenticationAttempt(
val authenticationUri: String,
val redirectUri: String,
val state: String
) : Parcelable {
constructor(parcel: Parcel) : this(
parcel.readString() ?: "invalid",
parcel.readString() ?: "invalid",
parcel.readString() ?: "invalid"
)
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeString(authenticationUri)
parcel.writeString(redirectUri)
parcel.writeString(state)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<AuthenticationAttempt> {
override fun createFromParcel(parcel: Parcel) = AuthenticationAttempt(parcel)
override fun newArray(size: Int): Array<AuthenticationAttempt?> = arrayOfNulls(size)
/*
The authentication page URI we're creating is based off the URI constructed by Apple's JavaScript SDK,
which is why certain fields (like the version, v) are included in the URI construction.
We have to build this URI ourselves because Apple's behavior in JavaScript is to POST the response,
while we need a GET so we can retrieve the authentication code and verify the state
merely by intercepting the URL.
See the Sign In With Apple Javascript SDK for comparison:
https://developer.apple.com/documentation/signinwithapplejs/configuring_your_webpage_for_sign_in_with_apple
*/
fun create(
configuration: SignInWithAppleConfiguration,
state: String = UUID.randomUUID().toString()
): AuthenticationAttempt {
val authenticationUri = Uri
.parse("https://appleid.apple.com/auth/authorize")
.buildUpon().apply {
appendQueryParameter("response_type", "code")
appendQueryParameter("v", "1.1.6")
appendQueryParameter("client_id", configuration.clientId)
appendQueryParameter("redirect_uri", configuration.redirectUri)
appendQueryParameter("scope", configuration.scope)
appendQueryParameter("state", state)
appendQueryParameter("response_mode", "form_post")
}
.build()
.toString()
return AuthenticationAttempt(authenticationUri, configuration.redirectUri, state)
}
}
}
fun show() {
val fragment = SignInWebViewDialogFragment.newInstance(AuthenticationAttempt.create(configuration))
fragment.configure(callback)
fragment.show(fragmentManager, fragmentTag)
}
}

View file

@ -6,13 +6,14 @@ import android.content.Context
import android.content.Intent
import android.os.Build
import android.os.Build.VERSION.SDK_INT
import androidx.core.content.edit
import androidx.preference.PreferenceManager
import com.habitrpg.android.habitica.data.TaskRepository
import com.habitrpg.android.habitica.models.tasks.RemindersItem
import com.habitrpg.android.habitica.models.tasks.Task
import com.habitrpg.android.habitica.receivers.NotificationPublisher
import com.habitrpg.android.habitica.receivers.TaskReceiver
import com.habitrpg.shared.habitica.HLogger
import com.habitrpg.shared.habitica.LogLevel
import io.reactivex.Flowable
import io.reactivex.functions.Consumer
import java.util.*
@ -61,9 +62,6 @@ class TaskAlarmManager(private var context: Context, private var taskRepository:
if (!preventDailyReminder) {
scheduleDailyReminder(context)
}
PreferenceManager.getDefaultSharedPreferences(context).edit {
putLong("lastReminderSchedule", Date().time)
}
}
fun scheduleAlarmsForTask(task: Task) {
@ -168,6 +166,7 @@ class TaskAlarmManager(private var context: Context, private var taskRepository:
}
private fun setAlarm(context: Context, time: Long, pendingIntent: PendingIntent?) {
HLogger.log(LogLevel.INFO, "TaskAlarmManager", "Scheduling for $time")
val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as? AlarmManager
if (pendingIntent == null) {

View file

@ -4,6 +4,7 @@ import com.habitrpg.android.habitica.models.tasks.Task
import io.realm.Case
import io.realm.OrderedRealmCollection
import io.realm.RealmQuery
import io.realm.Sort
import java.util.*
class TaskFilterHelper {
@ -99,7 +100,12 @@ class TaskFilterHelper {
query = query.`in`("tags.id", tagsId.toTypedArray())
}
if (searchQuery?.isNotEmpty() == true) {
query = query.beginsWith("text", searchQuery ?: "", Case.INSENSITIVE)
query = query
.beginGroup()
.contains("text", searchQuery ?: "", Case.INSENSITIVE)
.or()
.contains("notes", searchQuery ?: "", Case.INSENSITIVE)
.endGroup()
}
if (activeFilter != null && activeFilter != Task.FILTER_ALL) {
when (activeFilter) {
@ -115,6 +121,9 @@ class TaskFilterHelper {
Task.FILTER_COMPLETED -> query = query.equalTo("completed", true)
}
}
if (activeFilter != Task.FILTER_DATED) {
query = query.sort("position", Sort.ASCENDING, "dateCreated", Sort.DESCENDING)
}
}
return query
}

View file

@ -61,7 +61,7 @@ constructor(private val soundManager: SoundManager, threadExecutor: ThreadExecut
}
val event = ShareEvent()
event.sharedMessage = requestValues.activity.getString(R.string.share_levelup, requestValues.newLevel) + " https://habitica.com/social/level-UP"
event.sharedMessage = requestValues.activity.getString(R.string.share_levelup, requestValues.newLevel)
val avatarView = AvatarView(requestValues.activity, showBackground = true, showMount = true, showPet = true)
avatarView.setAvatar(requestValues.user)
avatarView.onAvatarImageReady(Consumer { t -> event.shareImage = t })

View file

@ -1,6 +1,5 @@
package com.habitrpg.android.habitica.models.inventory;
public interface Animal {
String getKey();
@ -30,4 +29,4 @@ public interface Animal {
Integer getNumberOwned();
void setNumberOwned(Integer numberOwned);
}
}

View file

@ -1,200 +0,0 @@
package com.habitrpg.android.habitica.models.inventory;
import androidx.annotation.Nullable;
import java.util.Date;
import io.realm.RealmObject;
import io.realm.annotations.PrimaryKey;
public class Customization extends RealmObject {
@PrimaryKey
private String id;
private String identifier, category, type, notes, customizationSet, customizationSetName, text;
private boolean purchased, isBuyable;
private Integer price, setPrice;
private Date availableFrom, availableUntil;
private void updateID() {
this.id = this.identifier + "_" + this.type + "_" + this.category;
}
public String getId() {
return this.id;
}
public void setId(String id) {
this.id = id;
}
@Nullable
public String getIdentifier() {
return this.identifier;
}
public void setIdentifier(String identifier) {
this.identifier = identifier;
this.updateID();
}
@Nullable
public String getCategory() {
return this.category;
}
public void setCategory(String category) {
this.category = category;
this.updateID();
}
@Nullable
public String getType() {
return this.type;
}
public void setType(String type) {
this.type = type;
this.updateID();
}
public String getNotes() {
return this.notes;
}
public void setNotes(String notes) {
this.notes = notes;
}
public String getCustomizationSet() {
return this.customizationSet;
}
public void setCustomizationSet(String customizationSet) {
this.customizationSet = customizationSet;
}
public String getCustomizationSetName() {
return this.customizationSetName;
}
public void setCustomizationSetName(@Nullable String customizationSetName) {
this.customizationSetName = customizationSetName;
}
public String getText() {
return this.text;
}
public void setText(String text) {
this.text = text;
}
@SuppressWarnings("RedundantIfStatement")
public boolean getPurchasable() {
Date today = new Date();
if (this.availableFrom != null && !this.availableFrom.before(today)) {
//Not released yet
return false;
}
if (this.availableUntil != null && !this.availableUntil.after(today)) {
//Discontinued
return false;
}
return true;
}
public boolean getPurchased() {
return this.purchased;
}
public void setPurchased(boolean purchased) {
this.purchased = purchased;
}
public Integer getPrice() {
return this.price;
}
public void setPrice(Integer price) {
this.price = price;
}
public Integer getSetPrice() {
return this.setPrice;
}
public void setSetPrice(Integer setPrice) {
this.setPrice = setPrice;
}
public Date getAvailableFrom() {
return this.availableFrom;
}
public void setAvailableFrom(Date availableFrom) {
this.availableFrom = availableFrom;
}
public Date getAvailableUntil() {
return this.availableUntil;
}
public void setAvailableUntil(Date availableUntil) {
this.availableUntil = availableUntil;
}
public String getImageName(String userSize, String hairColor) {
switch (this.type) {
case "skin":
return "skin_" + this.identifier;
case "shirt":
return userSize + "_shirt_" + this.identifier;
case "hair":
if (this.identifier.equals("0")) {
return "head_0";
}
switch (this.category) {
case "color":
return "hair_bangs_1_" + this.identifier;
case "flower":
return "hair_flower_" + this.identifier;
default:
return "hair_" + this.category + "_" + this.identifier + "_" + hairColor;
}
case "background":
return "background_" + this.identifier;
case "chair":
return "chair_" + identifier;
}
return "";
}
public boolean isUsable() {
return this.price == null || this.price == 0 || this.purchased;
}
public String getPath() {
String path = this.type;
if (this.category != null) {
path = path + "." + this.category;
}
path = path + "." + this.identifier;
return path;
}
public boolean getIsBuyable() {
return isBuyable;
}
public void setIsBuyable(boolean buyable) {
isBuyable = buyable;
}
}

View file

@ -0,0 +1,88 @@
package com.habitrpg.android.habitica.models.inventory
import io.realm.RealmObject
import io.realm.annotations.PrimaryKey
import java.util.*
open class Customization : RealmObject() {
@PrimaryKey
var id: String? = null
var identifier: String? = null
set(value) {
field = value
updateID()
}
var category: String? = null
set(value) {
field = value
updateID()
}
var type: String? = null
set(value) {
field = value
updateID()
}
var notes: String? = null
var customizationSet: String? = null
var customizationSetName: String? = null
var text: String? = null
var isBuyable = false
var price: Int? = null
var setPrice: Int? = null
var availableFrom: Date? = null
var availableUntil: Date? = null
private fun updateID() {
id = identifier + "_" + type + "_" + this.category
}
//Not released yet
val purchasable: Boolean
get() {
val today = Date()
if (availableFrom != null && !availableFrom!!.before(today)) { //Not released yet
return false
}
return !(availableUntil != null && !availableUntil!!.after(today))
}
fun getIconName(userSize: String?, hairColor: String?): String {
return if (type == "background") {
"icon_background_$identifier"
} else {
getImageName(userSize, hairColor)
}
}
fun getImageName(userSize: String?, hairColor: String?): String {
when (type) {
"skin" -> return "skin_$identifier"
"shirt" -> return userSize + "_shirt_" + identifier
"hair" -> {
return if (identifier == "0") {
"head_0"
} else when (this.category) {
"color" -> "hair_bangs_1_$identifier"
"flower" -> "hair_flower_$identifier"
else -> "hair_" + this.category + "_" + identifier + "_" + hairColor
}
}
"background" -> return "background_$identifier"
"chair" -> return "chair_$identifier"
}
return ""
}
fun isUsable(purchased: Boolean): Boolean {
return price == null || price == 0 || purchased
}
val path: String
get() {
var path = type
if (this.category != null) {
path = path + "." + this.category
}
path = "$path.$identifier"
return path
}
}

View file

@ -23,4 +23,6 @@ open class Equipment : RealmObject() {
var _int: Int = 0
var owned: Boolean? = null
var twoHanded = false
var mystery = ""
var gearSet = ""
}

View file

@ -1,7 +1,5 @@
package com.habitrpg.android.habitica.models.inventory;
import androidx.annotation.Nullable;
import io.realm.RealmObject;
import io.realm.annotations.Ignore;
import io.realm.annotations.PrimaryKey;

View file

@ -1,6 +1,5 @@
package com.habitrpg.android.habitica.models.inventory;
import io.realm.RealmObject;
import io.realm.annotations.Ignore;
import io.realm.annotations.PrimaryKey;
@ -28,6 +27,7 @@ public class Pet extends RealmObject implements Animal{
return text;
}
@Override
public void setText(String text) {
this.text = text;

View file

@ -28,6 +28,8 @@ open class Quest : RealmObject() {
var participants: RealmList<Member>? = null
var rageStrikes: RealmList<QuestRageStrike>? = null
var completed: String? = null
fun hasRageStrikes(): Boolean {
return rageStrikes?.isNotEmpty() ?: false
}

View file

@ -16,6 +16,7 @@ open class QuestContent : RealmObject(), Item {
}
internal var text: String = ""
var notes: String = ""
var completion: String = ""
internal var value: Int = 0
var previous: String? = null
var lvl: Int = 0

View file

@ -1,5 +1,6 @@
package com.habitrpg.android.habitica.models.shops
import android.content.Context
import android.content.res.Resources
import com.google.gson.annotations.SerializedName
@ -12,6 +13,10 @@ import io.realm.annotations.PrimaryKey
open class ShopItem : RealmObject() {
@PrimaryKey
var key: String = ""
set(value) {
field = value
unlockCondition?.questKey = key
}
var text: String? = ""
var notes: String? = ""
@SerializedName("class")
@ -36,11 +41,20 @@ open class ShopItem : RealmObject() {
var categoryIdentifier: String = ""
var limitedNumberLeft: Int? = null
var unlockCondition: ShopItemUnlockCondition? = null
set(value) {
field = value
if (key.isNotEmpty()) {
field?.questKey = key
}
}
var path: String? = null
var isSuggested: String? = null
var pinType: String? = null
@SerializedName("klass")
var habitClass: String? = null
var previous: String? = null
@SerializedName("lvl")
var level: Int? = null
val isTypeItem: Boolean
get() = "eggs" == purchaseType || "hatchingPotions" == purchaseType || "food" == purchaseType || "armoire" == purchaseType || "potion" == purchaseType
@ -54,10 +68,10 @@ open class ShopItem : RealmObject() {
val isTypeAnimal: Boolean
get() = "pets" == purchaseType || "mounts" == purchaseType
fun canAfford(user: User?, canAlwaysAffordSpecial: Boolean): Boolean = when(currency) {
"gold" -> value <= user?.stats?.gp ?: 0.0
"gems" -> if (canAlwaysAffordSpecial) true else value <= user?.gemCount ?: 0
"hourglasses" -> if (canAlwaysAffordSpecial) true else value <= user?.purchased?.plan?.consecutive?.trinkets ?: 0
fun canAfford(user: User?, quantity: Int): Boolean = when(currency) {
"gold" -> (value * quantity) <= user?.stats?.gp ?: 0.0
"gems" -> true
"hourglasses" -> true
else -> false
}
@ -73,6 +87,46 @@ open class ShopItem : RealmObject() {
return this.key.hashCode()
}
fun shortLockedReason(context: Context): String? {
return when {
unlockCondition != null -> {
unlockCondition?.shortReadableUnlockCondition(context)
}
previous != null -> {
try {
val thisNumber = Character.getNumericValue(key.last())
context.getString(R.string.unlock_previous_short, thisNumber - 1)
} catch (e: NumberFormatException) {
null
}
}
level != null -> {
context.getString(R.string.unlock_level_short, level ?: 0)
}
else -> null
}
}
fun lockedReason(context: Context): String? {
return when {
unlockCondition != null -> {
unlockCondition?.readableUnlockCondition(context)
}
previous != null -> {
try {
val thisNumber = Character.getNumericValue(key.last())
context.getString(R.string.unlock_previous, thisNumber - 1)
} catch (e: NumberFormatException) {
null
}
}
level != null -> {
context.getString(R.string.unlock_level, level ?: 0)
}
else -> null
}
}
companion object {
private const val GEM_FOR_GOLD = "gem"

View file

@ -1,5 +1,6 @@
package com.habitrpg.android.habitica.models.shops
import android.content.Context
import com.habitrpg.android.habitica.R
import io.realm.RealmObject
@ -8,12 +9,21 @@ import io.realm.annotations.PrimaryKey
open class ShopItemUnlockCondition : RealmObject() {
@PrimaryKey
internal var condition: String? = null
var questKey: String? = null
private var condition: String? = null
var incentiveThreshold: Int? = null
fun readableUnlockConditionId(): Int = when (this.condition) {
"party invite" -> R.string.party_invite
"login incentive" -> R.string.login_incentive
"create account" -> R.string.create_account
else -> R.string.empty
fun readableUnlockCondition(context: Context): String = when (this.condition) {
"party invite" -> context.getString(R.string.party_invite)
"login reward" -> if (incentiveThreshold != null) context.getString(R.string.login_incentive_count, incentiveThreshold) else context.getString(R.string.login_incentive)
"create account" -> context.getString(R.string.create_account)
else -> ""
}
fun shortReadableUnlockCondition(context: Context): String = when (this.condition) {
"party invite" -> context.getString(R.string.party_invite_short)
"login reward" -> if (incentiveThreshold != null) context.getString(R.string.login_incentive_short_count, incentiveThreshold) else context.getString(R.string.login_incentive_short)
"create account" -> context.getString(R.string.create_account_short)
else -> ""
}
}

View file

@ -32,6 +32,7 @@ open class Task : RealmObject, Parcelable {
var notes: String? = null
@TaskTypes
var type: String = ""
var challengeID: String? = null
var attribute: String? = Stats.STRENGTH
var value: Double = 0.0
var tags: RealmList<Tag>? = RealmList()

View file

@ -0,0 +1,19 @@
package com.habitrpg.android.habitica.models.user
import io.realm.RealmObject
open class EmailNotificationsPreference : RealmObject() {
var unsubscribeFromAll: Boolean = false
var invitedParty: Boolean = false
var invitedQuest: Boolean = false
var majorUpdates: Boolean = false
var wonChallenge: Boolean = false
var invitedGuild: Boolean = false
var newPM: Boolean = false
var questStarted: Boolean = false
var giftedGems: Boolean = false
var giftedSubscription: Boolean = false
var subscriptionReminders: Boolean = false
var onboarding: Boolean = false
var kickedGroup: Boolean = false
}

View file

@ -0,0 +1,28 @@
package com.habitrpg.android.habitica.models.user
import io.realm.RealmObject
import io.realm.annotations.PrimaryKey
open class OwnedCustomization : RealmObject(), OwnedObject {
@PrimaryKey
override var combinedKey: String? = null
override var userID: String? = null
set(value) {
field = value
combinedKey = field + type + key
}
override var key: String? = null
set(value) {
field = value
combinedKey = userID + type + field
}
var type: String? = null
set(value) {
field = value
combinedKey = userID + field + key
}
var category: String? = null
var purchased = false
}

View file

@ -6,6 +6,7 @@ import com.habitrpg.android.habitica.models.AvatarPreferences
import io.realm.RealmObject
import io.realm.annotations.PrimaryKey
import java.util.*
open class Preferences : RealmObject(), AvatarPreferences {
@ -33,6 +34,7 @@ open class Preferences : RealmObject(), AvatarPreferences {
var timezoneOffset: Int = 0
var timezoneOffsetAtLastCron: Int = 0
var pushNotifications: PushNotificationsPreference? = null
var emailNotifications: EmailNotificationsPreference? = null
var autoEquip: Boolean = true
override fun getBackground(): String? {
@ -93,7 +95,7 @@ open class Preferences : RealmObject(), AvatarPreferences {
override fun getChair(): String? {
return if (chair != null && chair != "none") {
if (chair!!.length > 5 && chair!!.substring(0, 6) != "chair_") {
if (chair?.contains("chair_") == true) {
chair
} else {
"chair_" + chair!!
@ -120,6 +122,6 @@ open class Preferences : RealmObject(), AvatarPreferences {
}
fun hasTaskBasedAllocation(): Boolean {
return allocationMode?.toLowerCase() == "taskbased" && automaticAllocation
return allocationMode?.toLowerCase(Locale.ROOT) == "taskbased" && automaticAllocation
}
}

View file

@ -1,7 +1,5 @@
package com.habitrpg.android.habitica.models.user;
import com.habitrpg.android.habitica.models.inventory.Customization;
import java.util.List;
import io.realm.RealmList;
@ -13,15 +11,15 @@ public class Purchases extends RealmObject {
@PrimaryKey
private String userId;
public RealmList<Customization> customizations;
public RealmList<OwnedCustomization> customizations;
User user;
private SubscriptionPlan plan;
public List<Customization> getCustomizations() {
public List<OwnedCustomization> getCustomizations() {
return customizations;
}
public void setCustomizations(RealmList<Customization> customizations) {
public void setCustomizations(RealmList<OwnedCustomization> customizations) {
this.customizations = customizations;
}

View file

@ -6,6 +6,8 @@ import android.content.Intent
import android.content.SharedPreferences
import com.habitrpg.android.habitica.HabiticaBaseApplication
import com.habitrpg.android.habitica.helpers.TaskAlarmManager
import com.habitrpg.shared.habitica.HLogger
import com.habitrpg.shared.habitica.LogLevel
import javax.inject.Inject
class TaskAlarmBootReceiver : BroadcastReceiver() {
@ -18,6 +20,7 @@ class TaskAlarmBootReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, arg1: Intent) {
HabiticaBaseApplication.userComponent?.inject(this)
taskAlarmManager.scheduleAllSavedAlarms(sharedPreferences.getBoolean("preventDailyReminder", false))
HLogger.log(LogLevel.INFO, this::javaClass.name, "onReceive")
}
}

View file

@ -15,6 +15,8 @@ import com.habitrpg.android.habitica.helpers.RxErrorHandler
import com.habitrpg.android.habitica.helpers.TaskAlarmManager
import com.habitrpg.android.habitica.models.tasks.Task
import com.habitrpg.android.habitica.ui.activities.MainActivity
import com.habitrpg.shared.habitica.HLogger
import com.habitrpg.shared.habitica.LogLevel
import io.reactivex.functions.Consumer
import java.util.*
import javax.inject.Inject
@ -31,6 +33,7 @@ class TaskReceiver : BroadcastReceiver() {
lateinit var taskRepository: TaskRepository
override fun onReceive(context: Context, intent: Intent) {
HLogger.log(LogLevel.INFO, this::javaClass.name, "onReceive")
HabiticaBaseApplication.userComponent?.inject(this)
val extras = intent.extras
if (extras != null) {
@ -58,6 +61,7 @@ class TaskReceiver : BroadcastReceiver() {
private fun createNotification(context: Context, task: Task) {
val intent = Intent(context, MainActivity::class.java)
HLogger.log(LogLevel.INFO, this::javaClass.name, "Create Notification")
intent.putExtra("notificationIdentifier", "task_reminder")
val pendingIntent = PendingIntent.getActivity(context, System.currentTimeMillis().toInt(), intent, 0)

View file

@ -18,6 +18,7 @@ import com.facebook.imagepipeline.image.ImageInfo
import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.helpers.AppConfigManager
import com.habitrpg.android.habitica.models.Avatar
import com.habitrpg.android.habitica.ui.helpers.DataBindingUtils
import io.reactivex.functions.Consumer
import java.util.*
import java.util.concurrent.atomic.AtomicInteger
@ -121,7 +122,7 @@ class AvatarView : View {
multiDraweeHolder.add(draweeHolder)
val controller = Fresco.newDraweeControllerBuilder()
.setUri(IMAGE_URI_ROOT + getFileName(layerName))
.setUri(IMAGE_URI_ROOT + DataBindingUtils.getFullFilename(layerName, null))
.setControllerListener(object : BaseControllerListener<ImageInfo>() {
override fun onFinalImageSet(
id: String?,
@ -382,18 +383,7 @@ class AvatarView : View {
return bounds
}
private fun getFileName(imageName: String): String {
val name = when {
FILENAME_MAP.containsKey(imageName) -> FILENAME_MAP[imageName]
imageName.startsWith("handleless") -> "chair_$imageName"
else -> imageName
}
return name + if (FILEFORMAT_MAP.containsKey(imageName)) {
"." + FILEFORMAT_MAP[imageName]
} else {
".png"
}
}
private fun onLayerComplete() {
if (numberLayersInProcess.decrementAndGet() == 0) {
@ -528,50 +518,9 @@ class AvatarView : View {
companion object {
const val IMAGE_URI_ROOT = "https://habitica-assets.s3.amazonaws.com/mobileApp/images/"
private const val TAG = "AvatarView"
val FILEFORMAT_MAP: Map<String, String>
val FILENAME_MAP: Map<String, String>
private val FULL_HERO_RECT = Rect(0, 0, 140, 147)
private val COMPACT_HERO_RECT = Rect(0, 0, 114, 114)
private val HERO_ONLY_RECT = Rect(0, 0, 90, 90)
init {
val tempMap = HashMap<String, String>()
tempMap["head_special_1"] = "gif"
tempMap["broad_armor_special_1"] = "gif"
tempMap["slim_armor_special_1"] = "gif"
tempMap["head_special_0"] = "gif"
tempMap["slim_armor_special_0"] = "gif"
tempMap["broad_armor_special_0"] = "gif"
tempMap["weapon_special_critical"] = "gif"
tempMap["weapon_special_0"] = "gif"
tempMap["shield_special_0"] = "gif"
tempMap["Pet-Wolf-Cerberus"] = "gif"
tempMap["armor_special_ks2019"] = "gif"
tempMap["slim_armor_special_ks2019"] = "gif"
tempMap["broad_armor_special_ks2019"] = "gif"
tempMap["eyewear_special_ks2019"] = "gif"
tempMap["head_special_ks2019"] = "gif"
tempMap["shield_special_ks2019"] = "gif"
tempMap["weapon_special_ks2019"] = "gif"
tempMap["Pet-Gryphon-Gryphatrice"] = "gif"
tempMap["Mount_Head_Gryphon-Gryphatrice"] = "gif"
tempMap["Mount_Body_Gryphon-Gryphatrice"] = "gif"
tempMap["background_clocktower"] = "gif"
tempMap["background_airship"] = "gif"
tempMap["background_steamworks"] = "gif"
FILEFORMAT_MAP = Collections.unmodifiableMap(tempMap)
val tempNameMap = HashMap<String, String>()
tempNameMap["head_special_1"] = "ContributorOnly-Equip-CrystalHelmet"
tempNameMap["armor_special_1"] = "ContributorOnly-Equip-CrystalArmor"
tempNameMap["head_special_0"] = "BackerOnly-Equip-ShadeHelmet"
tempNameMap["armor_special_0"] = "BackerOnly-Equip-ShadeArmor"
tempNameMap["shield_special_0"] = "BackerOnly-Shield-TormentedSkull"
tempNameMap["weapon_special_0"] = "BackerOnly-Weapon-DarkSoulsBlade"
tempNameMap["weapon_special_critical"] = "weapon_special_critical"
tempNameMap["Pet-Wolf-Cerberus"] = "Pet-Wolf-Cerberus"
FILENAME_MAP = Collections.unmodifiableMap(tempNameMap)
}
}
}

View file

@ -47,9 +47,9 @@ class FixCharacterValuesActivity: BaseActivity() {
setTitle(R.string.fix_character_values)
setupToolbar(binding.toolbar)
repository.getUser(userId).firstElement().subscribe(Consumer {
compositeSubscription.add(repository.getUser(userId).firstElement().subscribe(Consumer {
user = it
}, RxErrorHandler.handleEmptyError())
}, RxErrorHandler.handleEmptyError()))
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
@ -57,8 +57,8 @@ class FixCharacterValuesActivity: BaseActivity() {
return true
}
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
val id = item?.itemId
override fun onOptionsItemSelected(item: MenuItem): Boolean {
val id = item.itemId
if (id == R.id.action_save_changes) {
@Suppress("DEPRECATION")
@ -70,10 +70,10 @@ class FixCharacterValuesActivity: BaseActivity() {
userInfo["stats.mp"] = binding.manaEditText.getDoubleValue()
userInfo["stats.lvl"] = binding.levelEditText.getDoubleValue().toInt()
userInfo["achievements.streak"] = binding.streakEditText.getDoubleValue().toInt()
repository.updateUser(user, userInfo).subscribe(Consumer {}, RxErrorHandler.handleEmptyError(), Action {
compositeSubscription.add(repository.updateUser(user, userInfo).subscribe(Consumer {}, RxErrorHandler.handleEmptyError(), Action {
progressDialog.dismiss()
finish()
})
}))
return true
}
@ -89,14 +89,15 @@ class FixCharacterValuesActivity: BaseActivity() {
}
private fun updateFields(user: User) {
binding.healthEditText.text = user.stats?.hp.toString()
binding.experienceEditText.text = user.stats?.exp.toString()
binding.goldEditText.text = user.stats?.gp.toString()
binding.manaEditText.text = user.stats?.mp.toString()
binding.levelEditText.text = user.stats?.lvl.toString()
val stats = user.stats ?: return
binding.healthEditText.text = stats.hp.toString()
binding.experienceEditText.text = stats.exp.toString()
binding.goldEditText.text = stats.gp.toString()
binding.manaEditText.text = stats.mp.toString()
binding.levelEditText.text = stats.lvl.toString()
binding.streakEditText.text = user.streakCount.toString()
when (user.stats?.habitClass) {
when (stats.habitClass) {
Stats.WARRIOR -> {
binding.levelEditText.iconBackgroundColor = ContextCompat.getColor(this, R.color.red_500)
binding.levelEditText.setIconBitmap(HabiticaIconsHelper.imageOfWarriorLightBg())
@ -116,7 +117,7 @@ class FixCharacterValuesActivity: BaseActivity() {
}
}
fun FixValuesEditText.getDoubleValue(): Double {
private fun FixValuesEditText.getDoubleValue(): Double {
val stringValue = this.text
return try {
stringValue.toDouble()

View file

@ -31,6 +31,7 @@ import com.google.android.gms.common.ConnectionResult
import com.google.android.gms.common.GoogleApiAvailability
import com.google.android.gms.common.GooglePlayServicesUtil
import com.google.android.gms.common.Scopes
import com.habitrpg.android.habitica.BuildConfig
import com.habitrpg.android.habitica.HabiticaBaseApplication
import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.api.HostConfig
@ -40,10 +41,7 @@ import com.habitrpg.android.habitica.data.UserRepository
import com.habitrpg.android.habitica.extensions.addCancelButton
import com.habitrpg.android.habitica.extensions.addCloseButton
import com.habitrpg.android.habitica.extensions.addOkButton
import com.habitrpg.android.habitica.helpers.AmplitudeManager
import com.habitrpg.android.habitica.helpers.AppConfigManager
import com.habitrpg.android.habitica.helpers.KeyHelper
import com.habitrpg.android.habitica.helpers.RxErrorHandler
import com.habitrpg.android.habitica.helpers.*
import com.habitrpg.android.habitica.models.auth.UserAuthResponse
import com.habitrpg.android.habitica.proxy.CrashlyticsProxy
import com.habitrpg.android.habitica.ui.helpers.bindView
@ -51,6 +49,7 @@ import com.habitrpg.android.habitica.ui.helpers.dismissKeyboard
import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaAlertDialog
import com.habitrpg.android.habitica.ui.views.login.LockableScrollView
import com.habitrpg.android.habitica.ui.views.login.LoginBackgroundView
import com.willowtreeapps.signinwithapplebutton.SignInWithAppleConfiguration
import io.reactivex.Flowable
import io.reactivex.exceptions.Exceptions
import io.reactivex.functions.Consumer
@ -96,6 +95,7 @@ class LoginActivity : BaseActivity(), Consumer<UserAuthResponse> {
private val forgotPasswordButton: Button by bindView(R.id.forgot_password)
private val facebookLoginButton: Button by bindView(R.id.fb_login_button)
private val googleLoginButton: Button by bindView(R.id.google_login_button)
private val appleLoginButton: Button by bindView(R.id.apple_login_button)
private var callbackManager = CallbackManager.Factory.create()
private var googleEmail: String? = null
@ -177,6 +177,25 @@ class LoginActivity : BaseActivity(), Consumer<UserAuthResponse> {
forgotPasswordButton.setOnClickListener { onForgotPasswordClicked() }
facebookLoginButton.setOnClickListener { handleFacebookLogin() }
googleLoginButton.setOnClickListener { handleGoogleLogin() }
appleLoginButton.setOnClickListener {
val configuration = SignInWithAppleConfiguration(
clientId = BuildConfig.APPLE_AUTH_CLIENT_ID,
redirectUri = "${hostConfig.address}/api/v4/user/auth/apple",
scope = "name email"
)
val fragmentTag = "SignInWithAppleButton-SignInWebViewDialogFragment"
SignInWithAppleService(supportFragmentManager, fragmentTag, configuration) { result ->
when (result) {
is SignInWithAppleResult.Success -> {
val response = UserAuthResponse()
response.id = result.userID
response.apiToken = result.apiKey
response.newUser = result.newUser
}
}
}.show()
}
}
private fun setupFacebookLogin() {

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