mirror of
https://github.com/sudoxnym/habitica-android.git
synced 2026-05-20 04:39:04 +00:00
Merge branch 'version/4.3.0'
This commit is contained in:
commit
ac6223a50c
75 changed files with 835 additions and 509 deletions
|
|
@ -95,7 +95,6 @@ dependencies {
|
|||
implementation 'com.google.firebase:firebase-messaging-ktx'
|
||||
implementation 'com.google.firebase:firebase-config-ktx'
|
||||
implementation 'com.google.firebase:firebase-perf-ktx'
|
||||
implementation 'com.google.android.gms:play-services-ads:22.4.0'
|
||||
implementation "com.google.android.gms:play-services-auth:$play_auth_version"
|
||||
implementation 'com.google.android.flexbox:flexbox:3.0.0'
|
||||
implementation "com.google.android.gms:play-services-wearable:$play_wearables_version"
|
||||
|
|
@ -116,7 +115,7 @@ dependencies {
|
|||
implementation "com.google.accompanist:accompanist-systemuicontroller:$accompanist_version"
|
||||
implementation 'com.google.android.play:core:1.10.3'
|
||||
|
||||
implementation 'androidx.activity:activity-compose:1.7.2'
|
||||
implementation 'androidx.activity:activity-compose:1.8.0'
|
||||
implementation "androidx.compose.runtime:runtime-livedata:$compose_version"
|
||||
implementation "androidx.compose.material:material:$compose_version"
|
||||
implementation "androidx.compose.animation:animation:$compose_version"
|
||||
|
|
|
|||
|
|
@ -31,9 +31,6 @@
|
|||
"appinvite_service": {
|
||||
"status": 1,
|
||||
"other_platform_oauth_client": []
|
||||
},
|
||||
"ads_service": {
|
||||
"status": 2
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -62,9 +59,6 @@
|
|||
"appinvite_service": {
|
||||
"status": 1,
|
||||
"other_platform_oauth_client": []
|
||||
},
|
||||
"ads_service": {
|
||||
"status": 2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
|
||||
<solid android:color="@color/red_100" />
|
||||
<solid android:color="@color/maroon_100" />
|
||||
<corners android:radius="100dp" />
|
||||
<stroke android:width="1dp" android:color="@color/black_20_alpha" />
|
||||
</shape>
|
||||
</shape>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/confetti_container"
|
||||
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="vertical">
|
||||
|
||||
|
|
@ -35,7 +35,8 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:src="@drawable/death_ghost" />
|
||||
android:src="@drawable/death_ghost"
|
||||
android:importantForAccessibility="no" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/heart_view"
|
||||
|
|
@ -43,7 +44,8 @@
|
|||
android:layout_height="110dp"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:src="@drawable/ic_broken_heart" />
|
||||
android:src="@drawable/ic_broken_heart"
|
||||
android:importantForAccessibility="no" />
|
||||
</RelativeLayout>
|
||||
|
||||
<TextView
|
||||
|
|
@ -52,9 +54,9 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="@dimen/spacing_xlarge"
|
||||
android:gravity="center"
|
||||
android:paddingHorizontal="24dp"
|
||||
android:text="@string/you_ran_out_of_health"
|
||||
android:textStyle="bold"
|
||||
android:paddingHorizontal="24dp" />
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/loss_description"
|
||||
|
|
@ -64,9 +66,9 @@
|
|||
android:layout_marginVertical="@dimen/spacing_medium"
|
||||
android:gravity="center"
|
||||
android:lineSpacingExtra="4dp"
|
||||
android:paddingHorizontal="12dp"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="20sp"
|
||||
android:paddingHorizontal="12dp" />
|
||||
android:textSize="20sp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
|
|
@ -75,130 +77,128 @@
|
|||
android:gravity="center"
|
||||
android:text="@string/faint_broken_equipment"
|
||||
android:textColor="@color/text_secondary"
|
||||
android:textSize="16sp"/>
|
||||
android:textSize="16sp" />
|
||||
|
||||
<Space
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/restart_button"
|
||||
style="@style/HabiticaButton.Maroon"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="69dp"
|
||||
android:layout_marginHorizontal="24dp"
|
||||
android:layout_marginBottom="6dp"
|
||||
android:text="@string/faint_button"
|
||||
android:textStyle="bold"
|
||||
android:layout_marginHorizontal="24dp" />
|
||||
android:textStyle="bold" />
|
||||
|
||||
<com.habitrpg.android.habitica.ui.views.ads.AdButton
|
||||
android:id="@+id/ad_button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="60dp"
|
||||
android:layout_marginHorizontal="24dp"
|
||||
app:activeBackground="@drawable/ad_button_background_content"
|
||||
app:text="@string/watch_ad_to_hang_on"
|
||||
app:textColor="@color/text_primary"
|
||||
android:layout_marginHorizontal="24dp" />
|
||||
app:textColor="@color/text_primary" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/revive_subscriber_wrapper"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="@dimen/spacing_large">
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="65dp"
|
||||
android:paddingStart="24dp"
|
||||
android:paddingEnd="18dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_marginBottom="8dp">
|
||||
<TextView
|
||||
android:id="@+id/revive_subscriber_button"
|
||||
android:layout_marginBottom="@dimen/spacing_large"
|
||||
android:orientation="vertical">
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="60dp"
|
||||
android:text="@string/subscriber_button_faint"
|
||||
android:textStyle="bold"
|
||||
android:background="@drawable/subscriber_benefit_button_bg"
|
||||
android:gravity="center"
|
||||
android:textSize="16sp"
|
||||
android:backgroundTint="@null"
|
||||
android:textColor="@color/green_1"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:padding="0dp"/>
|
||||
android:layout_height="65dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:paddingStart="24dp"
|
||||
android:paddingEnd="18dp">
|
||||
|
||||
<androidx.compose.ui.platform.ComposeView
|
||||
android:id="@+id/revive_subscriber_button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="60dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:background="@drawable/subscriber_benefit_button_bg"
|
||||
android:backgroundTint="@null" />
|
||||
|
||||
<TextView
|
||||
style="@style/Caption2"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="top|end"
|
||||
android:background="@drawable/sub_perk_bg"
|
||||
android:paddingHorizontal="6dp"
|
||||
android:paddingVertical="4dp"
|
||||
android:text="@string/sub_perk"
|
||||
android:textColor="@color/green_500" />
|
||||
</FrameLayout>
|
||||
|
||||
<TextView
|
||||
style="@style/Body1"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/sub_perk_bg"
|
||||
android:textColor="@color/green_500"
|
||||
android:paddingHorizontal="6dp"
|
||||
android:paddingVertical="4dp"
|
||||
style="@style/Caption2"
|
||||
android:layout_gravity="top|end"
|
||||
android:text="@string/sub_perk"/>
|
||||
</FrameLayout>
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/faint_subscriber_description"
|
||||
android:layout_marginHorizontal="42dp"
|
||||
android:gravity="center"
|
||||
android:textColor="@color/text_teal"
|
||||
style="@style/Body1"
|
||||
/>
|
||||
android:text="@string/faint_subscriber_description"
|
||||
android:textColor="@color/text_teal" />
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/subscriber_benefit_used_view"
|
||||
style="@style/Body1"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="42dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginBottom="@dimen/spacing_large"
|
||||
android:gravity="center_horizontal"
|
||||
android:textColor="@color/text_teal"
|
||||
android:layout_marginHorizontal="42dp"
|
||||
tools:text="@string/subscriber_benefit_used_faint"
|
||||
style="@style/Body1"
|
||||
android:layout_marginBottom="@dimen/spacing_large"
|
||||
android:layout_marginTop="8dp"/>
|
||||
tools:text="@string/subscriber_benefit_used_faint" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/unsubbed_wrapper"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_horizontal"
|
||||
android:layout_marginTop="@dimen/spacing_large"
|
||||
android:orientation="vertical"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingBottom="12dp"
|
||||
android:paddingHorizontal="24dp"
|
||||
android:background="@drawable/subscribe_incentive_bg_topround"
|
||||
>
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="vertical"
|
||||
android:paddingHorizontal="24dp"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingBottom="12dp">
|
||||
|
||||
<Button
|
||||
android:id="@+id/subscribe_modal_button"
|
||||
style="@style/HabiticaButton.White"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="69dp"
|
||||
android:padding="0dp"
|
||||
android:text="@string/subscribe_incentive_button_faint"
|
||||
android:textStyle="bold"
|
||||
style="@style/HabiticaButton.White"
|
||||
android:textColor="@color/teal_10"
|
||||
android:padding="0dp"/>
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
style="@style/Body1"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:layout_marginTop="3dp"
|
||||
android:gravity="center_horizontal"
|
||||
android:text="@string/subscribe_incentive_text_faint"
|
||||
android:textColor="@color/teal_1"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
style="@style/Body1"
|
||||
android:layout_marginTop="3dp"/>
|
||||
android:textColor="@color/teal_1" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/snackbar_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="400dp"
|
||||
android:layout_gravity="bottom"
|
||||
android:paddingBottom="20dp"/>
|
||||
android:paddingBottom="20dp" />
|
||||
</FrameLayout>
|
||||
|
|
|
|||
|
|
@ -39,15 +39,73 @@
|
|||
<androidx.core.widget.NestedScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/notification_items"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:divider="?android:listDivider"
|
||||
android:visibility="invisible"
|
||||
android:orientation="vertical"
|
||||
android:showDividers="middle" />
|
||||
android:orientation="vertical">
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingTop="10dp"
|
||||
android:paddingEnd="10dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_weight="1"
|
||||
android:orientation="horizontal"
|
||||
android:paddingTop="@dimen/spacing_medium">
|
||||
|
||||
<TextView
|
||||
android:id="@android:id/title"
|
||||
style="@style/Body1"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dip"
|
||||
android:background="@color/transparent"
|
||||
android:text="@string/notifications"
|
||||
android:textAllCaps="true"
|
||||
android:textColor="@color/text_quad"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/notifications_title_badge"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="24dp"
|
||||
android:layout_marginStart="10dp"
|
||||
android:background="@drawable/badge_gray"
|
||||
android:gravity="center"
|
||||
android:minWidth="24dp"
|
||||
android:textColor="@color/text_quad"
|
||||
android:textSize="12sp"
|
||||
tools:text="1" />
|
||||
</LinearLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/dismiss_all_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/transparent"
|
||||
android:text="@string/dismiss_all"
|
||||
android:textColor="@color/text_brand" />
|
||||
</LinearLayout>
|
||||
<androidx.compose.ui.platform.ComposeView
|
||||
android:id="@+id/progress_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"/>
|
||||
<LinearLayout
|
||||
android:id="@+id/notification_items"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:divider="?android:listDivider"
|
||||
android:visibility="invisible"
|
||||
android:orientation="vertical"
|
||||
android:showDividers="middle" />
|
||||
</LinearLayout>
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||
</FrameLayout>
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
android:layout_height="match_parent"
|
||||
android:paddingTop="4dp"
|
||||
android:paddingBottom="4dp"
|
||||
android:gravity="center_vertical|right">
|
||||
android:gravity="center_vertical|end">
|
||||
<ImageView
|
||||
android:id="@+id/classIconView"
|
||||
android:layout_width="32dp"
|
||||
|
|
@ -15,4 +15,4 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="16sp"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
|
|
|||
|
|
@ -9,10 +9,11 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="12dp"
|
||||
android:scaleType="center" />
|
||||
android:scaleType="center"
|
||||
android:importantForAccessibility="no" />
|
||||
<TextView
|
||||
android:id="@+id/textView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_horizontal"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
|
|
|||
|
|
@ -24,7 +24,8 @@
|
|||
android:layout_height="3dp"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_margin="@dimen/spacing_large"
|
||||
android:src="@color/offset_background" />
|
||||
android:src="@color/offset_background"
|
||||
android:importantForAccessibility="no" />
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/subscriber_benefit_banner"
|
||||
|
|
@ -51,7 +52,8 @@
|
|||
android:layout_alignParentTop="true"
|
||||
android:layout_alignParentBottom="false"
|
||||
android:scaleType="centerCrop"
|
||||
android:src="@drawable/subscription_banner_image_left" />
|
||||
android:src="@drawable/subscription_banner_image_left"
|
||||
android:importantForAccessibility="no" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/banner_right_image"
|
||||
|
|
@ -60,7 +62,8 @@
|
|||
android:layout_alignParentTop="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:scaleType="centerCrop"
|
||||
android:src="@drawable/subscription_banner_image_right" />
|
||||
android:src="@drawable/subscription_banner_image_right"
|
||||
android:importantForAccessibility="no" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
|
|
@ -83,7 +86,8 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="sans-serif-medium"
|
||||
android:text="SUBSCRIBER BENEFIT"
|
||||
android:text="@string/subscriber_benefit"
|
||||
android:textAllCaps="true"
|
||||
android:textColor="@color/white" />
|
||||
</LinearLayout>
|
||||
</RelativeLayout>
|
||||
|
|
@ -116,7 +120,8 @@
|
|||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginTop="20dp"
|
||||
android:layout_marginBottom="20dp"
|
||||
android:src="@drawable/separator_fancy" />
|
||||
android:src="@drawable/separator_fancy"
|
||||
android:importantForAccessibility="no" />
|
||||
|
||||
|
||||
<com.habitrpg.android.habitica.ui.views.subscriptions.SubscriberBenefitView
|
||||
|
|
@ -130,7 +135,8 @@
|
|||
android:layout_gravity="center"
|
||||
android:layout_marginTop="20dp"
|
||||
android:layout_marginBottom="12dp"
|
||||
android:src="@drawable/separator_fancy" />
|
||||
android:src="@drawable/separator_fancy"
|
||||
android:importantForAccessibility="no" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/loadingIndicator"
|
||||
|
|
@ -155,7 +161,6 @@
|
|||
android:id="@+id/subscription3month"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:flagText="@string/save_20"
|
||||
app:gemCapText="@string/subscribe3month_gemcap"
|
||||
app:hourGlassCount="1"
|
||||
app:recurringText="@string/three_months" />
|
||||
|
|
|
|||
|
|
@ -72,7 +72,8 @@
|
|||
android:layout_weight="1"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingStart="@dimen/spacing_medium">
|
||||
android:paddingStart="@dimen/spacing_medium"
|
||||
android:paddingEnd="0dp">
|
||||
<TextView
|
||||
android:id="@+id/quest_title_view"
|
||||
android:layout_width="match_parent"
|
||||
|
|
@ -92,7 +93,8 @@
|
|||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:srcCompat="@drawable/ic_keyboard_arrow_right_gray_24dp"/>
|
||||
app:srcCompat="@drawable/ic_keyboard_arrow_right_gray_24dp"
|
||||
android:importantForAccessibility="no" />
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:visibility="gone"
|
||||
|
|
|
|||
|
|
@ -25,14 +25,16 @@
|
|||
android:scaleType="center"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_alignParentBottom="false"/>
|
||||
android:layout_alignParentBottom="false"
|
||||
android:importantForAccessibility="no" />
|
||||
<ImageView
|
||||
android:id="@+id/promo_banner_right_image"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:scaleType="center"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_alignParentEnd="true"/>
|
||||
android:layout_alignParentEnd="true"
|
||||
android:importantForAccessibility="no" />
|
||||
<LinearLayout
|
||||
android:layout_centerInParent="true"
|
||||
android:layout_width="wrap_content"
|
||||
|
|
@ -135,4 +137,4 @@
|
|||
tools:text="This is some text"
|
||||
android:lineSpacingExtra="3dp"/>
|
||||
</LinearLayout>
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
|
|
|
|||
|
|
@ -18,7 +18,8 @@
|
|||
android:layout_height="3dp"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_margin="@dimen/spacing_large"
|
||||
android:src="@color/offset_background" />
|
||||
android:src="@color/offset_background"
|
||||
android:importantForAccessibility="no" />
|
||||
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
|
|
@ -172,4 +173,4 @@
|
|||
</LinearLayout>
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
</LinearLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
|
|
|||
|
|
@ -23,7 +23,8 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/creator_hills_bg"
|
||||
android:layout_centerInParent="true" />
|
||||
android:layout_centerInParent="true"
|
||||
android:importantForAccessibility="no" />
|
||||
<com.habitrpg.common.habitica.views.AvatarView
|
||||
android:id="@+id/avatarView"
|
||||
android:layout_width="@dimen/avatar_small_width"
|
||||
|
|
@ -56,4 +57,4 @@
|
|||
android:layout_height="wrap_content"
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
|
||||
android:layout_width="0dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical"
|
||||
android:paddingStart="@dimen/spacing_medium"
|
||||
android:paddingTop="44dp"
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@
|
|||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="@dimen/spacing_medium"
|
||||
android:layout_marginEnd="3dp"
|
||||
android:layout_marginStart="@dimen/spacing_large"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginBottom="8dp">
|
||||
|
|
@ -47,12 +47,14 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="24dp"
|
||||
android:src="@drawable/flag_flap"
|
||||
android:layout_gravity="center_vertical" />
|
||||
android:layout_gravity="center_vertical"
|
||||
android:importantForAccessibility="no" />
|
||||
<TextView
|
||||
android:id="@+id/flag_textview"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="24dp"
|
||||
android:paddingEnd="@dimen/spacing_medium"
|
||||
android:paddingStart="0dp"
|
||||
android:background="@color/green_50"
|
||||
android:textColor="@color/white"
|
||||
style="@style/Caption2"
|
||||
|
|
@ -89,4 +91,4 @@
|
|||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
|
|
|||
|
|
@ -38,8 +38,7 @@
|
|||
android:layout_height="wrap_content"
|
||||
tools:text="This is the Title"
|
||||
android:gravity="center"
|
||||
style="@style/Title2"
|
||||
android:textSize="18sp"
|
||||
android:textSize="16sp"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible"
|
||||
android:textColor="@color/white"/>
|
||||
|
|
@ -49,8 +48,7 @@
|
|||
android:layout_height="wrap_content"
|
||||
tools:text="This is the Content"
|
||||
android:gravity="center"
|
||||
style="@style/Body1"
|
||||
android:textSize="13sp"
|
||||
android:textSize="14sp"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible"
|
||||
android:textColor="@color/white"/>
|
||||
|
|
|
|||
|
|
@ -1467,6 +1467,7 @@
|
|||
<string name="revive_broken_equipment">Your %s broke</string>
|
||||
<string name="subscribe_gems_for_gold_incentive_text">Subscribe to buy Gems with Gold and receive these other exclusive benefits!</string>
|
||||
<string name="subscribe_hourglass_incentive_text">Subscribers get Mystic Hourglasses to buy items in the Time Travelers Shop and these other exclusive benefits!</string>
|
||||
<string name="subscriber_benefit">SUBSCRIBER BENEFIT</string>
|
||||
|
||||
|
||||
<plurals name="you_x_others">
|
||||
|
|
|
|||
|
|
@ -114,7 +114,10 @@ class ApiClientImpl(
|
|||
|
||||
val calendar = GregorianCalendar()
|
||||
val timeZone = calendar.timeZone
|
||||
val timezoneOffset = -TimeUnit.MINUTES.convert(timeZone.getOffset(calendar.timeInMillis).toLong(), TimeUnit.MILLISECONDS)
|
||||
val timezoneOffset = -TimeUnit.MINUTES.convert(
|
||||
timeZone.getOffset(calendar.timeInMillis).toLong(),
|
||||
TimeUnit.MILLISECONDS
|
||||
)
|
||||
|
||||
val cacheSize: Long = 10 * 1024 * 1024 // 10 MB
|
||||
|
||||
|
|
@ -157,7 +160,8 @@ class ApiClientImpl(
|
|||
}
|
||||
|
||||
else -> {
|
||||
return@addNetworkInterceptor response.newBuilder().header("Cache-Control", "no-store").build()
|
||||
return@addNetworkInterceptor response.newBuilder()
|
||||
.header("Cache-Control", "no-store").build()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
@ -208,7 +212,11 @@ class ApiClientImpl(
|
|||
return process { this.apiService.connectLocal(auth) }
|
||||
}
|
||||
|
||||
override suspend fun connectSocial(network: String, userId: String, accessToken: String): UserAuthResponse? {
|
||||
override suspend fun connectSocial(
|
||||
network: String,
|
||||
userId: String,
|
||||
accessToken: String
|
||||
): UserAuthResponse? {
|
||||
val auth = UserAuthSocial()
|
||||
auth.network = network
|
||||
val authResponse = UserAuthSocialTokens()
|
||||
|
|
@ -232,34 +240,51 @@ class ApiClientImpl(
|
|||
if (SocketTimeoutException::class.java.isAssignableFrom(throwableClass)) {
|
||||
return
|
||||
}
|
||||
|
||||
var isUserInputCall = false
|
||||
@Suppress("DEPRECATION")
|
||||
if (SocketException::class.java.isAssignableFrom(throwableClass) || SSLException::class.java.isAssignableFrom(throwableClass)) {
|
||||
this.showConnectionProblemDialog(R.string.internal_error_api)
|
||||
if (SocketException::class.java.isAssignableFrom(throwableClass)
|
||||
|| SSLException::class.java.isAssignableFrom(throwableClass)
|
||||
) {
|
||||
this.showConnectionProblemDialog(R.string.internal_error_api, isUserInputCall)
|
||||
} else if (throwableClass == SocketTimeoutException::class.java || UnknownHostException::class.java == throwableClass || IOException::class.java == throwableClass) {
|
||||
this.showConnectionProblemDialog(R.string.network_error_no_network_body)
|
||||
this.showConnectionProblemDialog(
|
||||
R.string.network_error_no_network_body,
|
||||
isUserInputCall
|
||||
)
|
||||
} else if (HttpException::class.java.isAssignableFrom(throwable.javaClass)) {
|
||||
val error = throwable as HttpException
|
||||
val res = getErrorResponse(error)
|
||||
val status = error.code()
|
||||
val requestUrl = error.response()?.raw()?.request?.url
|
||||
val path = requestUrl?.encodedPath?.removePrefix("/api/v4") ?: ""
|
||||
isUserInputCall = when {
|
||||
path.startsWith("/groups") && path.endsWith("invite") -> true
|
||||
else -> false
|
||||
}
|
||||
|
||||
if (res.message != null && res.message == "RECEIPT_ALREADY_USED") {
|
||||
return
|
||||
}
|
||||
if (error.response()?.raw()?.request?.url?.toString()?.endsWith("/user/push-devices") == true) {
|
||||
if (requestUrl?.toString()?.endsWith("/user/push-devices") == true) {
|
||||
// workaround for an error that sometimes displays that the user already has this push device
|
||||
return
|
||||
}
|
||||
|
||||
if (status in 400..499) {
|
||||
if (res.displayMessage.isNotEmpty()) {
|
||||
showConnectionProblemDialog("", res.displayMessage)
|
||||
showConnectionProblemDialog("", res.displayMessage, isUserInputCall)
|
||||
} else if (status == 401) {
|
||||
showConnectionProblemDialog(R.string.authentication_error_title, R.string.authentication_error_body)
|
||||
showConnectionProblemDialog(
|
||||
R.string.authentication_error_title,
|
||||
R.string.authentication_error_body,
|
||||
isUserInputCall
|
||||
)
|
||||
}
|
||||
} else if (status in 500..599) {
|
||||
this.showConnectionProblemDialog(R.string.internal_error_api)
|
||||
this.showConnectionProblemDialog(R.string.internal_error_api, isUserInputCall)
|
||||
} else {
|
||||
showConnectionProblemDialog(R.string.internal_error_api)
|
||||
showConnectionProblemDialog(R.string.internal_error_api, isUserInputCall)
|
||||
}
|
||||
} else if (JsonSyntaxException::class.java.isAssignableFrom(throwableClass)) {
|
||||
Analytics.logError("Json Error: " + lastAPICallURL + ", " + throwable.message)
|
||||
|
|
@ -268,7 +293,10 @@ class ApiClientImpl(
|
|||
}
|
||||
}
|
||||
|
||||
override suspend fun updateMember(memberID: String, updateData: Map<String, Map<String, Boolean>>): Member? {
|
||||
override suspend fun updateMember(
|
||||
memberID: String,
|
||||
updateData: Map<String, Map<String, Boolean>>
|
||||
): Member? {
|
||||
return process { apiService.updateUser(memberID, updateData) }
|
||||
}
|
||||
|
||||
|
|
@ -303,24 +331,41 @@ class ApiClientImpl(
|
|||
return this.hostConfig.userID.isNotEmpty() && hostConfig.apiKey.isNotEmpty()
|
||||
}
|
||||
|
||||
private fun showConnectionProblemDialog(resourceMessageString: Int) {
|
||||
showConnectionProblemDialog(null, context.getString(resourceMessageString))
|
||||
private fun showConnectionProblemDialog(
|
||||
resourceMessageString: Int,
|
||||
isFromUserInput: Boolean
|
||||
) {
|
||||
showConnectionProblemDialog(null, context.getString(resourceMessageString), isFromUserInput)
|
||||
}
|
||||
|
||||
private fun showConnectionProblemDialog(resourceTitleString: Int, resourceMessageString: Int) {
|
||||
showConnectionProblemDialog(context.getString(resourceTitleString), context.getString(resourceMessageString))
|
||||
private fun showConnectionProblemDialog(
|
||||
resourceTitleString: Int,
|
||||
resourceMessageString: Int,
|
||||
isFromUserInput: Boolean
|
||||
) {
|
||||
showConnectionProblemDialog(
|
||||
context.getString(resourceTitleString),
|
||||
context.getString(resourceMessageString),
|
||||
isFromUserInput
|
||||
)
|
||||
}
|
||||
|
||||
private var erroredRequestCount = 0
|
||||
private fun showConnectionProblemDialog(
|
||||
resourceTitleString: String?,
|
||||
resourceMessageString: String
|
||||
resourceMessageString: String,
|
||||
isFromUserInput: Boolean
|
||||
) {
|
||||
erroredRequestCount += 1
|
||||
val application = (context as? HabiticaBaseApplication)
|
||||
?: (context.applicationContext as? HabiticaBaseApplication)
|
||||
application?.currentActivity?.get()
|
||||
?.showConnectionProblem(erroredRequestCount, resourceTitleString, resourceMessageString)
|
||||
?.showConnectionProblem(
|
||||
erroredRequestCount,
|
||||
resourceTitleString,
|
||||
resourceMessageString,
|
||||
isFromUserInput
|
||||
)
|
||||
}
|
||||
|
||||
private fun hideConnectionProblemDialog() {
|
||||
|
|
@ -378,7 +423,13 @@ class ApiClientImpl(
|
|||
}
|
||||
|
||||
override suspend fun purchaseItem(type: String, itemKey: String, purchaseQuantity: Int): Void? {
|
||||
return process { apiService.purchaseItem(type, itemKey, mapOf(Pair("quantity", purchaseQuantity))) }
|
||||
return process {
|
||||
apiService.purchaseItem(
|
||||
type,
|
||||
itemKey,
|
||||
mapOf(Pair("quantity", purchaseQuantity))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val lastSubscribeCall: Date? = null
|
||||
|
|
@ -506,7 +557,11 @@ class ApiClientImpl(
|
|||
|
||||
override suspend fun revive(): Items? = process { apiService.revive() }
|
||||
|
||||
override suspend fun useSkill(skillName: String, targetType: String, targetId: String): SkillResponse? {
|
||||
override suspend fun useSkill(
|
||||
skillName: String,
|
||||
targetType: String,
|
||||
targetId: String
|
||||
): SkillResponse? {
|
||||
return process { apiService.useSkill(skillName, targetType, targetId) }
|
||||
}
|
||||
|
||||
|
|
@ -562,22 +617,33 @@ class ApiClientImpl(
|
|||
return processResponse(apiService.leaveGroup(groupId, keepChallenges))
|
||||
}
|
||||
|
||||
override suspend fun postGroupChat(groupId: String, message: Map<String, String>): PostChatMessageResult? {
|
||||
override suspend fun postGroupChat(
|
||||
groupId: String,
|
||||
message: Map<String, String>
|
||||
): PostChatMessageResult? {
|
||||
return process { apiService.postGroupChat(groupId, message) }
|
||||
}
|
||||
|
||||
override suspend fun deleteMessage(groupId: String, messageId: String): Void? {
|
||||
return process { apiService.deleteMessage(groupId, messageId) }
|
||||
}
|
||||
|
||||
override suspend fun deleteInboxMessage(id: String): Void? {
|
||||
return process { apiService.deleteInboxMessage(id) }
|
||||
}
|
||||
|
||||
override suspend fun getGroupMembers(groupId: String, includeAllPublicFields: Boolean?): List<Member>? {
|
||||
override suspend fun getGroupMembers(
|
||||
groupId: String,
|
||||
includeAllPublicFields: Boolean?
|
||||
): List<Member>? {
|
||||
return processResponse(apiService.getGroupMembers(groupId, includeAllPublicFields))
|
||||
}
|
||||
|
||||
override suspend fun getGroupMembers(groupId: String, includeAllPublicFields: Boolean?, lastId: String): List<Member>? {
|
||||
override suspend fun getGroupMembers(
|
||||
groupId: String,
|
||||
includeAllPublicFields: Boolean?,
|
||||
lastId: String
|
||||
): List<Member>? {
|
||||
return processResponse(apiService.getGroupMembers(groupId, includeAllPublicFields, lastId))
|
||||
}
|
||||
|
||||
|
|
@ -589,7 +655,11 @@ class ApiClientImpl(
|
|||
return process { apiService.reportMember(mid, data) }
|
||||
}
|
||||
|
||||
override suspend fun flagMessage(groupId: String, mid: String, data: MutableMap<String, String>): Void? {
|
||||
override suspend fun flagMessage(
|
||||
groupId: String,
|
||||
mid: String,
|
||||
data: MutableMap<String, String>
|
||||
): Void? {
|
||||
return process { apiService.flagMessage(groupId, mid, data) }
|
||||
}
|
||||
|
||||
|
|
@ -601,7 +671,10 @@ class ApiClientImpl(
|
|||
return process { apiService.seenMessages(groupId) }
|
||||
}
|
||||
|
||||
override suspend fun inviteToGroup(groupId: String, inviteData: Map<String, Any>): List<InviteResponse>? {
|
||||
override suspend fun inviteToGroup(
|
||||
groupId: String,
|
||||
inviteData: Map<String, Any>
|
||||
): List<InviteResponse>? {
|
||||
return process { apiService.inviteToGroup(groupId, inviteData) }
|
||||
}
|
||||
|
||||
|
|
@ -609,7 +682,10 @@ class ApiClientImpl(
|
|||
return process { apiService.rejectGroupInvite(groupId) }
|
||||
}
|
||||
|
||||
override suspend fun getGroupInvites(groupId: String, includeAllPublicFields: Boolean?): List<Member>? {
|
||||
override suspend fun getGroupInvites(
|
||||
groupId: String,
|
||||
includeAllPublicFields: Boolean?
|
||||
): List<Member>? {
|
||||
return process { apiService.getGroupInvites(groupId, includeAllPublicFields) }
|
||||
}
|
||||
|
||||
|
|
@ -663,14 +739,21 @@ class ApiClientImpl(
|
|||
return process { apiService.retrievePartySeekingUsers(page) }
|
||||
}
|
||||
|
||||
override suspend fun getMember(memberId: String) = processResponse(apiService.getMember(memberId))
|
||||
override suspend fun getMemberWithUsername(username: String) = processResponse(apiService.getMemberWithUsername(username))
|
||||
override suspend fun getMember(memberId: String) =
|
||||
processResponse(apiService.getMember(memberId))
|
||||
|
||||
override suspend fun getMemberWithUsername(username: String) =
|
||||
processResponse(apiService.getMemberWithUsername(username))
|
||||
|
||||
override suspend fun getMemberAchievements(memberId: String): List<Achievement>? {
|
||||
return process { apiService.getMemberAchievements(memberId, languageCode) }
|
||||
}
|
||||
|
||||
override suspend fun findUsernames(username: String, context: String?, id: String?): List<FindUsernameResult>? {
|
||||
override suspend fun findUsernames(
|
||||
username: String,
|
||||
context: String?,
|
||||
id: String?
|
||||
): List<FindUsernameResult>? {
|
||||
return process { apiService.findUsernames(username, context, id) }
|
||||
}
|
||||
|
||||
|
|
@ -829,7 +912,14 @@ class ApiClientImpl(
|
|||
}
|
||||
|
||||
override suspend fun transferGems(giftedID: String, amount: Int): Void? {
|
||||
return process { apiService.transferGems(mapOf(Pair("toUserId", giftedID), Pair("gemAmount", amount))) }
|
||||
return process {
|
||||
apiService.transferGems(
|
||||
mapOf(
|
||||
Pair("toUserId", giftedID),
|
||||
Pair("gemAmount", amount)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getTeamPlans(): List<TeamPlan>? {
|
||||
|
|
|
|||
|
|
@ -7,14 +7,14 @@ import android.provider.Settings
|
|||
import android.util.Log
|
||||
import androidx.core.content.edit
|
||||
import androidx.core.os.bundleOf
|
||||
import com.google.android.gms.ads.AdRequest
|
||||
/*import com.google.android.gms.ads.AdRequest
|
||||
import com.google.android.gms.ads.LoadAdError
|
||||
import com.google.android.gms.ads.MobileAds
|
||||
import com.google.android.gms.ads.OnUserEarnedRewardListener
|
||||
import com.google.android.gms.ads.RequestConfiguration
|
||||
import com.google.android.gms.ads.rewarded.RewardItem
|
||||
import com.google.android.gms.ads.rewarded.RewardedAd
|
||||
import com.google.android.gms.ads.rewarded.RewardedAdLoadCallback
|
||||
import com.google.android.gms.ads.rewarded.RewardedAdLoadCallback*/
|
||||
import com.google.firebase.analytics.FirebaseAnalytics
|
||||
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
||||
import com.habitrpg.android.habitica.BuildConfig
|
||||
|
|
@ -63,8 +63,8 @@ fun String.md5(): String? {
|
|||
}
|
||||
}
|
||||
|
||||
class AdHandler(val activity: Activity, val type: AdType, val rewardAction: (Boolean) -> Unit) : OnUserEarnedRewardListener {
|
||||
private var rewardedAd: RewardedAd? = null
|
||||
class AdHandler(val activity: Activity, val type: AdType, val rewardAction: (Boolean) -> Unit) {
|
||||
//private var rewardedAd: RewardedAd? = null
|
||||
|
||||
companion object {
|
||||
private enum class AdStatus {
|
||||
|
|
@ -111,16 +111,16 @@ class AdHandler(val activity: Activity, val type: AdType, val rewardAction: (Boo
|
|||
val android_id: String =
|
||||
Settings.Secure.getString(context.contentResolver, Settings.Secure.ANDROID_ID)
|
||||
val deviceId: String = android_id.md5()?.uppercase() ?: ""
|
||||
val configuration = RequestConfiguration.Builder().setTestDeviceIds(listOf(deviceId)).build()
|
||||
MobileAds.setRequestConfiguration(configuration)
|
||||
//val configuration = RequestConfiguration.Builder().setTestDeviceIds(listOf(deviceId)).build()
|
||||
//MobileAds.setRequestConfiguration(configuration)
|
||||
}
|
||||
|
||||
currentAdStatus = AdStatus.INITIALIZING
|
||||
MobileAds.initialize(context) {
|
||||
/*MobileAds.initialize(context) {
|
||||
currentAdStatus = AdStatus.READY
|
||||
onComplete()
|
||||
FirebaseCrashlytics.getInstance().recordException(Throwable("Ads Initialized"))
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
fun whenAdsInitialized(context: Context, onComplete: () -> Unit) {
|
||||
|
|
@ -156,7 +156,7 @@ class AdHandler(val activity: Activity, val type: AdType, val rewardAction: (Boo
|
|||
|
||||
fun prepare(onComplete: ((Boolean) -> Unit)? = null) {
|
||||
whenAdsInitialized(activity) {
|
||||
val adRequest = AdRequest.Builder()
|
||||
/*val adRequest = AdRequest.Builder()
|
||||
.build()
|
||||
|
||||
if (BuildConfig.DEBUG || BuildConfig.TESTING_LEVEL == "staff" || BuildConfig.TESTING_LEVEL == "alpha") {
|
||||
|
|
@ -184,7 +184,7 @@ class AdHandler(val activity: Activity, val type: AdType, val rewardAction: (Boo
|
|||
onComplete?.invoke(true)
|
||||
}
|
||||
}
|
||||
)
|
||||
)*/
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -209,22 +209,22 @@ class AdHandler(val activity: Activity, val type: AdType, val rewardAction: (Boo
|
|||
}
|
||||
|
||||
private fun configureReward() {
|
||||
rewardedAd?.run { }
|
||||
//rewardedAd?.run { }
|
||||
}
|
||||
|
||||
private fun showRewardedAd() {
|
||||
if (nextAdAllowedDate(type)?.after(Date()) == true) {
|
||||
return
|
||||
}
|
||||
if (rewardedAd != null) {
|
||||
/*if (rewardedAd != null) {
|
||||
rewardedAd?.show(activity, this)
|
||||
setNextAllowedDate(type)
|
||||
} else {
|
||||
Log.d(TAG, "The rewarded ad wasn't ready yet.")
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
override fun onUserEarnedReward(rewardItem: RewardItem) {
|
||||
/*override fun onUserEarnedReward(rewardItem: RewardItem) {
|
||||
Analytics.sendEvent(
|
||||
"adRewardEarned",
|
||||
EventCategory.BEHAVIOUR,
|
||||
|
|
@ -240,5 +240,5 @@ class AdHandler(val activity: Activity, val type: AdType, val rewardAction: (Boo
|
|||
)
|
||||
)
|
||||
rewardAction(true)
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import com.habitrpg.android.habitica.databinding.MountImageviewBinding
|
|||
import com.habitrpg.android.habitica.models.inventory.Food
|
||||
import com.habitrpg.android.habitica.models.inventory.Pet
|
||||
import com.habitrpg.android.habitica.ui.activities.BaseActivity
|
||||
import com.habitrpg.android.habitica.ui.theme.HabiticaTheme
|
||||
import com.habitrpg.common.habitica.theme.HabiticaTheme
|
||||
import com.habitrpg.android.habitica.ui.views.BackgroundScene
|
||||
import com.habitrpg.android.habitica.ui.views.SnackbarActivity
|
||||
import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaAlertDialog
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import com.habitrpg.android.habitica.databinding.PetImageviewBinding
|
|||
import com.habitrpg.android.habitica.models.inventory.Egg
|
||||
import com.habitrpg.android.habitica.models.inventory.HatchingPotion
|
||||
import com.habitrpg.android.habitica.models.user.Items
|
||||
import com.habitrpg.android.habitica.ui.theme.HabiticaTheme
|
||||
import com.habitrpg.common.habitica.theme.HabiticaTheme
|
||||
import com.habitrpg.android.habitica.ui.views.BackgroundScene
|
||||
import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaAlertDialog
|
||||
import com.habitrpg.common.habitica.extensions.layoutInflater
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import androidx.savedstate.setViewTreeSavedStateRegistryOwner
|
|||
import com.habitrpg.android.habitica.HabiticaBaseApplication
|
||||
import com.habitrpg.android.habitica.databinding.MountImageviewBinding
|
||||
import com.habitrpg.android.habitica.ui.activities.BaseActivity
|
||||
import com.habitrpg.android.habitica.ui.theme.HabiticaTheme
|
||||
import com.habitrpg.common.habitica.theme.HabiticaTheme
|
||||
import com.habitrpg.android.habitica.ui.views.BackgroundScene
|
||||
import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaAlertDialog
|
||||
import com.habitrpg.common.habitica.extensions.dpToPx
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ import com.habitrpg.android.habitica.databinding.PetImageviewBinding
|
|||
import com.habitrpg.android.habitica.models.inventory.Food
|
||||
import com.habitrpg.android.habitica.models.inventory.Pet
|
||||
import com.habitrpg.android.habitica.ui.activities.BaseActivity
|
||||
import com.habitrpg.android.habitica.ui.theme.HabiticaTheme
|
||||
import com.habitrpg.common.habitica.theme.HabiticaTheme
|
||||
import com.habitrpg.android.habitica.ui.views.BackgroundScene
|
||||
import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaAlertDialog
|
||||
import com.habitrpg.common.habitica.extensions.dpToPx
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ import android.widget.FrameLayout
|
|||
import android.widget.RelativeLayout
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.habitrpg.android.habitica.R
|
||||
import com.habitrpg.android.habitica.data.InventoryRepository
|
||||
|
|
@ -24,16 +23,14 @@ import com.habitrpg.android.habitica.helpers.HitType
|
|||
import com.habitrpg.android.habitica.helpers.ReviewManager
|
||||
import com.habitrpg.android.habitica.ui.fragments.purchases.EventOutcomeSubscriptionBottomSheetFragment
|
||||
import com.habitrpg.android.habitica.ui.fragments.purchases.EventOutcomeSubscriptionBottomSheetFragment.Companion.EVENT_ARMOIRE_OPENED
|
||||
import com.habitrpg.android.habitica.ui.fragments.purchases.SubscriptionBottomSheetFragment
|
||||
import com.habitrpg.android.habitica.ui.viewmodels.MainUserViewModel
|
||||
import com.habitrpg.android.habitica.ui.views.ads.AdButton
|
||||
import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaBottomSheetDialog
|
||||
import com.habitrpg.android.habitica.ui.views.progress.HabiticaCircularProgressView
|
||||
import com.habitrpg.common.habitica.views.HabiticaCircularProgressView
|
||||
import com.habitrpg.common.habitica.extensions.dpToPx
|
||||
import com.habitrpg.common.habitica.extensions.loadImage
|
||||
import com.habitrpg.common.habitica.helpers.Animations
|
||||
import com.habitrpg.common.habitica.helpers.ExceptionHandler
|
||||
import com.habitrpg.common.habitica.helpers.MainNavigationController
|
||||
import com.habitrpg.common.habitica.helpers.launchCatching
|
||||
import com.plattysoft.leonids.ParticleSystem
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
|
|
|
|||
|
|
@ -223,7 +223,7 @@ abstract class BaseActivity : AppCompatActivity() {
|
|||
}
|
||||
}
|
||||
|
||||
open fun showConnectionProblem(errorCount: Int, title: String?, message: String) {
|
||||
open fun showConnectionProblem(errorCount: Int, title: String?, message: String, isFromUserInput: Boolean) {
|
||||
val alert = HabiticaAlertDialog(this)
|
||||
alert.setTitle(title)
|
||||
alert.setMessage(message)
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ import com.habitrpg.android.habitica.helpers.EventCategory
|
|||
import com.habitrpg.android.habitica.helpers.HitType
|
||||
import com.habitrpg.common.habitica.helpers.MainNavigationController
|
||||
import com.habitrpg.android.habitica.helpers.PurchaseHandler
|
||||
import com.habitrpg.android.habitica.ui.theme.HabiticaTheme
|
||||
import com.habitrpg.common.habitica.theme.HabiticaTheme
|
||||
import com.habitrpg.android.habitica.ui.viewmodels.MainUserViewModel
|
||||
import com.habitrpg.android.habitica.ui.views.CurrencyText
|
||||
import com.habitrpg.android.habitica.ui.views.HabiticaButton
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
package com.habitrpg.android.habitica.ui.activities
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.drawable.BitmapDrawable
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.os.Bundle
|
||||
|
|
|
|||
|
|
@ -6,6 +6,25 @@ import android.os.Bundle
|
|||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.animation.AccelerateInterpolator
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.core.content.edit
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.habitrpg.android.habitica.HabiticaApplication
|
||||
|
|
@ -32,6 +51,8 @@ import com.habitrpg.common.habitica.extensions.fromHtml
|
|||
import com.habitrpg.common.habitica.helpers.Animations
|
||||
import com.habitrpg.common.habitica.helpers.ExceptionHandler
|
||||
import com.habitrpg.common.habitica.helpers.launchCatching
|
||||
import com.habitrpg.common.habitica.theme.HabiticaTheme
|
||||
import com.habitrpg.common.habitica.views.HabiticaCircularProgressView
|
||||
import com.plattysoft.leonids.ParticleSystem
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import kotlinx.coroutines.MainScope
|
||||
|
|
@ -138,30 +159,59 @@ class DeathActivity : BaseActivity(), SnackbarActivity {
|
|||
binding.subscriberBenefitUsedView.visibility = View.GONE
|
||||
}
|
||||
|
||||
binding.reviveSubscriberButton.setOnClickListener {
|
||||
Analytics.sendEvent("second chance perk", EventCategory.BEHAVIOUR, HitType.EVENT)
|
||||
sharedPreferences.edit {
|
||||
putLong("last_sub_revive", Date().time)
|
||||
}
|
||||
lifecycleScope.launchCatching {
|
||||
delay(300)
|
||||
binding.reviveSubscriberWrapper.startAnimation(Animations.fadeOutAnimation())
|
||||
}
|
||||
lifecycleScope.launch(ExceptionHandler.coroutine()) {
|
||||
userRepository.updateUser("stats.hp", 1)
|
||||
MainScope().launchCatching {
|
||||
delay(1000)
|
||||
(HabiticaBaseApplication.getInstance(this@DeathActivity)?.currentActivity?.get() as? SnackbarActivity)?.let {activity ->
|
||||
HabiticaSnackbar.showSnackbar(
|
||||
activity.snackbarContainer(), getString(R.string.subscriber_benefit_success_faint), HabiticaSnackbar.SnackbarDisplayType.SUBSCRIBER_BENEFIT, isSubscriberBenefit = true, duration = 2500)
|
||||
binding.reviveSubscriberButton.setContent {
|
||||
var isUsingBenefit by remember { mutableStateOf(false) }
|
||||
HabiticaTheme {
|
||||
if (isUsingBenefit) {
|
||||
Box(contentAlignment = Alignment.Center, modifier = Modifier.fillMaxWidth().height(60.dp)) {
|
||||
CircularProgressIndicator()
|
||||
}
|
||||
} else {
|
||||
Box(
|
||||
contentAlignment = Alignment.Center,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(60.dp)
|
||||
.clickable {
|
||||
isUsingBenefit = true
|
||||
Analytics.sendEvent(
|
||||
"second chance perk",
|
||||
EventCategory.BEHAVIOUR,
|
||||
HitType.EVENT
|
||||
)
|
||||
sharedPreferences.edit {
|
||||
putLong("last_sub_revive", Date().time)
|
||||
}
|
||||
lifecycleScope.launch(ExceptionHandler.coroutine()) {
|
||||
userRepository.updateUser("stats.hp", 1)
|
||||
MainScope().launchCatching {
|
||||
delay(1000)
|
||||
(HabiticaBaseApplication.getInstance(this@DeathActivity)?.currentActivity?.get() as? SnackbarActivity)?.let { activity ->
|
||||
HabiticaSnackbar.showSnackbar(
|
||||
activity.snackbarContainer(),
|
||||
getString(R.string.subscriber_benefit_success_faint),
|
||||
HabiticaSnackbar.SnackbarDisplayType.SUBSCRIBER_BENEFIT,
|
||||
isSubscriberBenefit = true,
|
||||
duration = 2500
|
||||
)
|
||||
}
|
||||
}
|
||||
finish()
|
||||
}
|
||||
}
|
||||
) {
|
||||
Text(stringResource(R.string.subscriber_button_faint),
|
||||
fontSize = 16.sp,
|
||||
fontWeight = FontWeight.Medium,
|
||||
textAlign = TextAlign.Center)
|
||||
}
|
||||
}
|
||||
finish()
|
||||
}
|
||||
}
|
||||
|
||||
binding.restartButton.setOnClickListener {
|
||||
binding.restartButton.isEnabled = false
|
||||
binding.restartButton.startAnimation(Animations.fadeOutAnimation())
|
||||
lifecycleScope.launch(ExceptionHandler.coroutine()) {
|
||||
val brokenItem = userRepository.revive()
|
||||
if (brokenItem != null) {
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ import com.habitrpg.android.habitica.models.user.Permission
|
|||
import com.habitrpg.android.habitica.models.user.Stats
|
||||
import com.habitrpg.android.habitica.ui.adapter.social.AchievementProfileAdapter
|
||||
import com.habitrpg.android.habitica.ui.fragments.ReportBottomSheetFragment
|
||||
import com.habitrpg.android.habitica.ui.theme.HabiticaTheme
|
||||
import com.habitrpg.common.habitica.theme.HabiticaTheme
|
||||
import com.habitrpg.android.habitica.ui.views.AppHeaderView
|
||||
import com.habitrpg.android.habitica.ui.views.HabiticaSnackbar
|
||||
import com.habitrpg.android.habitica.ui.views.HabiticaSnackbar.SnackbarDisplayType
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import android.app.NotificationChannel
|
|||
import android.app.NotificationManager
|
||||
import android.appwidget.AppWidgetManager
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.res.Configuration
|
||||
|
|
@ -18,7 +17,6 @@ import androidx.activity.result.contract.ActivityResultContracts
|
|||
import androidx.activity.viewModels
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.appcompat.app.ActionBarDrawerToggle
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.height
|
||||
|
|
@ -30,14 +28,12 @@ import androidx.compose.runtime.livedata.observeAsState
|
|||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.ComposeView
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.core.view.children
|
||||
import androidx.core.view.setPadding
|
||||
import androidx.drawerlayout.widget.DrawerLayout
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.setViewTreeLifecycleOwner
|
||||
import androidx.navigation.NavDestination
|
||||
import androidx.navigation.findNavController
|
||||
import androidx.navigation.fragment.NavHostFragment
|
||||
|
|
@ -68,17 +64,17 @@ import com.habitrpg.android.habitica.interactors.CheckClassSelectionUseCase
|
|||
import com.habitrpg.android.habitica.interactors.DisplayItemDropUseCase
|
||||
import com.habitrpg.android.habitica.interactors.NotifyUserUseCase
|
||||
import com.habitrpg.android.habitica.interactors.ShareAvatarUseCase
|
||||
import com.habitrpg.android.habitica.interactors.SharePetUseCase
|
||||
import com.habitrpg.android.habitica.models.TutorialStep
|
||||
import com.habitrpg.android.habitica.models.user.User
|
||||
import com.habitrpg.android.habitica.models.user.UserQuestStatus
|
||||
import com.habitrpg.android.habitica.ui.TutorialView
|
||||
import com.habitrpg.android.habitica.ui.fragments.NavigationDrawerFragment
|
||||
import com.habitrpg.android.habitica.ui.theme.HabiticaTheme
|
||||
import com.habitrpg.android.habitica.ui.theme.colors
|
||||
import com.habitrpg.common.habitica.theme.HabiticaTheme
|
||||
import com.habitrpg.android.habitica.ui.viewmodels.MainActivityViewModel
|
||||
import com.habitrpg.android.habitica.ui.viewmodels.NotificationsViewModel
|
||||
import com.habitrpg.android.habitica.ui.views.AppHeaderView
|
||||
import com.habitrpg.android.habitica.ui.views.ComposableAvatarView
|
||||
import com.habitrpg.common.habitica.views.ComposableAvatarView
|
||||
import com.habitrpg.android.habitica.ui.views.GroupPlanMemberList
|
||||
import com.habitrpg.android.habitica.ui.views.HabiticaButton
|
||||
import com.habitrpg.android.habitica.ui.views.HabiticaSnackbar
|
||||
|
|
@ -767,11 +763,11 @@ open class MainActivity : BaseActivity(), SnackbarActivity {
|
|||
|
||||
private var errorJob: Job? = null
|
||||
|
||||
override fun showConnectionProblem(errorCount: Int, title: String?, message: String) {
|
||||
if (errorCount == 1) {
|
||||
override fun showConnectionProblem(errorCount: Int, title: String?, message: String, isFromUserInput: Boolean) {
|
||||
if (errorCount == 1 && !isFromUserInput) {
|
||||
showSnackbar(title = title, content = message, displayType = HabiticaSnackbar.SnackbarDisplayType.FAILURE)
|
||||
} else if (title != null) {
|
||||
super.showConnectionProblem(errorCount, title, message)
|
||||
super.showConnectionProblem(errorCount, title, message, isFromUserInput)
|
||||
} else {
|
||||
if (errorJob?.isCancelled == false) {
|
||||
// a new error resets the timer to hide the error message
|
||||
|
|
|
|||
|
|
@ -13,7 +13,10 @@ import android.widget.LinearLayout
|
|||
import android.widget.RatingBar
|
||||
import android.widget.TextView
|
||||
import androidx.activity.viewModels
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.children
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.habitrpg.android.habitica.R
|
||||
import com.habitrpg.android.habitica.data.InventoryRepository
|
||||
|
|
@ -40,10 +43,13 @@ import com.habitrpg.common.habitica.models.notifications.NewStuffData
|
|||
import com.habitrpg.common.habitica.models.notifications.PartyInvitationData
|
||||
import com.habitrpg.common.habitica.models.notifications.QuestInvitationData
|
||||
import com.habitrpg.common.habitica.models.notifications.UnallocatedPointsData
|
||||
import com.habitrpg.common.habitica.views.HabiticaCircularProgressView
|
||||
import com.habitrpg.common.habitica.views.PixelArtView
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.FlowPreview
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.debounce
|
||||
import kotlinx.coroutines.flow.firstOrNull
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
|
@ -74,6 +80,7 @@ class NotificationsActivity : BaseActivity(), androidx.swiperefreshlayout.widget
|
|||
|
||||
private var notifications: List<Notification> = emptyList()
|
||||
|
||||
@OptIn(FlowPreview::class)
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
|
|
@ -87,17 +94,36 @@ class NotificationsActivity : BaseActivity(), androidx.swiperefreshlayout.widget
|
|||
|
||||
inflater = getSystemService(Context.LAYOUT_INFLATER_SERVICE) as? LayoutInflater
|
||||
|
||||
binding.progressView.setContent {
|
||||
HabiticaCircularProgressView(indicatorSize = 60.dp)
|
||||
}
|
||||
|
||||
lifecycleScope.launchCatching {
|
||||
viewModel.getNotifications().collect {
|
||||
viewModel.getNotifications()
|
||||
.debounce(250)
|
||||
.collect {
|
||||
setNotifications(it)
|
||||
viewModel.markNotificationsAsSeen(it)
|
||||
}
|
||||
}
|
||||
|
||||
lifecycleScope.launchCatching {
|
||||
viewModel.getNotificationCount()
|
||||
.collect {
|
||||
binding.notificationsTitleBadge.text = it.toString()
|
||||
}
|
||||
}
|
||||
|
||||
binding.notificationsRefreshLayout.setOnRefreshListener(this)
|
||||
lifecycleScope.launchCatching {
|
||||
viewModel.refreshNotifications()
|
||||
}
|
||||
|
||||
binding.dismissAllButton.setOnClickListener {
|
||||
HapticFeedbackManager.tap(it)
|
||||
viewModel.dismissAllNotifications(notifications)
|
||||
setNotifications(emptyList())
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSupportNavigateUp(): Boolean {
|
||||
|
|
@ -131,15 +157,18 @@ class NotificationsActivity : BaseActivity(), androidx.swiperefreshlayout.widget
|
|||
binding.notificationItems.removeAllViewsInLayout()
|
||||
binding.notificationItems.showDividers = LinearLayout.SHOW_DIVIDER_NONE
|
||||
binding.notificationItems.addView(inflater?.inflate(R.layout.no_notifications, binding.notificationItems, false))
|
||||
binding.progressView.isVisible = false
|
||||
}
|
||||
|
||||
|
||||
private fun displayNotificationsListView(notifications: List<Notification>) {
|
||||
binding.notificationItems.showDividers = LinearLayout.SHOW_DIVIDER_MIDDLE or LinearLayout.SHOW_DIVIDER_END
|
||||
val viewList = arrayListOf<View>()
|
||||
createNotificationsHeaderView(notifications.count())?.let { viewList.add(it) }
|
||||
|
||||
lifecycleScope.launch(ExceptionHandler.coroutine()) {
|
||||
notifications.map {
|
||||
val currentViews = mutableSetOf<View>().apply {
|
||||
addAll(binding.notificationItems.children)
|
||||
}
|
||||
notifications.forEach {
|
||||
val item: View? = when (it.type) {
|
||||
Notification.Type.NEW_CHAT_MESSAGE.type -> createNewChatMessageNotification(it)
|
||||
Notification.Type.NEW_STUFF.type -> createNewStuffNotification(it)
|
||||
|
|
@ -154,30 +183,22 @@ class NotificationsActivity : BaseActivity(), androidx.swiperefreshlayout.widget
|
|||
else -> null
|
||||
}
|
||||
|
||||
if (item != null) {
|
||||
viewList.add(item)
|
||||
item?.let { view ->
|
||||
if (!currentViews.removeIf { it.tag == view.tag }) {
|
||||
binding.notificationItems.addView(view)
|
||||
}
|
||||
}
|
||||
}
|
||||
updateNotificationsAndRefresh(viewList)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateNotificationsAndRefresh(newItems: List<View>) {
|
||||
val currentViews = (0 until binding.notificationItems.childCount).map {
|
||||
binding.notificationItems.getChildAt(it)
|
||||
}
|
||||
val viewsToRemove = currentViews - newItems
|
||||
viewsToRemove.forEach { binding.notificationItems.removeView(it) }
|
||||
val viewsToAdd = newItems - currentViews
|
||||
viewsToAdd.forEach {
|
||||
binding.notificationItems.addView(it)
|
||||
}
|
||||
// Remove views that are no longer valid
|
||||
currentViews.forEach { binding.notificationItems.removeView(it) }
|
||||
|
||||
lifecycleScope.launch {
|
||||
delay(250)
|
||||
// Unnecessary but looks clean c:
|
||||
if (binding.notificationItems.visibility != View.VISIBLE) {
|
||||
binding.notificationItems.fadeInAnimation(200)
|
||||
lifecycleScope.launch {
|
||||
binding.progressView.isVisible = false
|
||||
delay(250)
|
||||
if (binding.notificationItems.visibility != View.VISIBLE) {
|
||||
binding.notificationItems.fadeInAnimation(200)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -194,22 +215,6 @@ class NotificationsActivity : BaseActivity(), androidx.swiperefreshlayout.widget
|
|||
}
|
||||
}
|
||||
|
||||
private fun createNotificationsHeaderView(notificationCount: Int): View? {
|
||||
val header = inflater?.inflate(R.layout.notifications_header, binding.notificationItems, false)
|
||||
|
||||
val badge = header?.findViewById(R.id.notifications_title_badge) as? TextView
|
||||
badge?.text = notificationCount.toString()
|
||||
|
||||
val dismissAllButton = header?.findViewById(R.id.dismiss_all_button) as? Button
|
||||
dismissAllButton?.setOnClickListener {
|
||||
binding.root.flash()
|
||||
HapticFeedbackManager.tap(it)
|
||||
viewModel.dismissAllNotifications(notifications)
|
||||
}
|
||||
|
||||
return header
|
||||
}
|
||||
|
||||
private fun createNewChatMessageNotification(notification: Notification): View? {
|
||||
val data = notification.data as? NewChatMessageData
|
||||
val stringId = if (viewModel.isPartyMessage(data)) R.string.new_msg_party else R.string.new_msg_guild
|
||||
|
|
@ -229,13 +234,16 @@ class NotificationsActivity : BaseActivity(), androidx.swiperefreshlayout.widget
|
|||
)
|
||||
}
|
||||
|
||||
private var baileyNewsNotification: Notification? = null
|
||||
|
||||
private suspend fun createNewStuffNotification(notification: Notification): View? = withContext(Dispatchers.IO) {
|
||||
var baileyNotification = notification
|
||||
val data = notification.data as? NewStuffData
|
||||
val text = if (data?.title != null) {
|
||||
fromHtml("<b>" + getString(R.string.new_bailey_update) + "</b><br>" + data.title)
|
||||
} else {
|
||||
baileyNotification = userRepository.getNewsNotification() ?: notification
|
||||
baileyNotification = baileyNewsNotification ?: userRepository.getNewsNotification() ?: notification
|
||||
baileyNewsNotification = baileyNotification
|
||||
val baileyNewsData = baileyNotification.data as? NewStuffData
|
||||
fromHtml("<b>" + getString(R.string.new_bailey_update) + "</b><br>" + baileyNewsData?.title)
|
||||
}
|
||||
|
|
@ -332,6 +340,7 @@ class NotificationsActivity : BaseActivity(), androidx.swiperefreshlayout.widget
|
|||
textColor: Int? = null
|
||||
): View? {
|
||||
val item = inflater?.inflate(R.layout.notification_item, binding.notificationItems, false)
|
||||
item?.tag = notification.id
|
||||
|
||||
val container = item?.findViewById(R.id.notification_item) as? View
|
||||
container?.setOnClickListener {
|
||||
|
|
@ -345,7 +354,7 @@ class NotificationsActivity : BaseActivity(), androidx.swiperefreshlayout.widget
|
|||
|
||||
val dismissButton = item?.findViewById(R.id.dismiss_button) as? ImageView
|
||||
dismissButton?.setOnClickListener {
|
||||
container?.flash()
|
||||
it.flash()
|
||||
HapticFeedbackManager.tap(it)
|
||||
removeNotificationAndRefresh(notification)
|
||||
viewModel.dismissNotification(notification)
|
||||
|
|
@ -444,6 +453,7 @@ class NotificationsActivity : BaseActivity(), androidx.swiperefreshlayout.widget
|
|||
inviterId: String? = null
|
||||
): View? {
|
||||
val item = inflater?.inflate(R.layout.notification_item_actionable, binding.notificationItems, false)
|
||||
item?.tag = notification.id
|
||||
|
||||
if (openable) {
|
||||
val container = item?.findViewById(R.id.notification_item) as? View
|
||||
|
|
@ -463,7 +473,6 @@ class NotificationsActivity : BaseActivity(), androidx.swiperefreshlayout.widget
|
|||
|
||||
val acceptButton = item?.findViewById(R.id.accept_button) as? Button
|
||||
acceptButton?.setOnClickListener {
|
||||
binding.root.flash()
|
||||
HapticFeedbackManager.tap(it)
|
||||
removeNotificationAndRefresh(notification)
|
||||
viewModel.accept(notification.id)
|
||||
|
|
@ -471,7 +480,6 @@ class NotificationsActivity : BaseActivity(), androidx.swiperefreshlayout.widget
|
|||
|
||||
val rejectButton = item?.findViewById(R.id.reject_button) as? Button
|
||||
rejectButton?.setOnClickListener {
|
||||
binding.root.flash()
|
||||
HapticFeedbackManager.tap(it)
|
||||
removeNotificationAndRefresh(notification)
|
||||
viewModel.reject(notification.id)
|
||||
|
|
|
|||
|
|
@ -50,7 +50,10 @@ import com.habitrpg.android.habitica.models.tasks.Task
|
|||
import com.habitrpg.android.habitica.models.tasks.TaskGroupPlan
|
||||
import com.habitrpg.android.habitica.ui.helpers.ToolbarColorHelper
|
||||
import com.habitrpg.android.habitica.ui.helpers.dismissKeyboard
|
||||
import com.habitrpg.android.habitica.ui.theme.HabiticaTheme
|
||||
import com.habitrpg.android.habitica.ui.theme.colors
|
||||
import com.habitrpg.android.habitica.ui.theme.textPrimaryFor
|
||||
import com.habitrpg.android.habitica.ui.theme.windowBackgroundFor
|
||||
import com.habitrpg.common.habitica.theme.HabiticaTheme
|
||||
import com.habitrpg.android.habitica.ui.viewmodels.MainUserViewModel
|
||||
import com.habitrpg.android.habitica.ui.viewmodels.TaskFormViewModel
|
||||
import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaAlertDialog
|
||||
|
|
|
|||
|
|
@ -50,7 +50,13 @@ import com.habitrpg.android.habitica.data.UserRepository
|
|||
import com.habitrpg.common.habitica.helpers.MainNavigationController
|
||||
import com.habitrpg.android.habitica.helpers.TaskDescriptionBuilder
|
||||
import com.habitrpg.android.habitica.models.members.Member
|
||||
import com.habitrpg.android.habitica.ui.theme.HabiticaTheme
|
||||
import com.habitrpg.android.habitica.ui.theme.colors
|
||||
import com.habitrpg.android.habitica.ui.theme.contentBackgroundFor
|
||||
import com.habitrpg.android.habitica.ui.theme.primaryBackgroundFor
|
||||
import com.habitrpg.android.habitica.ui.theme.textPrimaryFor
|
||||
import com.habitrpg.android.habitica.ui.theme.textSecondaryFor
|
||||
import com.habitrpg.android.habitica.ui.theme.windowBackgroundFor
|
||||
import com.habitrpg.common.habitica.theme.HabiticaTheme
|
||||
import com.habitrpg.android.habitica.ui.viewmodels.BaseViewModel
|
||||
import com.habitrpg.android.habitica.ui.viewmodels.MainUserViewModel
|
||||
import com.habitrpg.android.habitica.ui.views.CompletedAt
|
||||
|
|
|
|||
|
|
@ -614,8 +614,8 @@ class NavigationDrawerFragment : DialogFragment() {
|
|||
// set UP the drawer's list view with items and click listener
|
||||
|
||||
lifecycleScope.launchCatching {
|
||||
viewModel.getNotifications().collect {
|
||||
setNotificationsCount(it.count())
|
||||
viewModel.getNotificationCount().collect {
|
||||
setNotificationsCount(it)
|
||||
}
|
||||
}
|
||||
lifecycleScope.launchCatching {
|
||||
|
|
|
|||
|
|
@ -35,7 +35,8 @@ import com.habitrpg.common.habitica.helpers.MainNavigationController
|
|||
import com.habitrpg.android.habitica.models.inventory.Equipment
|
||||
import com.habitrpg.android.habitica.ui.activities.BaseActivity
|
||||
import com.habitrpg.android.habitica.ui.fragments.BaseMainFragment
|
||||
import com.habitrpg.android.habitica.ui.theme.HabiticaTheme
|
||||
import com.habitrpg.android.habitica.ui.theme.colors
|
||||
import com.habitrpg.common.habitica.theme.HabiticaTheme
|
||||
import com.habitrpg.android.habitica.ui.viewmodels.MainUserViewModel
|
||||
import com.habitrpg.android.habitica.ui.views.SegmentedControl
|
||||
import com.habitrpg.android.habitica.ui.views.equipment.AvatarCustomizationOverviewView
|
||||
|
|
|
|||
|
|
@ -33,7 +33,6 @@ import com.habitrpg.android.habitica.ui.views.CurrencyText
|
|||
import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaAlertDialog
|
||||
import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaProgressDialog
|
||||
import com.habitrpg.android.habitica.ui.views.insufficientCurrency.InsufficientGemsDialog
|
||||
import com.habitrpg.android.habitica.ui.views.insufficientCurrency.InsufficientHourglassesDialog
|
||||
import com.habitrpg.android.habitica.ui.views.shops.PurchaseDialog
|
||||
import com.habitrpg.common.habitica.helpers.ExceptionHandler
|
||||
import com.habitrpg.common.habitica.helpers.RecyclerViewState
|
||||
|
|
@ -256,7 +255,7 @@ open class ShopFragment : BaseMainFragment<FragmentRefreshRecyclerviewBinding>()
|
|||
alert.setMessage(getString(R.string.change_class_equipment_warning))
|
||||
alert.addButton(R.string.choose_class, true) { _, _ ->
|
||||
val dialog = HabiticaProgressDialog.show(
|
||||
context,
|
||||
requireActivity(),
|
||||
getString(R.string.changing_class_progress),
|
||||
300
|
||||
)
|
||||
|
|
@ -274,7 +273,7 @@ open class ShopFragment : BaseMainFragment<FragmentRefreshRecyclerviewBinding>()
|
|||
alert.setTitle(getString(R.string.class_confirmation, classIdentifier))
|
||||
alert.addButton(R.string.choose_class, true) { _, _ ->
|
||||
val dialog = HabiticaProgressDialog.show(
|
||||
context,
|
||||
requireActivity(),
|
||||
getString(R.string.changing_class_progress),
|
||||
300
|
||||
)
|
||||
|
|
|
|||
|
|
@ -4,9 +4,15 @@ import android.os.Bundle
|
|||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.habitrpg.android.habitica.models.shops.Shop
|
||||
import com.habitrpg.android.habitica.ui.fragments.purchases.EventOutcomeSubscriptionBottomSheetFragment
|
||||
import com.habitrpg.android.habitica.ui.fragments.purchases.SubscriptionBottomSheetFragment
|
||||
import com.habitrpg.android.habitica.ui.views.CurrencyText
|
||||
import com.habitrpg.common.habitica.helpers.launchCatching
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
|
||||
@AndroidEntryPoint
|
||||
class TimeTravelersShopFragment : ShopFragment() {
|
||||
|
|
@ -22,6 +28,17 @@ class TimeTravelersShopFragment : ShopFragment() {
|
|||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
initializeCurrencyViews()
|
||||
|
||||
lifecycleScope.launchCatching {
|
||||
val user = userViewModel.user.value
|
||||
if (user?.isSubscribed != true) {
|
||||
delay(2.seconds)
|
||||
val subscriptionBottomSheet = EventOutcomeSubscriptionBottomSheetFragment().apply {
|
||||
eventType = EventOutcomeSubscriptionBottomSheetFragment.EVENT_HOURGLASS_SHOP_OPENED
|
||||
}
|
||||
activity?.supportFragmentManager?.let { subscriptionBottomSheet.show(it, SubscriptionBottomSheetFragment.TAG) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun initializeCurrencyViews() {
|
||||
|
|
|
|||
|
|
@ -488,7 +488,7 @@ class AccountPreferenceFragment :
|
|||
}
|
||||
|
||||
private fun deleteAccount(password: String) {
|
||||
val dialog = context?.let { HabiticaProgressDialog.show(it, R.string.deleting_account) }
|
||||
val dialog = activity?.let { HabiticaProgressDialog.show(it, R.string.deleting_account) }
|
||||
lifecycleScope.launchCatching({ throwable ->
|
||||
dialog?.dismiss()
|
||||
if (throwable is HttpException && throwable.code() == 401) {
|
||||
|
|
@ -537,7 +537,7 @@ class AccountPreferenceFragment :
|
|||
}
|
||||
|
||||
private fun resetAccount() {
|
||||
val dialog = context?.let { HabiticaProgressDialog.show(it, R.string.resetting_account) }
|
||||
val dialog = activity?.let { HabiticaProgressDialog.show(it, R.string.resetting_account) }
|
||||
lifecycleScope.launch(ExceptionHandler.coroutine()) {
|
||||
userRepository.resetAccount()
|
||||
dialog?.dismiss()
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.habitrpg.android.habitica.ui.fragments.purchases
|
|||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.core.view.isVisible
|
||||
import com.habitrpg.android.habitica.R
|
||||
|
||||
class EventOutcomeSubscriptionBottomSheetFragment : SubscriptionBottomSheetFragment() {
|
||||
|
|
@ -42,6 +43,7 @@ class EventOutcomeSubscriptionBottomSheetFragment : SubscriptionBottomSheetFragm
|
|||
binding.subscribeBenefits.text = getString(R.string.subscribe_hourglass_incentive_text)
|
||||
binding.subscriberBenefits.hideMysticHourglassBenefit()
|
||||
binding.subscription1month.visibility = View.GONE
|
||||
skus.firstOrNull { buttonForSku(it)?.isVisible == true }?.let { selectSubscription(it) }
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ import com.habitrpg.android.habitica.ui.activities.GiftGemsActivity
|
|||
import com.habitrpg.android.habitica.ui.fragments.BaseFragment
|
||||
import com.habitrpg.android.habitica.ui.fragments.PromoInfoFragment
|
||||
import com.habitrpg.android.habitica.ui.helpers.dismissKeyboard
|
||||
import com.habitrpg.android.habitica.ui.theme.HabiticaTheme
|
||||
import com.habitrpg.common.habitica.theme.HabiticaTheme
|
||||
import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaAlertDialog
|
||||
import com.habitrpg.android.habitica.ui.views.promo.BirthdayBanner
|
||||
import com.habitrpg.common.habitica.extensions.isUsingNightModeResources
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ open class SubscriptionBottomSheetFragment : BottomSheetDialogFragment() {
|
|||
lateinit var purchaseHandler: PurchaseHandler
|
||||
|
||||
private var selectedSubscriptionSku: ProductDetails? = null
|
||||
private var skus: List<ProductDetails> = emptyList()
|
||||
internal var skus: List<ProductDetails> = emptyList()
|
||||
|
||||
private var user: User? = null
|
||||
private var hasLoadedSubscriptionOptions: Boolean = false
|
||||
|
|
@ -112,7 +112,11 @@ open class SubscriptionBottomSheetFragment : BottomSheetDialogFragment() {
|
|||
for (sku in subscriptions) {
|
||||
updateButtonLabel(sku, sku.subscriptionOfferDetails?.firstOrNull()?.pricingPhases?.pricingPhaseList?.firstOrNull()?.formattedPrice ?: "")
|
||||
}
|
||||
subscriptions.minByOrNull { it.subscriptionOfferDetails?.firstOrNull()?.pricingPhases?.pricingPhaseList?.firstOrNull()?.priceAmountMicros ?: 0 }?.let { selectSubscription(it) }
|
||||
subscriptions
|
||||
.filter { buttonForSku(it)?.isVisible == true }
|
||||
.minByOrNull {
|
||||
it.subscriptionOfferDetails?.firstOrNull()?.pricingPhases?.pricingPhaseList?.firstOrNull()?.priceAmountMicros ?: 0
|
||||
}?.let { selectSubscription(it) }
|
||||
hasLoadedSubscriptionOptions = true
|
||||
updateSubscriptionInfo()
|
||||
}
|
||||
|
|
@ -130,7 +134,7 @@ open class SubscriptionBottomSheetFragment : BottomSheetDialogFragment() {
|
|||
}
|
||||
}
|
||||
|
||||
private fun selectSubscription(sku: ProductDetails) {
|
||||
internal fun selectSubscription(sku: ProductDetails) {
|
||||
if (this.selectedSubscriptionSku != null) {
|
||||
val oldButton = buttonForSku(this.selectedSubscriptionSku)
|
||||
oldButton?.setIsSelected(false)
|
||||
|
|
@ -141,7 +145,7 @@ open class SubscriptionBottomSheetFragment : BottomSheetDialogFragment() {
|
|||
binding.subscribeButton.isEnabled = true
|
||||
}
|
||||
|
||||
private fun buttonForSku(sku: ProductDetails?): SubscriptionOptionView? {
|
||||
internal fun buttonForSku(sku: ProductDetails?): SubscriptionOptionView? {
|
||||
return buttonForSku(sku?.productId)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ import com.habitrpg.android.habitica.models.user.User
|
|||
import com.habitrpg.android.habitica.ui.activities.GiftSubscriptionActivity
|
||||
import com.habitrpg.android.habitica.ui.fragments.BaseFragment
|
||||
import com.habitrpg.android.habitica.ui.fragments.PromoInfoFragment
|
||||
import com.habitrpg.android.habitica.ui.theme.HabiticaTheme
|
||||
import com.habitrpg.common.habitica.theme.HabiticaTheme
|
||||
import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaAlertDialog
|
||||
import com.habitrpg.android.habitica.ui.views.promo.BirthdayBanner
|
||||
import com.habitrpg.android.habitica.ui.views.subscriptions.SubscriptionOptionView
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ import com.habitrpg.android.habitica.ui.activities.MainActivity
|
|||
import com.habitrpg.android.habitica.ui.fragments.BaseFragment
|
||||
import com.habitrpg.android.habitica.ui.fragments.inventory.items.ItemDialogFragment
|
||||
import com.habitrpg.android.habitica.ui.helpers.dismissKeyboard
|
||||
import com.habitrpg.android.habitica.ui.theme.HabiticaTheme
|
||||
import com.habitrpg.common.habitica.theme.HabiticaTheme
|
||||
import com.habitrpg.android.habitica.ui.viewHolders.GroupMemberViewHolder
|
||||
import com.habitrpg.android.habitica.ui.viewmodels.PartyViewModel
|
||||
import com.habitrpg.android.habitica.ui.views.HabiticaSnackbar
|
||||
|
|
|
|||
|
|
@ -55,7 +55,8 @@ import com.habitrpg.android.habitica.databinding.FragmentComposeBinding
|
|||
import com.habitrpg.common.habitica.helpers.MainNavigationController
|
||||
import com.habitrpg.android.habitica.models.invitations.InviteResponse
|
||||
import com.habitrpg.android.habitica.ui.fragments.BaseFragment
|
||||
import com.habitrpg.android.habitica.ui.theme.HabiticaTheme
|
||||
import com.habitrpg.android.habitica.ui.theme.colors
|
||||
import com.habitrpg.common.habitica.theme.HabiticaTheme
|
||||
import com.habitrpg.android.habitica.ui.viewmodels.BaseViewModel
|
||||
import com.habitrpg.android.habitica.ui.viewmodels.MainUserViewModel
|
||||
import com.habitrpg.android.habitica.ui.views.LoadingButtonState
|
||||
|
|
|
|||
|
|
@ -60,13 +60,14 @@ import com.habitrpg.android.habitica.helpers.HitType
|
|||
import com.habitrpg.android.habitica.models.invitations.InviteResponse
|
||||
import com.habitrpg.android.habitica.models.members.Member
|
||||
import com.habitrpg.android.habitica.ui.fragments.BaseFragment
|
||||
import com.habitrpg.android.habitica.ui.theme.HabiticaTheme
|
||||
import com.habitrpg.android.habitica.ui.theme.colors
|
||||
import com.habitrpg.common.habitica.theme.HabiticaTheme
|
||||
import com.habitrpg.android.habitica.ui.viewmodels.BaseViewModel
|
||||
import com.habitrpg.android.habitica.ui.viewmodels.MainUserViewModel
|
||||
import com.habitrpg.android.habitica.ui.views.LoadingButton
|
||||
import com.habitrpg.android.habitica.ui.views.LoadingButtonState
|
||||
import com.habitrpg.android.habitica.ui.views.LoadingButtonType
|
||||
import com.habitrpg.android.habitica.ui.views.progress.HabiticaCircularProgressView
|
||||
import com.habitrpg.common.habitica.views.HabiticaCircularProgressView
|
||||
import com.habitrpg.android.habitica.ui.views.progress.HabiticaPullRefreshIndicator
|
||||
import com.habitrpg.android.habitica.ui.views.social.PartySeekingListItem
|
||||
import com.habitrpg.common.habitica.helpers.launchCatching
|
||||
|
|
|
|||
|
|
@ -1,222 +1,83 @@
|
|||
package com.habitrpg.android.habitica.ui.theme
|
||||
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Shapes
|
||||
import androidx.compose.material.Typography
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalLayoutDirection
|
||||
import androidx.compose.ui.res.colorResource
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.font.FontFamily
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.google.accompanist.themeadapter.material.createMdcTheme
|
||||
import com.habitrpg.android.habitica.R
|
||||
import com.habitrpg.android.habitica.models.tasks.Task
|
||||
import com.habitrpg.common.habitica.extensions.getThemeColor
|
||||
import com.habitrpg.common.habitica.theme.HabiticaColors
|
||||
import com.habitrpg.common.habitica.theme.HabiticaTheme
|
||||
|
||||
|
||||
@Composable
|
||||
fun HabiticaTheme(
|
||||
content: @Composable () -> Unit
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val layoutDirection = LocalLayoutDirection.current
|
||||
val (colors, _, _) = createMdcTheme(
|
||||
context = context,
|
||||
layoutDirection = layoutDirection,
|
||||
setTextColors = true
|
||||
)
|
||||
MaterialTheme(
|
||||
colors = colors ?: MaterialTheme.colors,
|
||||
typography = Typography(
|
||||
defaultFontFamily = FontFamily.Default,
|
||||
h1 = TextStyle(
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 20.sp,
|
||||
letterSpacing = (0.05).sp
|
||||
),
|
||||
h2 = TextStyle(
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 28.sp,
|
||||
letterSpacing = (0.05).sp
|
||||
),
|
||||
subtitle1 = TextStyle(
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 16.sp
|
||||
),
|
||||
subtitle2 = TextStyle(
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 16.sp,
|
||||
letterSpacing = 0.1.sp
|
||||
),
|
||||
body1 = TextStyle(
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 14.sp,
|
||||
letterSpacing = 0.35.sp,
|
||||
lineHeight = 16.sp
|
||||
),
|
||||
body2 = TextStyle(
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 14.sp,
|
||||
letterSpacing = 0.2.sp,
|
||||
lineHeight = 16.sp
|
||||
),
|
||||
button = TextStyle(
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 14.sp,
|
||||
letterSpacing = 1.25.sp
|
||||
),
|
||||
caption = TextStyle(
|
||||
fontWeight = FontWeight.Bold,
|
||||
fontSize = 12.sp
|
||||
),
|
||||
overline = TextStyle(
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 10.sp,
|
||||
letterSpacing = 1.5.sp
|
||||
)
|
||||
),
|
||||
shapes = Shapes(
|
||||
RoundedCornerShape(4.dp),
|
||||
RoundedCornerShape(8.dp),
|
||||
RoundedCornerShape(12.dp)
|
||||
),
|
||||
content = content
|
||||
)
|
||||
fun HabiticaColors.textPrimaryFor(task: Task?): Color {
|
||||
return colorResource((if (isSystemInDarkTheme()) task?.extraExtraLightTaskColor else task?.extraDarkTaskColor) ?: R.color.text_primary)
|
||||
}
|
||||
|
||||
val Typography.caption1
|
||||
get() = caption
|
||||
val Typography.caption2
|
||||
get() = TextStyle(
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 12.sp,
|
||||
letterSpacing = 0.4.sp
|
||||
)
|
||||
val Typography.caption3
|
||||
get() = TextStyle(
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 12.sp,
|
||||
letterSpacing = 0.3.sp,
|
||||
lineHeight = 14.sp
|
||||
)
|
||||
val Typography.caption4
|
||||
get() = TextStyle(
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 12.sp,
|
||||
letterSpacing = 0.35.sp
|
||||
)
|
||||
val Typography.subtitle3
|
||||
get() = TextStyle(
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 16.sp,
|
||||
letterSpacing = 0.15.sp
|
||||
)
|
||||
|
||||
object HabiticaTheme {
|
||||
val typography: Typography
|
||||
@Composable
|
||||
get() = MaterialTheme.typography
|
||||
|
||||
val shapes: Shapes
|
||||
@Composable
|
||||
get() = MaterialTheme.shapes
|
||||
|
||||
val colors: HabiticaColors
|
||||
@Composable
|
||||
get() {
|
||||
val context = LocalContext.current
|
||||
return HabiticaColors(
|
||||
windowBackground = Color(context.getThemeColor(R.attr.colorWindowBackground)),
|
||||
contentBackground = Color(context.getThemeColor(R.attr.colorContentBackground)),
|
||||
contentBackgroundOffset = Color(context.getThemeColor(R.attr.colorContentBackgroundOffset)),
|
||||
offsetBackground = Color(context.getThemeColor(R.attr.colorOffsetBackground)),
|
||||
textPrimary = Color(context.getThemeColor(R.attr.textColorPrimary)),
|
||||
textSecondary = Color(context.getThemeColor(R.attr.textColorSecondary)),
|
||||
textTertiary = Color(ContextCompat.getColor(context, R.color.text_ternary)),
|
||||
textQuad = Color(ContextCompat.getColor(context, R.color.text_quad)),
|
||||
textDimmed = Color(ContextCompat.getColor(context, R.color.text_dimmed)),
|
||||
tintedUiMain = Color(context.getThemeColor(R.attr.tintedUiMain)),
|
||||
tintedUiSub = Color(context.getThemeColor(R.attr.tintedUiSub)),
|
||||
tintedUiDetails = Color(context.getThemeColor(R.attr.tintedUiDetails)),
|
||||
pixelArtBackground = Color(context.getThemeColor(R.attr.colorContentBackground)),
|
||||
errorBackground = Color(ContextCompat.getColor(context, R.color.background_red)),
|
||||
errorColor = Color(ContextCompat.getColor(context, R.color.text_red)),
|
||||
successBackground = Color(ContextCompat.getColor(context, R.color.background_green)),
|
||||
successColor = Color(ContextCompat.getColor(context, R.color.text_green))
|
||||
)
|
||||
}
|
||||
@Composable
|
||||
fun HabiticaColors.textSecondaryFor(task: Task?): Color {
|
||||
return colorResource((if (isSystemInDarkTheme()) task?.extraLightTaskColor else task?.lowSaturationTaskColor) ?: R.color.brand_sub_text)
|
||||
}
|
||||
|
||||
class HabiticaColors(
|
||||
val windowBackground: Color,
|
||||
val contentBackground: Color,
|
||||
val contentBackgroundOffset: Color,
|
||||
val offsetBackground: Color,
|
||||
val textPrimary: Color,
|
||||
val textSecondary: Color,
|
||||
val textTertiary: Color,
|
||||
val textQuad: Color,
|
||||
val textDimmed: Color,
|
||||
val tintedUiMain: Color,
|
||||
val tintedUiSub: Color,
|
||||
val tintedUiDetails: Color,
|
||||
val pixelArtBackground: Color,
|
||||
val errorBackground: Color,
|
||||
val errorColor: Color,
|
||||
val successBackground: Color,
|
||||
val successColor: Color
|
||||
) {
|
||||
@Composable
|
||||
fun HabiticaColors.primaryBackgroundFor(task: Task?): Color {
|
||||
return colorResource((if (isSystemInDarkTheme()) task?.mediumTaskColor else task?.lightTaskColor) ?: R.color.brand_400)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun textPrimaryFor(task: Task?): Color {
|
||||
return colorResource((if (isSystemInDarkTheme()) task?.extraExtraLightTaskColor else task?.extraDarkTaskColor) ?: R.color.text_primary)
|
||||
}
|
||||
@Composable
|
||||
fun HabiticaColors.windowBackgroundFor(task: Task?): Color {
|
||||
return (if (isSystemInDarkTheme()) task?.extraExtraDarkTaskColor else task?.extraExtraLightTaskColor)?.let { colorResource(it) } ?: windowBackground
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun textSecondaryFor(task: Task?): Color {
|
||||
return colorResource((if (isSystemInDarkTheme()) task?.extraLightTaskColor else task?.lowSaturationTaskColor) ?: R.color.brand_sub_text)
|
||||
}
|
||||
@Composable
|
||||
fun HabiticaColors.contentBackgroundFor(task: Task?): Color {
|
||||
return (if (isSystemInDarkTheme()) task?.darkestTaskColor else task?.lightestTaskColor)?.let { colorResource(it) } ?: windowBackground
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun primaryBackgroundFor(task: Task?): Color {
|
||||
return colorResource((if (isSystemInDarkTheme()) task?.mediumTaskColor else task?.lightTaskColor) ?: R.color.brand_400)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun windowBackgroundFor(task: Task?): Color {
|
||||
return (if (isSystemInDarkTheme()) task?.extraExtraDarkTaskColor else task?.extraExtraLightTaskColor)?.let { colorResource(it) } ?: windowBackground
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun contentBackgroundFor(task: Task?): Color {
|
||||
return (if (isSystemInDarkTheme()) task?.darkestTaskColor else task?.lightestTaskColor)?.let { colorResource(it) } ?: windowBackground
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun pixelArtBackground(hasIcon: Boolean): Color {
|
||||
return if (isSystemInDarkTheme()) {
|
||||
colorResource(if (hasIcon) R.color.gray_200 else R.color.gray_5)
|
||||
} else {
|
||||
colorResource(if (hasIcon) R.color.content_background else R.color.content_background_offset)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun basicTextColor(): Color {
|
||||
return colorResource(R.color.gray200_gray400)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun basicButtonColor(): Color {
|
||||
return colorResource(R.color.gray700_gray10)
|
||||
@Composable
|
||||
fun HabiticaColors.pixelArtBackground(hasIcon: Boolean): Color {
|
||||
return if (isSystemInDarkTheme()) {
|
||||
colorResource(if (hasIcon) R.color.gray_200 else R.color.gray_5)
|
||||
} else {
|
||||
colorResource(if (hasIcon) R.color.content_background else R.color.content_background_offset)
|
||||
}
|
||||
}
|
||||
|
||||
class HabiticaTypography
|
||||
@Composable
|
||||
fun HabiticaColors.basicTextColor(): Color {
|
||||
return colorResource(R.color.gray200_gray400)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun HabiticaColors.basicButtonColor(): Color {
|
||||
return colorResource(R.color.gray700_gray10)
|
||||
}
|
||||
|
||||
val HabiticaTheme.colors: HabiticaColors
|
||||
@Composable
|
||||
get() {
|
||||
val context = LocalContext.current
|
||||
return HabiticaColors(
|
||||
windowBackground = Color(context.getThemeColor(R.attr.colorWindowBackground)),
|
||||
contentBackground = Color(context.getThemeColor(R.attr.colorContentBackground)),
|
||||
contentBackgroundOffset = Color(context.getThemeColor(R.attr.colorContentBackgroundOffset)),
|
||||
offsetBackground = Color(context.getThemeColor(R.attr.colorOffsetBackground)),
|
||||
textPrimary = Color(context.getThemeColor(R.attr.textColorPrimary)),
|
||||
textSecondary = Color(context.getThemeColor(R.attr.textColorSecondary)),
|
||||
textTertiary = Color(ContextCompat.getColor(context, R.color.text_ternary)),
|
||||
textQuad = Color(ContextCompat.getColor(context, R.color.text_quad)),
|
||||
textDimmed = Color(ContextCompat.getColor(context, R.color.text_dimmed)),
|
||||
tintedUiMain = Color(context.getThemeColor(R.attr.tintedUiMain)),
|
||||
tintedUiSub = Color(context.getThemeColor(R.attr.tintedUiSub)),
|
||||
tintedUiDetails = Color(context.getThemeColor(R.attr.tintedUiDetails)),
|
||||
pixelArtBackground = Color(context.getThemeColor(R.attr.colorContentBackground)),
|
||||
errorBackground = Color(ContextCompat.getColor(context, R.color.background_red)),
|
||||
errorColor = Color(ContextCompat.getColor(context, R.color.text_red)),
|
||||
successBackground = Color(ContextCompat.getColor(context, R.color.background_green)),
|
||||
successColor = Color(ContextCompat.getColor(context, R.color.text_green))
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ open class NotificationsViewModel @Inject constructor(
|
|||
)
|
||||
|
||||
private var party: UserParty? = null
|
||||
private var hasStats = false
|
||||
|
||||
private val customNotifications = MutableStateFlow<List<Notification>>(emptyList())
|
||||
|
||||
|
|
@ -63,6 +64,7 @@ open class NotificationsViewModel @Inject constructor(
|
|||
userViewModel.user.observeForever {
|
||||
if (it == null) return@observeForever
|
||||
party = it.party
|
||||
hasStats = it.hasClass
|
||||
val notifications = convertInvitationsToNotifications(it)
|
||||
if (it.flags?.newStuff == true) {
|
||||
val notification = Notification()
|
||||
|
|
@ -89,7 +91,11 @@ open class NotificationsViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
fun getNotificationCount(): Flow<Int> {
|
||||
return getNotifications().map { it.count() }.distinctUntilChanged()
|
||||
return getNotifications().map {
|
||||
it.count { notification ->
|
||||
(notification.type != Notification.Type.UNALLOCATED_STATS_POINTS.type) || hasStats
|
||||
}
|
||||
}.distinctUntilChanged()
|
||||
}
|
||||
|
||||
fun allNotificationsSeen(): Flow<Boolean> {
|
||||
|
|
|
|||
|
|
@ -62,7 +62,11 @@ import com.habitrpg.android.habitica.models.user.Purchases
|
|||
import com.habitrpg.android.habitica.models.user.Stats
|
||||
import com.habitrpg.android.habitica.models.user.SubscriptionPlan
|
||||
import com.habitrpg.android.habitica.models.user.User
|
||||
import com.habitrpg.android.habitica.ui.theme.HabiticaTheme
|
||||
import com.habitrpg.android.habitica.ui.theme.basicButtonColor
|
||||
import com.habitrpg.android.habitica.ui.theme.basicTextColor
|
||||
import com.habitrpg.android.habitica.ui.theme.colors
|
||||
import com.habitrpg.common.habitica.theme.HabiticaTheme
|
||||
import com.habitrpg.common.habitica.views.ComposableAvatarView
|
||||
import com.habitrpg.shared.habitica.models.Avatar
|
||||
import kotlin.random.Random
|
||||
|
||||
|
|
|
|||
|
|
@ -32,7 +32,8 @@ import androidx.compose.ui.unit.dp
|
|||
import androidx.fragment.app.Fragment
|
||||
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
||||
import com.habitrpg.android.habitica.R
|
||||
import com.habitrpg.android.habitica.ui.theme.HabiticaTheme
|
||||
import com.habitrpg.android.habitica.ui.theme.colors
|
||||
import com.habitrpg.common.habitica.theme.HabiticaTheme
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
|
|
|
|||
|
|
@ -33,7 +33,9 @@ import com.habitrpg.android.habitica.models.social.Group
|
|||
import com.habitrpg.android.habitica.models.user.Authentication
|
||||
import com.habitrpg.android.habitica.models.user.Profile
|
||||
import com.habitrpg.android.habitica.models.user.Stats
|
||||
import com.habitrpg.android.habitica.ui.theme.HabiticaTheme
|
||||
import com.habitrpg.android.habitica.ui.theme.colors
|
||||
import com.habitrpg.common.habitica.theme.HabiticaTheme
|
||||
import com.habitrpg.common.habitica.views.ComposableAvatarView
|
||||
import kotlin.random.Random
|
||||
|
||||
@Composable
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ import androidx.compose.ui.text.font.FontWeight
|
|||
import androidx.compose.ui.unit.TextUnit
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.habitrpg.android.habitica.ui.theme.HabiticaTheme
|
||||
import com.habitrpg.common.habitica.theme.HabiticaTheme
|
||||
|
||||
@Composable
|
||||
fun HabiticaButton(
|
||||
|
|
|
|||
|
|
@ -42,7 +42,8 @@ import androidx.compose.ui.unit.Dp
|
|||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.habitrpg.android.habitica.R
|
||||
import com.habitrpg.android.habitica.ui.theme.HabiticaTheme
|
||||
import com.habitrpg.android.habitica.ui.theme.colors
|
||||
import com.habitrpg.common.habitica.theme.HabiticaTheme
|
||||
import com.habitrpg.common.habitica.helpers.NumberAbbreviator
|
||||
import java.text.NumberFormat
|
||||
|
||||
|
|
|
|||
|
|
@ -51,7 +51,8 @@ import androidx.compose.ui.tooling.preview.Preview
|
|||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.habitrpg.android.habitica.R
|
||||
import com.habitrpg.android.habitica.ui.theme.HabiticaTheme
|
||||
import com.habitrpg.android.habitica.ui.theme.colors
|
||||
import com.habitrpg.common.habitica.theme.HabiticaTheme
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import androidx.compose.ui.graphics.Color
|
|||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.habitrpg.common.habitica.views.ComposableAvatarView
|
||||
import com.habitrpg.shared.habitica.models.Avatar
|
||||
|
||||
@Composable
|
||||
|
|
|
|||
|
|
@ -1,19 +1,40 @@
|
|||
package com.habitrpg.android.habitica.ui.views.dialogs
|
||||
|
||||
import android.content.Context
|
||||
import com.habitrpg.android.habitica.R
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.ComposeView
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import androidx.lifecycle.setViewTreeLifecycleOwner
|
||||
import androidx.savedstate.setViewTreeSavedStateRegistryOwner
|
||||
import com.habitrpg.common.habitica.theme.HabiticaTheme
|
||||
import com.habitrpg.common.habitica.views.HabiticaCircularProgressView
|
||||
import com.habitrpg.common.habitica.extensions.dpToPx
|
||||
|
||||
class HabiticaProgressDialog(context: Context) : HabiticaAlertDialog(context) {
|
||||
|
||||
companion object {
|
||||
fun show(context: Context, titleID: Int): HabiticaProgressDialog {
|
||||
fun show(context: FragmentActivity, titleID: Int): HabiticaProgressDialog {
|
||||
return show(context, context.getString(titleID))
|
||||
}
|
||||
|
||||
fun show(context: Context, title: String?, dialogWidth: Int = 300): HabiticaProgressDialog {
|
||||
fun show(context: FragmentActivity, title: String?, dialogWidth: Int = 300): HabiticaProgressDialog {
|
||||
val dialog = HabiticaProgressDialog(context)
|
||||
dialog.setAdditionalContentView(R.layout.circular_progress)
|
||||
val composeView = ComposeView(context)
|
||||
dialog.setAdditionalContentView(composeView)
|
||||
composeView.setContent {
|
||||
HabiticaTheme {
|
||||
HabiticaCircularProgressView(Modifier.size(60.dp))
|
||||
}
|
||||
}
|
||||
dialog.window?.let {
|
||||
dialog.additionalContentView?.setViewTreeSavedStateRegistryOwner(context)
|
||||
it.decorView.setViewTreeSavedStateRegistryOwner(context)
|
||||
dialog.additionalContentView?.setViewTreeLifecycleOwner(context)
|
||||
it.decorView.setViewTreeLifecycleOwner(context)
|
||||
}
|
||||
dialog.dialogWidth = dialogWidth.dpToPx(context)
|
||||
dialog.setTitle(title)
|
||||
dialog.enqueue()
|
||||
|
|
|
|||
|
|
@ -26,8 +26,10 @@ import androidx.compose.ui.unit.dp
|
|||
import com.habitrpg.android.habitica.R
|
||||
import com.habitrpg.android.habitica.models.user.Outfit
|
||||
import com.habitrpg.android.habitica.models.user.Preferences
|
||||
import com.habitrpg.android.habitica.ui.theme.HabiticaTheme
|
||||
import com.habitrpg.android.habitica.ui.theme.caption2
|
||||
import com.habitrpg.android.habitica.ui.theme.colors
|
||||
import com.habitrpg.android.habitica.ui.theme.pixelArtBackground
|
||||
import com.habitrpg.common.habitica.theme.HabiticaTheme
|
||||
import com.habitrpg.common.habitica.theme.caption2
|
||||
import com.habitrpg.android.habitica.ui.views.PixelArtView
|
||||
|
||||
@Composable
|
||||
|
|
|
|||
|
|
@ -14,7 +14,8 @@ import androidx.compose.ui.text.style.TextAlign
|
|||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.habitrpg.android.habitica.R
|
||||
import com.habitrpg.android.habitica.ui.theme.HabiticaTheme
|
||||
import com.habitrpg.android.habitica.ui.theme.colors
|
||||
import com.habitrpg.common.habitica.theme.HabiticaTheme
|
||||
import com.habitrpg.android.habitica.ui.views.HabiticaButton
|
||||
|
||||
@Composable
|
||||
|
|
|
|||
|
|
@ -23,7 +23,9 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.habitrpg.android.habitica.ui.theme.HabiticaTheme
|
||||
import com.habitrpg.android.habitica.ui.theme.colors
|
||||
import com.habitrpg.common.habitica.theme.HabiticaTheme
|
||||
import com.habitrpg.common.habitica.views.HabiticaCircularProgressView
|
||||
import java.lang.Float.min
|
||||
|
||||
@OptIn(ExperimentalMaterialApi::class)
|
||||
|
|
|
|||
|
|
@ -380,10 +380,7 @@ class PurchaseDialog(
|
|||
}
|
||||
parentActivity?.let { activity -> subscriptionBottomSheet.show(activity.supportFragmentManager, SubscriptionBottomSheetFragment.TAG) }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,9 +35,10 @@ import com.habitrpg.android.habitica.models.user.ContributorInfo
|
|||
import com.habitrpg.android.habitica.models.user.Profile
|
||||
import com.habitrpg.android.habitica.models.user.Stats
|
||||
import com.habitrpg.android.habitica.ui.fragments.social.party.InviteButton
|
||||
import com.habitrpg.android.habitica.ui.theme.HabiticaTheme
|
||||
import com.habitrpg.android.habitica.ui.theme.colors
|
||||
import com.habitrpg.common.habitica.theme.HabiticaTheme
|
||||
import com.habitrpg.android.habitica.ui.views.ClassText
|
||||
import com.habitrpg.android.habitica.ui.views.ComposableAvatarView
|
||||
import com.habitrpg.common.habitica.views.ComposableAvatarView
|
||||
import com.habitrpg.android.habitica.ui.views.ComposableUsernameLabel
|
||||
import com.habitrpg.android.habitica.ui.views.LoadingButtonState
|
||||
import com.habitrpg.common.habitica.extensions.toLocale
|
||||
|
|
|
|||
|
|
@ -49,7 +49,8 @@ import androidx.compose.ui.unit.sp
|
|||
import androidx.compose.ui.zIndex
|
||||
import com.habitrpg.android.habitica.R
|
||||
import com.habitrpg.android.habitica.interactors.ShareMountUseCase
|
||||
import com.habitrpg.android.habitica.ui.theme.HabiticaTheme
|
||||
import com.habitrpg.android.habitica.ui.theme.colors
|
||||
import com.habitrpg.common.habitica.theme.HabiticaTheme
|
||||
import com.habitrpg.android.habitica.ui.views.BackgroundScene
|
||||
import com.habitrpg.android.habitica.ui.views.HabiticaButton
|
||||
import com.habitrpg.common.habitica.helpers.launchCatching
|
||||
|
|
|
|||
|
|
@ -69,7 +69,8 @@ import com.habitrpg.android.habitica.interactors.ShareMountUseCase
|
|||
import com.habitrpg.android.habitica.interactors.SharePetUseCase
|
||||
import com.habitrpg.android.habitica.models.inventory.Food
|
||||
import com.habitrpg.android.habitica.models.inventory.Pet
|
||||
import com.habitrpg.android.habitica.ui.theme.HabiticaTheme
|
||||
import com.habitrpg.android.habitica.ui.theme.colors
|
||||
import com.habitrpg.common.habitica.theme.HabiticaTheme
|
||||
import com.habitrpg.android.habitica.ui.views.BackgroundScene
|
||||
import com.habitrpg.android.habitica.ui.views.HabiticaButton
|
||||
import com.habitrpg.android.habitica.ui.views.PixelArtView
|
||||
|
|
|
|||
|
|
@ -27,7 +27,8 @@ import androidx.compose.ui.unit.dp
|
|||
import androidx.compose.ui.unit.sp
|
||||
import com.habitrpg.android.habitica.R
|
||||
import com.habitrpg.android.habitica.models.Assignable
|
||||
import com.habitrpg.android.habitica.ui.theme.HabiticaTheme
|
||||
import com.habitrpg.android.habitica.ui.theme.colors
|
||||
import com.habitrpg.common.habitica.theme.HabiticaTheme
|
||||
import com.habitrpg.android.habitica.ui.views.CompletedAt
|
||||
import com.habitrpg.android.habitica.ui.views.UserRow
|
||||
import java.util.Date
|
||||
|
|
|
|||
|
|
@ -39,7 +39,8 @@ import androidx.compose.ui.tooling.preview.Preview
|
|||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.habitrpg.android.habitica.R
|
||||
import com.habitrpg.android.habitica.ui.theme.HabiticaTheme
|
||||
import com.habitrpg.android.habitica.ui.theme.colors
|
||||
import com.habitrpg.common.habitica.theme.HabiticaTheme
|
||||
import com.habitrpg.common.habitica.extensions.getThemeColor
|
||||
|
||||
@Composable
|
||||
|
|
|
|||
|
|
@ -41,7 +41,8 @@ import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
|||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.habitrpg.android.habitica.R
|
||||
import com.habitrpg.android.habitica.ui.theme.HabiticaTheme
|
||||
import com.habitrpg.android.habitica.ui.theme.colors
|
||||
import com.habitrpg.common.habitica.theme.HabiticaTheme
|
||||
import com.habitrpg.android.habitica.ui.views.HabiticaIconsHelper
|
||||
import com.habitrpg.common.habitica.extensions.getThemeColor
|
||||
import com.habitrpg.common.habitica.extensions.nameRes
|
||||
|
|
|
|||
|
|
@ -33,7 +33,8 @@ import androidx.compose.ui.unit.Dp
|
|||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.habitrpg.android.habitica.R
|
||||
import com.habitrpg.android.habitica.ui.theme.HabiticaTheme
|
||||
import com.habitrpg.android.habitica.ui.theme.colors
|
||||
import com.habitrpg.common.habitica.theme.HabiticaTheme
|
||||
import com.habitrpg.common.habitica.extensions.getThemeColor
|
||||
|
||||
data class LabeledValue<V>(val label: String, val value: V)
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ buildscript {
|
|||
amplitude_version = '1.6.1'
|
||||
appcompat_version = '1.6.1'
|
||||
coil_version = '2.4.0'
|
||||
compose_version = '1.5.2'
|
||||
compose_version = '1.5.4'
|
||||
core_ktx_version = '1.12.0'
|
||||
coroutines_version = '1.7.2'
|
||||
daggerhilt_version = '2.47'
|
||||
|
|
@ -25,7 +25,7 @@ buildscript {
|
|||
markwon_version = '4.6.2'
|
||||
mockk_version = '1.13.4'
|
||||
moshi_version = '1.15.0'
|
||||
navigation_version = '2.7.3'
|
||||
navigation_version = '2.7.4'
|
||||
okhttp_version = '4.11.0'
|
||||
paging_version = '3.2.1'
|
||||
play_wearables_version = '18.1.0'
|
||||
|
|
|
|||
|
|
@ -37,6 +37,11 @@ android {
|
|||
|
||||
buildFeatures {
|
||||
viewBinding = true
|
||||
compose = true
|
||||
}
|
||||
|
||||
composeOptions {
|
||||
kotlinCompilerExtensionVersion = "1.5.3"
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
|
|
@ -84,7 +89,9 @@ android {
|
|||
}
|
||||
|
||||
val core_ktx_version: String by rootExtra
|
||||
val accompanist_version: String by rootExtra
|
||||
val appcompat_version: String by rootExtra
|
||||
val compose_version: String by rootExtra
|
||||
val markwon_version: String by rootExtra
|
||||
val coil_version: String by rootExtra
|
||||
val mockk_version: String by rootExtra
|
||||
|
|
@ -111,7 +118,7 @@ dependencies {
|
|||
implementation("androidx.recyclerview:recyclerview:1.3.1")
|
||||
implementation("androidx.navigation:navigation-common-ktx:$navigation_version")
|
||||
implementation("androidx.navigation:navigation-runtime-ktx:$navigation_version")
|
||||
implementation("com.google.android.material:material:1.9.0")
|
||||
implementation("com.google.android.material:material:1.10.0")
|
||||
|
||||
testImplementation("io.mockk:mockk:$mockk_version")
|
||||
testImplementation("io.mockk:mockk-android:$mockk_version")
|
||||
|
|
@ -124,6 +131,15 @@ dependencies {
|
|||
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
|
||||
androidTestImplementation("org.jetbrains.kotlin:kotlin-reflect:$kotlin_version")
|
||||
|
||||
implementation("androidx.activity:activity-compose:1.8.0")
|
||||
implementation("androidx.compose.runtime:runtime-livedata:$compose_version")
|
||||
implementation("androidx.compose.material:material:$compose_version")
|
||||
implementation("androidx.compose.animation:animation:$compose_version")
|
||||
implementation("androidx.compose.ui:ui-text-google-fonts:$compose_version")
|
||||
implementation("androidx.compose.ui:ui-tooling:$compose_version")
|
||||
implementation("androidx.compose.material3:material3:1.1.2")
|
||||
implementation("com.google.accompanist:accompanist-themeadapter-material:$accompanist_version")
|
||||
|
||||
implementation(project(":shared"))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,12 +4,18 @@ import android.view.View
|
|||
import android.view.ViewGroup
|
||||
import android.view.animation.AlphaAnimation
|
||||
import android.widget.ProgressBar
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.ComposeView
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.habitrpg.android.habitica.extensions.inflate
|
||||
import com.habitrpg.common.habitica.R
|
||||
import com.habitrpg.common.habitica.databinding.EmptyItemBinding
|
||||
import com.habitrpg.common.habitica.databinding.FailedItemBinding
|
||||
import com.habitrpg.common.habitica.theme.HabiticaTheme
|
||||
import com.habitrpg.common.habitica.views.HabiticaCircularProgressView
|
||||
|
||||
data class EmptyItem(
|
||||
var title: String,
|
||||
|
|
@ -87,7 +93,12 @@ class RecyclerViewStateAdapter(val showLoadingAsEmpty: Boolean = false) : Recycl
|
|||
animation1.duration = 300
|
||||
animation1.startOffset = 500
|
||||
animation1.fillAfter = true
|
||||
view.findViewById<ProgressBar>(R.id.loading_indicator).startAnimation(animation1)
|
||||
view.findViewById<ComposeView>(R.id.compose_view).startAnimation(animation1)
|
||||
view.findViewById<ComposeView>(R.id.compose_view).setContent {
|
||||
HabiticaTheme {
|
||||
HabiticaCircularProgressView(Modifier.size(60.dp))
|
||||
}
|
||||
}
|
||||
object : RecyclerView.ViewHolder(view) {}
|
||||
}
|
||||
1 -> FailedViewHolder(parent.inflate(R.layout.failed_item))
|
||||
|
|
|
|||
|
|
@ -0,0 +1,146 @@
|
|||
package com.habitrpg.common.habitica.theme
|
||||
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Shapes
|
||||
import androidx.compose.material.Typography
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalLayoutDirection
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.font.FontFamily
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.google.accompanist.themeadapter.material.createMdcTheme
|
||||
|
||||
@Composable
|
||||
fun HabiticaTheme(
|
||||
content: @Composable () -> Unit
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val layoutDirection = LocalLayoutDirection.current
|
||||
val (colors, _, _) = createMdcTheme(
|
||||
context = context,
|
||||
layoutDirection = layoutDirection,
|
||||
setTextColors = true
|
||||
)
|
||||
MaterialTheme(
|
||||
colors = colors ?: MaterialTheme.colors,
|
||||
typography = Typography(
|
||||
defaultFontFamily = FontFamily.Default,
|
||||
h1 = TextStyle(
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 20.sp,
|
||||
letterSpacing = (0.05).sp
|
||||
),
|
||||
h2 = TextStyle(
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 28.sp,
|
||||
letterSpacing = (0.05).sp
|
||||
),
|
||||
subtitle1 = TextStyle(
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 16.sp
|
||||
),
|
||||
subtitle2 = TextStyle(
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 16.sp,
|
||||
letterSpacing = 0.1.sp
|
||||
),
|
||||
body1 = TextStyle(
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 14.sp,
|
||||
letterSpacing = 0.35.sp,
|
||||
lineHeight = 16.sp
|
||||
),
|
||||
body2 = TextStyle(
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 14.sp,
|
||||
letterSpacing = 0.2.sp,
|
||||
lineHeight = 16.sp
|
||||
),
|
||||
button = TextStyle(
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 14.sp,
|
||||
letterSpacing = 1.25.sp
|
||||
),
|
||||
caption = TextStyle(
|
||||
fontWeight = FontWeight.Bold,
|
||||
fontSize = 12.sp
|
||||
),
|
||||
overline = TextStyle(
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 10.sp,
|
||||
letterSpacing = 1.5.sp
|
||||
)
|
||||
),
|
||||
shapes = Shapes(
|
||||
RoundedCornerShape(4.dp),
|
||||
RoundedCornerShape(8.dp),
|
||||
RoundedCornerShape(12.dp)
|
||||
),
|
||||
content = content
|
||||
)
|
||||
}
|
||||
|
||||
val Typography.caption1
|
||||
get() = caption
|
||||
val Typography.caption2
|
||||
get() = TextStyle(
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 12.sp,
|
||||
letterSpacing = 0.4.sp
|
||||
)
|
||||
val Typography.caption3
|
||||
get() = TextStyle(
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 12.sp,
|
||||
letterSpacing = 0.3.sp,
|
||||
lineHeight = 14.sp
|
||||
)
|
||||
val Typography.caption4
|
||||
get() = TextStyle(
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 12.sp,
|
||||
letterSpacing = 0.35.sp
|
||||
)
|
||||
val Typography.subtitle3
|
||||
get() = TextStyle(
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 16.sp,
|
||||
letterSpacing = 0.15.sp
|
||||
)
|
||||
|
||||
object HabiticaTheme {
|
||||
val typography: Typography
|
||||
@Composable
|
||||
get() = MaterialTheme.typography
|
||||
|
||||
val shapes: Shapes
|
||||
@Composable
|
||||
get() = MaterialTheme.shapes
|
||||
}
|
||||
|
||||
class HabiticaColors(
|
||||
val windowBackground: Color,
|
||||
val contentBackground: Color,
|
||||
val contentBackgroundOffset: Color,
|
||||
val offsetBackground: Color,
|
||||
val textPrimary: Color,
|
||||
val textSecondary: Color,
|
||||
val textTertiary: Color,
|
||||
val textQuad: Color,
|
||||
val textDimmed: Color,
|
||||
val tintedUiMain: Color,
|
||||
val tintedUiSub: Color,
|
||||
val tintedUiDetails: Color,
|
||||
val pixelArtBackground: Color,
|
||||
val errorBackground: Color,
|
||||
val errorColor: Color,
|
||||
val successBackground: Color,
|
||||
val successColor: Color
|
||||
)
|
||||
|
||||
class HabiticaTypography
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.habitrpg.android.habitica.ui.views
|
||||
package com.habitrpg.common.habitica.views
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.habitrpg.android.habitica.ui.views.progress
|
||||
package com.habitrpg.common.habitica.views
|
||||
|
||||
import androidx.compose.animation.core.CubicBezierEasing
|
||||
import androidx.compose.animation.core.animateFloat
|
||||
|
|
@ -28,7 +28,7 @@ import androidx.compose.ui.res.colorResource
|
|||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.habitrpg.android.habitica.R
|
||||
import com.habitrpg.common.habitica.R
|
||||
|
||||
@Composable
|
||||
fun HabiticaCircularProgressView(
|
||||
|
|
@ -2,10 +2,10 @@
|
|||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<ProgressBar
|
||||
android:id="@+id/loading_indicator"
|
||||
<androidx.compose.ui.platform.ComposeView
|
||||
android:id="@+id/compose_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
/>
|
||||
</FrameLayout>
|
||||
</FrameLayout>
|
||||
|
|
|
|||
|
|
@ -162,5 +162,14 @@
|
|||
<color name="material_card_background_inverse_color">@color/gray_5</color>
|
||||
<color name="divider_color">@color/gray_500</color>
|
||||
|
||||
<color name="background_red">@color/red_100</color>
|
||||
<color name="background_orange">@color/orange_100</color>
|
||||
<color name="background_yellow">@color/yellow_100</color>
|
||||
<color name="background_green">@color/green_100</color>
|
||||
<color name="background_blue">@color/blue_100</color>
|
||||
<color name="background_teal">@color/teal_100</color>
|
||||
<color name="background_brand">@color/brand_300</color>
|
||||
<color name="background_brand_30">#4D6033B5</color>
|
||||
|
||||
<color name="dim_background">#40BDA8FF</color>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
New in 4.3:
|
||||
It’s easier than ever to party up with our newest feature: Look for Party and Find Members!
|
||||
- Solo players can let Party leaders know they want an invite by going to Menu > Party and tapping ‘Look for Party’
|
||||
- Party leaders can see players looking for Party by tapping ‘Find Members’ on the Party screen and send invites
|
||||
- Can gift Gems by username
|
||||
- Bailey notification will show title
|
||||
- Selecting a class is more consistent
|
||||
- Chat notifications open Party
|
||||
- Other various fixes
|
||||
|
||||
- Pets just got cuter! Tap a Pet or Mount to see them in an environment that changes each month.
|
||||
- Pets bounce when fed
|
||||
- New Subscriber benefit: Buy one Armoire, get another free!
|
||||
- New Subscriber benefit: Get a second chance at life once a day when you run out of HP!
|
||||
- Tap your avatar to share your latest looks at any time
|
||||
- See answers to common Quest mechanic questions under your active Quest
|
||||
- Updated Quest interface
|
||||
- The Quest shop now shows a check by completed Quests
|
||||
|
|
@ -1,2 +1,2 @@
|
|||
NAME=4.3
|
||||
CODE=6681
|
||||
CODE=6731
|
||||
Loading…
Reference in a new issue