Implement improved help screen

This commit is contained in:
Phillip Thelen 2020-03-18 15:18:59 +01:00
parent 057e9963bf
commit edc2a83a08
29 changed files with 1630 additions and 519 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 904 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 638 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 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,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_300" >
</solid>
<!-- Here is the corner radius -->
<corners android:bottomLeftRadius="4dp" android:bottomRightRadius="4dp">
</corners>
</shape>

View file

@ -1,36 +0,0 @@
<?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/teal_100"
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

@ -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,170 @@
<?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/using_habitica"
android:layout_marginStart="@dimen/spacing_large"
android:layout_marginEnd="@dimen/spacing_large"
android:textSize="16sp"
android:textStyle="bold"
android:textColor="@color/brand_300"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/using_habitica_description"
android:textSize="12sp"
android:textColor="@color/gray_300"
android:layout_marginStart="40dp"
android:layout_marginEnd="40dp"
android:gravity="center"
android:layout_marginTop="4dp"
android:layout_marginBottom="10dp"
/>
<TextView
android:layout_width="match_parent"
android:layout_height="40dp"
android:text="@string/lets_go"
android:gravity="center"
android:layout_marginStart="@dimen/spacing_large"
android:layout_marginEnd="@dimen/spacing_large"
android:background="@drawable/support_info_lower_bg"
android:textColor="@color/white"
android:textAllCaps="true"
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"
android:textSize="16sp"
android:textStyle="bold"
android:textColor="@color/brand_300"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/bugs_fixes_description"
android:textSize="12sp"
android:textColor="@color/gray_300"
android:layout_marginStart="40dp"
android:layout_marginEnd="40dp"
android:gravity="center"
android:layout_marginTop="4dp"
android:layout_marginBottom="10dp"
/>
<TextView
android:layout_width="match_parent"
android:layout_height="40dp"
android:text="@string/get_help"
android:gravity="center"
android:layout_marginStart="@dimen/spacing_large"
android:layout_marginEnd="@dimen/spacing_large"
android:background="@drawable/support_info_lower_bg"
android:textColor="@color/white"
android:textAllCaps="true"
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"
android:textSize="16sp"
android:textStyle="bold"
android:textColor="@color/brand_300"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/suggestions_feedback_description"
android:textSize="12sp"
android:textColor="@color/gray_300"
android:layout_marginStart="40dp"
android:layout_marginEnd="40dp"
android:gravity="center"
android:layout_marginTop="4dp"
android:layout_marginBottom="10dp"
/>
<TextView
android:layout_width="match_parent"
android:layout_height="40dp"
android:text="@string/contact_us"
android:gravity="center"
android:layout_marginStart="@dimen/spacing_large"
android:layout_marginEnd="@dimen/spacing_large"
android:background="@drawable/support_info_lower_bg"
android:textColor="@color/white"
android:textStyle="bold"
android:textAllCaps="true"
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.Blue"
android:text="@string/reset_walkthrough"
android:layout_margin="@dimen/spacing_large"/>
</LinearLayout>

View file

@ -0,0 +1,60 @@
<?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"
android:textSize="14sp"
android:textStyle="bold"
tools:text="Title"/>
<TextView
android:id="@+id/subtitle_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/gray_200"
android:textSize="14sp"
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

@ -202,12 +202,9 @@
android:label="@string/sidebar_news" />
<fragment
android:id="@+id/FAQOverviewFragment"
android:name="com.habitrpg.android.habitica.ui.fragments.faq.FAQOverviewFragment"
android:name="com.habitrpg.android.habitica.ui.fragments.support.FAQOverviewFragment"
android:label="@string/sidebar_help" >
<deepLink app:uri="habitica.com/static/faq" />
<action
android:id="@+id/openFAQDetail"
app:destination="@id/FAQDetailFragment" />
</fragment>
<fragment
android:id="@+id/aboutFragment"
@ -246,14 +243,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"
@ -403,4 +392,16 @@
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="SupportMainFragment" >
<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="BugFixFragment" />
</navigation>

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,11 @@
<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>
</resources>

View file

@ -344,6 +344,7 @@
<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>
@ -954,7 +955,45 @@
<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="wacky"> Wacky </string>
</resources>

View file

@ -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>

View file

@ -42,16 +42,9 @@ 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.preferences.EmailNotificationsPreferencesFragment;
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.AvatarOverviewFragment;
import com.habitrpg.android.habitica.ui.fragments.inventory.equipment.EquipmentDetailFragment;
@ -66,9 +59,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;
@ -77,12 +75,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;
@ -93,6 +91,9 @@ 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.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;
@ -146,8 +147,6 @@ public interface UserComponent {
void inject(TasksFragment tasksFragment);
void inject(FAQDetailFragment faqDetailFragment);
void inject(FAQOverviewFragment faqOverviewFragment);
void inject(AvatarCustomizationFragment avatarCustomizationFragment);
@ -331,4 +330,8 @@ public interface UserComponent {
void inject(@NotNull GiftBalanceGemsFragment giftBalanceGemsFragment);
void inject(@NotNull EmailNotificationsPreferencesFragment emailNotificationsPreferencesFragment);
void inject(@NotNull SupportMainFragment supportMainFragment);
void inject(@NotNull BugFixFragment bugFixFragment);
}

View file

@ -1,120 +0,0 @@
package com.habitrpg.android.habitica.ui.adapter
import android.text.method.LinkMovementMethod
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.TextView
import androidx.core.os.bundleOf
import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.helpers.MainNavigationController
import com.habitrpg.android.habitica.models.FAQArticle
import com.habitrpg.android.habitica.ui.activities.MainActivity
import com.habitrpg.android.habitica.ui.fragments.faq.FAQOverviewFragmentDirections
import com.habitrpg.android.habitica.ui.helpers.bindView
import com.habitrpg.android.habitica.ui.helpers.setMarkdown
import io.reactivex.BackpressureStrategy
import io.reactivex.Flowable
import io.reactivex.subjects.PublishSubject
class FAQOverviewRecyclerAdapter : androidx.recyclerview.widget.RecyclerView.Adapter<androidx.recyclerview.widget.RecyclerView.ViewHolder>() {
var activity: MainActivity? = null
private var articles: List<FAQArticle> = emptyList()
private val resetWalkthroughEvents = PublishSubject.create<String>()
fun setArticles(articles: List<FAQArticle>) {
this.articles = articles
this.notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): androidx.recyclerview.widget.RecyclerView.ViewHolder {
return when (viewType) {
VIEW_TYPE_JUSTIN -> {
val view = LayoutInflater.from(parent.context).inflate(R.layout.button_list_item, parent, false)
ResetWalkthroughViewHolder(view)
}
VIEW_TYPE_HEADER -> {
val view = LayoutInflater.from(parent.context).inflate(R.layout.help_header, parent, false)
HeaderViewHolder(view)
}
else -> {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.plain_list_item, parent, false)
FAQArticleViewHolder(view)
}
}
}
override fun onBindViewHolder(holder: androidx.recyclerview.widget.RecyclerView.ViewHolder, position: Int) {
if (getItemViewType(position) == VIEW_TYPE_FAQ) {
(holder as? FAQArticleViewHolder)?.bind(articles[position - 1])
}
}
override fun getItemViewType(position: Int): Int {
return when (position) {
0 -> VIEW_TYPE_HEADER
articles.size+1 -> VIEW_TYPE_JUSTIN
else -> VIEW_TYPE_FAQ
}
}
override fun getItemCount(): Int {
return this.articles.size + 2
}
fun getResetWalkthroughEvents(): Flowable<String> {
return resetWalkthroughEvents.toFlowable(BackpressureStrategy.DROP)
}
internal inner class FAQArticleViewHolder(itemView: View) : androidx.recyclerview.widget.RecyclerView.ViewHolder(itemView), View.OnClickListener {
private val textView: TextView by bindView(itemView, R.id.textView)
private var article: FAQArticle? = null
init {
textView.setOnClickListener(this)
}
fun bind(article: FAQArticle) {
this.article = article
this.textView.text = this.article?.question
}
override fun onClick(v: View) {
article?.position?.let {
MainNavigationController.navigate(FAQOverviewFragmentDirections.openFAQDetail(it))
}
}
}
private inner class ResetWalkthroughViewHolder internal constructor(itemView: View) : androidx.recyclerview.widget.RecyclerView.ViewHolder(itemView) {
init {
val button = itemView as? Button
button?.text = itemView.context.getString(R.string.reset_walkthrough)
button?.setOnClickListener { resetWalkthroughEvents.onNext("") }
}
}
private inner class HeaderViewHolder internal constructor(itemView: View) : androidx.recyclerview.widget.RecyclerView.ViewHolder(itemView) {
init {
val textView = itemView.findViewById<TextView>(R.id.text_view)
textView.setMarkdown(itemView.context.getString(R.string.need_help_header_description, "[Habitica Help Guild](https://habitica.com/groups/guild/5481ccf3-5d2d-48a9-a871-70a7380cee5a)"))
textView.setOnClickListener { MainNavigationController.navigate(R.id.guildFragment, bundleOf("groupID" to "5481ccf3-5d2d-48a9-a871-70a7380cee5a")) }
textView.movementMethod = LinkMovementMethod.getInstance()
}
}
companion object {
private const val VIEW_TYPE_JUSTIN = 0
private const val VIEW_TYPE_HEADER = 1
private const val VIEW_TYPE_FAQ = 2
}
}

View file

@ -323,7 +323,7 @@ class NavigationDrawerFragment : DialogFragment() {
items.add(HabiticaDrawerItem(R.id.subscriptionPurchaseActivity, SIDEBAR_SUBSCRIPTION, context.getString(R.string.sidebar_subscription), isHeader = false))
items.add(HabiticaDrawerItem(0, SIDEBAR_ABOUT_HEADER, context.getString(R.string.sidebar_about), true))
items.add(HabiticaDrawerItem(R.id.newsFragment, SIDEBAR_NEWS, context.getString(R.string.sidebar_news)))
items.add(HabiticaDrawerItem(R.id.FAQOverviewFragment, SIDEBAR_HELP, context.getString(R.string.sidebar_help)))
items.add(HabiticaDrawerItem(R.id.supportMainFragment, SIDEBAR_HELP, context.getString(R.string.sidebar_help)))
items.add(HabiticaDrawerItem(R.id.aboutFragment, SIDEBAR_ABOUT, context.getString(R.string.sidebar_about)))
}
if (configManager.enableGiftOneGetOne()) {

View file

@ -1,52 +0,0 @@
package com.habitrpg.android.habitica.ui.fragments.faq
import android.os.Bundle
import android.text.method.LinkMovementMethod
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.components.UserComponent
import com.habitrpg.android.habitica.data.FAQRepository
import com.habitrpg.android.habitica.extensions.inflate
import com.habitrpg.android.habitica.helpers.RxErrorHandler
import com.habitrpg.android.habitica.ui.fragments.BaseMainFragment
import com.habitrpg.android.habitica.ui.helpers.MarkdownParser
import com.habitrpg.android.habitica.ui.helpers.bindOptionalView
import com.habitrpg.android.habitica.ui.helpers.resetViews
import io.reactivex.functions.Consumer
import javax.inject.Inject
class FAQDetailFragment : BaseMainFragment() {
@Inject
lateinit var faqRepository: FAQRepository
private val questionTextView: TextView? by bindOptionalView(R.id.questionTextView)
private val answerTextView: TextView? by bindOptionalView(R.id.answerTextView)
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
super.onCreateView(inflater, container, savedInstanceState)
return container?.inflate(R.layout.fragment_faq_detail)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
resetViews()
arguments?.let {
val args = FAQDetailFragmentArgs.fromBundle(it)
compositeSubscription.add(faqRepository.getArticle(args.position).subscribe(Consumer { faq ->
this.questionTextView?.text = faq.question
this.answerTextView?.text = MarkdownParser.parseMarkdown(faq.answer)
}, RxErrorHandler.handleEmptyError()))
}
this.answerTextView?.movementMethod = LinkMovementMethod.getInstance()
}
override fun injectFragment(component: UserComponent) {
component.inject(this)
}
}

View file

@ -1,65 +0,0 @@
package com.habitrpg.android.habitica.ui.fragments.faq
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.components.UserComponent
import com.habitrpg.android.habitica.data.FAQRepository
import com.habitrpg.android.habitica.extensions.inflate
import com.habitrpg.android.habitica.helpers.RxErrorHandler
import com.habitrpg.android.habitica.ui.adapter.FAQOverviewRecyclerAdapter
import com.habitrpg.android.habitica.ui.fragments.BaseMainFragment
import com.habitrpg.android.habitica.ui.helpers.SafeDefaultItemAnimator
import com.habitrpg.android.habitica.ui.helpers.bindView
import com.habitrpg.android.habitica.ui.helpers.resetViews
import io.reactivex.functions.Consumer
import javax.inject.Inject
class FAQOverviewFragment : BaseMainFragment() {
@Inject
lateinit var faqRepository: FAQRepository
private val recyclerView: androidx.recyclerview.widget.RecyclerView? by bindView(R.id.recyclerView)
internal var adapter: FAQOverviewRecyclerAdapter? = null
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
super.onCreateView(inflater, container, savedInstanceState)
return container?.inflate(R.layout.fragment_recyclerview)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
resetViews()
adapter = FAQOverviewRecyclerAdapter()
adapter?.getResetWalkthroughEvents()?.subscribe(Consumer { this.userRepository.resetTutorial(user) }, RxErrorHandler.handleEmptyError())?.let { compositeSubscription.add(it) }
adapter?.activity = activity
recyclerView?.layoutManager = androidx.recyclerview.widget.LinearLayoutManager(activity)
activity?.let { recyclerView?.addItemDecoration(androidx.recyclerview.widget.DividerItemDecoration(it, androidx.recyclerview.widget.DividerItemDecoration.VERTICAL)) }
recyclerView?.adapter = adapter
recyclerView?.itemAnimator = SafeDefaultItemAnimator()
this.loadArticles()
}
override fun onDestroy() {
faqRepository.close()
super.onDestroy()
}
override fun injectFragment(component: UserComponent) {
component.inject(this)
}
private fun loadArticles() {
if (adapter == null) {
return
}
compositeSubscription.add(faqRepository.getArticles().subscribe(Consumer { adapter?.setArticles(it) }, RxErrorHandler.handleEmptyError()))
}
}

View file

@ -0,0 +1,109 @@
package com.habitrpg.android.habitica.ui.fragments.support
import android.content.pm.PackageManager
import android.os.Build
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.app.ShareCompat
import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.components.UserComponent
import com.habitrpg.android.habitica.databinding.FragmentSupportBugFixBinding
import com.habitrpg.android.habitica.helpers.AppConfigManager
import com.habitrpg.android.habitica.helpers.AppTestingLevel
import com.habitrpg.android.habitica.helpers.DeviceName
import com.habitrpg.android.habitica.modules.AppModule
import com.habitrpg.android.habitica.ui.fragments.BaseMainFragment
import io.reactivex.Completable
import javax.inject.Inject
import javax.inject.Named
class BugFixFragment: BaseMainFragment() {
private var deviceInfo: DeviceName.DeviceInfo? = null
private lateinit var binding: FragmentSupportBugFixBinding
@field:[Inject Named(AppModule.NAMED_USER_ID)]
lateinit var userId: String
@Inject
lateinit var appConfigManager: AppConfigManager
override fun injectFragment(component: UserComponent) {
component.inject(this)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
hidesToolbar = true
super.onCreateView(inflater, container, savedInstanceState)
binding = FragmentSupportBugFixBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
compositeSubscription.add(Completable.fromAction {
deviceInfo = DeviceName.getDeviceInfo(context)
}.subscribe())
binding.reportBugButton.setOnClickListener {
sendEmail("[Android] Bugreport")
}
}
private val versionName: String by lazy {
try {
@Suppress("DEPRECATION")
activity?.packageManager?.getPackageInfo(activity?.packageName, 0)?.versionName ?: ""
} catch (e: PackageManager.NameNotFoundException) {
""
}
}
private val versionCode: Int by lazy {
try {
@Suppress("DEPRECATION")
activity?.packageManager?.getPackageInfo(activity?.packageName, 0)?.versionCode ?: 0
} catch (e: PackageManager.NameNotFoundException) {
0
}
}
private fun sendEmail(subject: String) {
val version = Build.VERSION.SDK_INT
val deviceName = deviceInfo?.name ?: DeviceName.getDeviceName()
val manufacturer = deviceInfo?.manufacturer ?: Build.MANUFACTURER
var bodyOfEmail = "Device: $manufacturer $deviceName" +
" \nAndroid Version: $version"+
" \nAppVersion: " + getString(R.string.version_info, versionName, versionCode)
if (appConfigManager.testingLevel().name != AppTestingLevel.PRODUCTION.name) {
bodyOfEmail += " ${appConfigManager.testingLevel().name}"
}
bodyOfEmail += " \nUser ID: $userId"
val user = this.user
if (user != null) {
bodyOfEmail += " \nLevel: " + (user.stats?.lvl ?: 0) +
" \nClass: " + (if (user.preferences?.disableClasses == true) "Disabled" else (user.stats?.habitClass ?: "None")) +
" \nIs in Inn: " + (user.preferences?.sleep ?: false) +
" \nUses Costume: " + (user.preferences?.costume ?: false) +
" \nCustom Day Start: " + (user.preferences?.dayStart ?: 0) +
" \nTimezone Offset: " + (user.preferences?.timezoneOffset ?: 0)
}
bodyOfEmail += " \nDetails:\n"
activity?.let {
ShareCompat.IntentBuilder.from(it)
.setType("message/rfc822")
.addEmailTo(appConfigManager.supportEmail())
.setSubject(subject)
.setText(bodyOfEmail)
.setChooserTitle("Send email...")
.startChooser()
}
}
}

View file

@ -0,0 +1,84 @@
package com.habitrpg.android.habitica.ui.fragments.support
import android.os.Bundle
import android.text.method.LinkMovementMethod
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import androidx.core.os.bundleOf
import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.components.UserComponent
import com.habitrpg.android.habitica.data.FAQRepository
import com.habitrpg.android.habitica.databinding.FragmentFaqOverviewBinding
import com.habitrpg.android.habitica.databinding.SupportFaqItemBinding
import com.habitrpg.android.habitica.extensions.addCloseButton
import com.habitrpg.android.habitica.extensions.layoutInflater
import com.habitrpg.android.habitica.helpers.MainNavigationController
import com.habitrpg.android.habitica.helpers.RxErrorHandler
import com.habitrpg.android.habitica.ui.fragments.BaseMainFragment
import com.habitrpg.android.habitica.ui.helpers.setMarkdown
import com.habitrpg.android.habitica.ui.views.HabiticaIconsHelper
import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaAlertDialog
import io.reactivex.functions.Consumer
import javax.inject.Inject
class FAQOverviewFragment : BaseMainFragment() {
private lateinit var binding: FragmentFaqOverviewBinding
@Inject
lateinit var faqRepository: FAQRepository
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
hidesToolbar = true
super.onCreateView(inflater, container, savedInstanceState)
binding = FragmentFaqOverviewBinding.inflate(inflater, container, false)
binding.healthSection.findViewById<ImageView>(R.id.icon_view).setImageBitmap(HabiticaIconsHelper.imageOfHeartLarge())
binding.experienceSection.findViewById<ImageView>(R.id.icon_view).setImageBitmap(HabiticaIconsHelper.imageOfExperienceReward())
binding.manaSection.findViewById<ImageView>(R.id.icon_view).setImageBitmap(HabiticaIconsHelper.imageOfMagicLarge())
binding.goldSection.findViewById<ImageView>(R.id.icon_view).setImageBitmap(HabiticaIconsHelper.imageOfGoldReward())
binding.gemsSection.findViewById<ImageView>(R.id.icon_view).setImageBitmap(HabiticaIconsHelper.imageOfGem())
binding.hourglassesSection.findViewById<ImageView>(R.id.icon_view).setImageBitmap(HabiticaIconsHelper.imageOfHourglassLarge())
binding.statsSection.findViewById<ImageView>(R.id.icon_view).setImageBitmap(HabiticaIconsHelper.imageOfStats())
binding.moreHelpTextView.setMarkdown(context?.getString(R.string.need_help_header_description, "[Habitica Help Guild](https://habitica.com/groups/guild/5481ccf3-5d2d-48a9-a871-70a7380cee5a)"))
binding.moreHelpTextView.setOnClickListener { MainNavigationController.navigate(R.id.guildFragment, bundleOf("groupID" to "5481ccf3-5d2d-48a9-a871-70a7380cee5a")) }
binding.moreHelpTextView.movementMethod = LinkMovementMethod.getInstance()
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
this.loadArticles()
}
override fun onDestroy() {
faqRepository.close()
super.onDestroy()
}
override fun injectFragment(component: UserComponent) {
component.inject(this)
}
private fun loadArticles() {
compositeSubscription.add(faqRepository.getArticles().subscribe(Consumer {
val context = context ?: return@Consumer
for (article in it) {
val binding = SupportFaqItemBinding.inflate(context.layoutInflater, binding.faqLinearLayout, true)
binding.textView.text = article.question
binding.root.setOnClickListener {
val dialog = HabiticaAlertDialog(binding.root.context)
dialog.setTitle(article.question)
dialog.setMessage(article.answer)
dialog.addCloseButton()
dialog.show()
}
}
}, RxErrorHandler.handleEmptyError()))
}
}

View file

@ -0,0 +1,126 @@
package com.habitrpg.android.habitica.ui.fragments.support
import android.content.pm.PackageManager
import android.os.Build
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.app.ShareCompat
import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.components.UserComponent
import com.habitrpg.android.habitica.data.FAQRepository
import com.habitrpg.android.habitica.databinding.FragmentSupportMainBinding
import com.habitrpg.android.habitica.helpers.AppConfigManager
import com.habitrpg.android.habitica.helpers.AppTestingLevel
import com.habitrpg.android.habitica.helpers.DeviceName
import com.habitrpg.android.habitica.helpers.MainNavigationController
import com.habitrpg.android.habitica.modules.AppModule
import com.habitrpg.android.habitica.ui.fragments.BaseMainFragment
import io.reactivex.Completable
import javax.inject.Inject
import javax.inject.Named
class SupportMainFragment : BaseMainFragment() {
private var deviceInfo: DeviceName.DeviceInfo? = null
private lateinit var binding: FragmentSupportMainBinding
@field:[Inject Named(AppModule.NAMED_USER_ID)]
lateinit var userId: String
@Inject
lateinit var faqRepository: FAQRepository
@Inject
lateinit var appConfigManager: AppConfigManager
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
hidesToolbar = true
super.onCreateView(inflater, container, savedInstanceState)
binding = FragmentSupportMainBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.usingHabiticaWrapper.setOnClickListener {
MainNavigationController.navigate(R.id.FAQOverviewFragment)
}
binding.bugsFixesWrapper.setOnClickListener {
MainNavigationController.navigate(R.id.bugFixFragment)
}
binding.suggestionsFeedbackWrapper.setOnClickListener {
sendEmail("[Android] Feedback")
}
compositeSubscription.add(Completable.fromAction {
deviceInfo = DeviceName.getDeviceInfo(context)
}.subscribe())
binding.resetTutorialButton.setOnClickListener {
userRepository.resetTutorial(user)
}
}
override fun onDestroy() {
faqRepository.close()
super.onDestroy()
}
override fun injectFragment(component: UserComponent) {
component.inject(this)
}
private val versionName: String by lazy {
try {
@Suppress("DEPRECATION")
activity?.packageManager?.getPackageInfo(activity?.packageName, 0)?.versionName ?: ""
} catch (e: PackageManager.NameNotFoundException) {
""
}
}
private val versionCode: Int by lazy {
try {
@Suppress("DEPRECATION")
activity?.packageManager?.getPackageInfo(activity?.packageName, 0)?.versionCode ?: 0
} catch (e: PackageManager.NameNotFoundException) {
0
}
}
private fun sendEmail(subject: String) {
val version = Build.VERSION.SDK_INT
val deviceName = deviceInfo?.name ?: DeviceName.getDeviceName()
val manufacturer = deviceInfo?.manufacturer ?: Build.MANUFACTURER
var bodyOfEmail = "Device: $manufacturer $deviceName" +
" \nAndroid Version: $version"+
" \nAppVersion: " + getString(R.string.version_info, versionName, versionCode)
if (appConfigManager.testingLevel().name != AppTestingLevel.PRODUCTION.name) {
bodyOfEmail += " ${appConfigManager.testingLevel().name}"
}
bodyOfEmail += " \nUser ID: $userId"
val user = this.user
if (user != null) {
bodyOfEmail += " \nLevel: " + (user.stats?.lvl ?: 0) +
" \nClass: " + (if (user.preferences?.disableClasses == true) "Disabled" else (user.stats?.habitClass ?: "None")) +
" \nIs in Inn: " + (user.preferences?.sleep ?: false) +
" \nUses Costume: " + (user.preferences?.costume ?: false) +
" \nCustom Day Start: " + (user.preferences?.dayStart ?: 0) +
" \nTimezone Offset: " + (user.preferences?.timezoneOffset ?: 0)
}
bodyOfEmail += " \nDetails:\n"
activity?.let {
ShareCompat.IntentBuilder.from(it)
.setType("message/rfc822")
.addEmailTo(appConfigManager.supportEmail())
.setSubject(subject)
.setText(bodyOfEmail)
.setChooserTitle("Send email...")
.startChooser()
}
}
}

View file

@ -51,6 +51,19 @@ public class HabiticaIconsHelper {
return imageOfMagic;
}
private static Bitmap imageOfMagicLarge = null;
public static Bitmap imageOfMagicLarge() {
if (imageOfMagicLarge != null)
return imageOfMagicLarge;
int size = scaleSize(36);
imageOfMagicLarge = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(imageOfMagicLarge);
HabiticaIcons.drawMagic(canvas, new RectF(0f, 0f, size, size), HabiticaIcons.ResizingBehavior.AspectFit);
return imageOfMagicLarge;
}
private static Bitmap imageOfGold = null;
public static Bitmap imageOfGold() {
if (imageOfGold != null)
@ -93,6 +106,19 @@ public class HabiticaIconsHelper {
return imageOfHourglass;
}
private static Bitmap imageOfHourglassLarge = null;
public static Bitmap imageOfHourglassLarge() {
if (imageOfHourglassLarge != null)
return imageOfHourglassLarge;
int size = scaleSize(40);
imageOfHourglassLarge = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(imageOfHourglassLarge);
HabiticaIcons.drawHourglass(canvas, new RectF(0f, 0f, size, size), HabiticaIcons.ResizingBehavior.AspectFit);
return imageOfHourglassLarge;
}
private static Bitmap imageOfExperienceReward = null;
public static Bitmap imageOfExperienceReward() {
if (imageOfExperienceReward != null)
@ -155,8 +181,7 @@ public class HabiticaIconsHelper {
int size = scaleSize(36);
imageOfHeartLarge = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(imageOfHeartLarge);
canvas.scale(displayDensity, displayDensity);
HabiticaIcons.drawHeart(canvas, false);
HabiticaIcons.drawHeart(canvas, new RectF(0f, 0f, size, size), HabiticaIcons.ResizingBehavior.AspectFit, false);
return imageOfHeartLarge;
}
@ -263,7 +288,7 @@ public class HabiticaIconsHelper {
imageOfItemIndicatorNumber = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(imageOfItemIndicatorNumber);
canvas.scale(displayDensity, displayDensity);
HabiticaIcons.drawItemIndicator(canvas, Color.parseColor("#C3C0C7"), false, false);
HabiticaIcons.drawItemIndicator(canvas, Color.parseColor("#C3C0C7"), false, false, false);
return imageOfItemIndicatorNumber;
}
@ -277,7 +302,7 @@ public class HabiticaIconsHelper {
imageOfItemIndicatorLocked = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(imageOfItemIndicatorLocked);
canvas.scale(displayDensity, displayDensity);
HabiticaIcons.drawItemIndicator(canvas, Color.parseColor("#C3C0C7"), true, false);
HabiticaIcons.drawItemIndicator(canvas, Color.parseColor("#C3C0C7"), true, false, false);
return imageOfItemIndicatorLocked;
}
@ -290,7 +315,7 @@ public class HabiticaIconsHelper {
imageOfItemIndicatorLimited = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(imageOfItemIndicatorLimited);
canvas.scale(displayDensity, displayDensity);
HabiticaIcons.drawItemIndicator(canvas, Color.parseColor("#C3C0C7"), false, true);
HabiticaIcons.drawItemIndicator(canvas, Color.parseColor("#C3C0C7"), false, true, false);
return imageOfItemIndicatorLimited;
}
@ -750,4 +775,15 @@ public class HabiticaIconsHelper {
return imageOfHabitControlMinus;
}
public static Bitmap imageOfStats() {
int width = scaleSize(30);
int height = scaleSize(30);
Bitmap imageOfHabitControlMinus = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(imageOfHabitControlMinus);
canvas.scale(displayDensity, displayDensity);
HabiticaIcons.drawStats(canvas);
return imageOfHabitControlMinus;
}
}

View file

@ -0,0 +1,52 @@
package com.habitrpg.android.habitica.ui.views
import android.content.Context
import android.util.AttributeSet
import android.view.View
import android.widget.LinearLayout
import androidx.core.content.ContextCompat
import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.databinding.SupportCollapsibleSectionBinding
import com.habitrpg.android.habitica.extensions.layoutInflater
import com.habitrpg.android.habitica.ui.helpers.MarkdownParser
class SupportCollapsibleSection : LinearLayout {
constructor(context: Context) : super(context) {
init(null, 0)
}
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
init(attrs, 0)
}
constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) {
init(attrs, defStyle)
}
private fun init(attrs: AttributeSet?, defStyle: Int) {
val binding = SupportCollapsibleSectionBinding.inflate(context.layoutInflater, this)
val a = context.obtainStyledAttributes(
attrs, R.styleable.SupportCollapsibleSection, defStyle, 0)
orientation = VERTICAL
binding.titleView.text = a.getString(R.styleable.SupportCollapsibleSection_title)
binding.subtitleView.text = a.getString(R.styleable.SupportCollapsibleSection_subtitle)
binding.descriptionView.text = MarkdownParser.parseMarkdown(a.getString(R.styleable.SupportCollapsibleSection_description))
binding.titleView.setTextColor(a.getColor(R.styleable.SupportCollapsibleSection_titleColor, ContextCompat.getColor(context, R.color.gray_50)))
background = context.getDrawable(R.drawable.layout_rounded_bg_gray_700)
a.recycle()
setOnClickListener {
binding.descriptionView.visibility = if (binding.descriptionView.visibility == View.VISIBLE){
binding.caretView.setImageResource(R.drawable.ic_keyboard_arrow_down_black_24dp)
View.GONE
} else{
binding.caretView.setImageResource(R.drawable.ic_keyboard_arrow_up_black_24dp)
View.VISIBLE
}
}
}
}

View file

@ -11,7 +11,7 @@ buildscript {
maven { url "https://plugins.gradle.org/m2/" }
}
dependencies {
classpath 'com.android.tools.build:gradle:3.6.0-rc03'
classpath 'com.android.tools.build:gradle:3.6.1'
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
classpath 'com.google.gms:google-services:4.3.3'
classpath "io.realm:realm-gradle-plugin:6.0.2"