diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/api/GSonFactoryCreator.java b/Habitica/src/main/java/com/habitrpg/android/habitica/api/GSonFactoryCreator.java new file mode 100644 index 000000000..5b12a4788 --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/api/GSonFactoryCreator.java @@ -0,0 +1,136 @@ +package com.habitrpg.android.habitica.api; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.reflect.TypeToken; +import com.habitrpg.android.habitica.models.ContentResult; +import com.habitrpg.android.habitica.models.FAQArticle; +import com.habitrpg.android.habitica.models.Skill; +import com.habitrpg.android.habitica.models.Tag; +import com.habitrpg.android.habitica.models.TutorialStep; +import com.habitrpg.android.habitica.models.WorldState; +import com.habitrpg.android.habitica.models.inventory.Customization; +import com.habitrpg.android.habitica.models.inventory.Egg; +import com.habitrpg.android.habitica.models.inventory.Equipment; +import com.habitrpg.android.habitica.models.inventory.Food; +import com.habitrpg.android.habitica.models.inventory.HatchingPotion; +import com.habitrpg.android.habitica.models.inventory.Mount; +import com.habitrpg.android.habitica.models.inventory.Pet; +import com.habitrpg.android.habitica.models.inventory.Quest; +import com.habitrpg.android.habitica.models.inventory.QuestCollect; +import com.habitrpg.android.habitica.models.inventory.QuestContent; +import com.habitrpg.android.habitica.models.inventory.QuestDropItem; +import com.habitrpg.android.habitica.models.responses.FeedResponse; +import com.habitrpg.android.habitica.models.social.Challenge; +import com.habitrpg.android.habitica.models.social.ChatMessage; +import com.habitrpg.android.habitica.models.social.Group; +import com.habitrpg.android.habitica.models.tasks.Task; +import com.habitrpg.android.habitica.models.tasks.TaskList; +import com.habitrpg.android.habitica.models.user.Purchases; +import com.habitrpg.android.habitica.models.user.User; +import com.habitrpg.android.habitica.utils.BooleanAsIntAdapter; +import com.habitrpg.android.habitica.utils.ChallengeDeserializer; +import com.habitrpg.android.habitica.utils.ChallengeListDeserializer; +import com.habitrpg.android.habitica.utils.ChatMessageDeserializer; +import com.habitrpg.android.habitica.utils.ChatMessageListDeserializer; +import com.habitrpg.android.habitica.utils.ContentDeserializer; +import com.habitrpg.android.habitica.utils.CustomizationDeserializer; +import com.habitrpg.android.habitica.utils.DateDeserializer; +import com.habitrpg.android.habitica.utils.EggListDeserializer; +import com.habitrpg.android.habitica.utils.EquipmentListDeserializer; +import com.habitrpg.android.habitica.utils.FAQArticleListDeserilializer; +import com.habitrpg.android.habitica.utils.FeedResponseDeserializer; +import com.habitrpg.android.habitica.utils.FoodListDeserializer; +import com.habitrpg.android.habitica.utils.GroupSerialization; +import com.habitrpg.android.habitica.utils.HatchingPotionListDeserializer; +import com.habitrpg.android.habitica.utils.MemberSerialization; +import com.habitrpg.android.habitica.utils.MountListDeserializer; +import com.habitrpg.android.habitica.utils.MountMapDeserializer; +import com.habitrpg.android.habitica.utils.PetListDeserializer; +import com.habitrpg.android.habitica.utils.PetMapDeserializer; +import com.habitrpg.android.habitica.utils.PurchasedDeserializer; +import com.habitrpg.android.habitica.utils.QuestCollectDeserializer; +import com.habitrpg.android.habitica.utils.QuestDeserializer; +import com.habitrpg.android.habitica.utils.QuestDropItemsListSerialization; +import com.habitrpg.android.habitica.utils.QuestListDeserializer; +import com.habitrpg.android.habitica.utils.SkillDeserializer; +import com.habitrpg.android.habitica.utils.TaskListDeserializer; +import com.habitrpg.android.habitica.utils.TaskSerializer; +import com.habitrpg.android.habitica.utils.TaskTagDeserializer; +import com.habitrpg.android.habitica.utils.TutorialStepListDeserializer; +import com.habitrpg.android.habitica.utils.UserDeserializer; +import com.habitrpg.android.habitica.utils.WorldStateSerialization; + +import java.lang.reflect.Member; +import java.lang.reflect.Type; +import java.util.Date; +import java.util.List; +import java.util.Map; + +import io.realm.RealmList; +import retrofit2.converter.gson.GsonConverterFactory; + +public class GSonFactoryCreator { + + public static GsonConverterFactory create() { + Type taskTagClassListType = new TypeToken>() {}.getType(); + Type skillListType = new TypeToken>() {}.getType(); + Type customizationListType = new TypeToken>() {}.getType(); + Type tutorialStepListType = new TypeToken>() {}.getType(); + Type faqArticleListType = new TypeToken>() {}.getType(); + Type itemDataListType = new TypeToken>() {}.getType(); + Type eggListType = new TypeToken>() {}.getType(); + Type foodListType = new TypeToken>() {}.getType(); + Type hatchingPotionListType = new TypeToken>() {}.getType(); + Type questContentListType = new TypeToken>() {}.getType(); + Type petMapType = new TypeToken>() {}.getType(); + Type mountMapType = new TypeToken>() {}.getType(); + Type petListType = new TypeToken>() {}.getType(); + Type mountListType = new TypeToken>() {}.getType(); + Type questCollectListType = new TypeToken>() {}.getType(); + Type chatMessageListType = new TypeToken>() {}.getType(); + Type challengeListType = new TypeToken>() {}.getType(); + Type challengeRealmListType = new TypeToken>() {}.getType(); + Type questDropItemListType = new TypeToken>() {}.getType(); + + //Exclusion strategy needed for DBFlow https://github.com/Raizlabs/DBFlow/issues/121 + Gson gson = new GsonBuilder() + .registerTypeAdapter(taskTagClassListType, new TaskTagDeserializer()) + .registerTypeAdapter(Boolean.class, new BooleanAsIntAdapter()) + .registerTypeAdapter(boolean.class, new BooleanAsIntAdapter()) + .registerTypeAdapter(skillListType, new SkillDeserializer()) + .registerTypeAdapter(TaskList.class, new TaskListDeserializer()) + .registerTypeAdapter(Purchases.class, new PurchasedDeserializer()) + .registerTypeAdapter(customizationListType, new CustomizationDeserializer()) + .registerTypeAdapter(tutorialStepListType, new TutorialStepListDeserializer()) + .registerTypeAdapter(faqArticleListType, new FAQArticleListDeserilializer()) + .registerTypeAdapter(Group.class, new GroupSerialization()) + .registerTypeAdapter(Date.class, new DateDeserializer()) + .registerTypeAdapter(itemDataListType, new EquipmentListDeserializer()) + .registerTypeAdapter(eggListType, new EggListDeserializer()) + .registerTypeAdapter(foodListType, new FoodListDeserializer()) + .registerTypeAdapter(hatchingPotionListType, new HatchingPotionListDeserializer()) + .registerTypeAdapter(questContentListType, new QuestListDeserializer()) + .registerTypeAdapter(petListType, new PetListDeserializer()) + .registerTypeAdapter(mountListType, new MountListDeserializer()) + .registerTypeAdapter(petMapType, new PetMapDeserializer()) + .registerTypeAdapter(mountMapType, new MountMapDeserializer()) + .registerTypeAdapter(ChatMessage.class, new ChatMessageDeserializer()) + .registerTypeAdapter(Task.class, new TaskSerializer()) + .registerTypeAdapter(ContentResult.class, new ContentDeserializer()) + .registerTypeAdapter(FeedResponse.class, new FeedResponseDeserializer()) + .registerTypeAdapter(Challenge.class, new ChallengeDeserializer()) + .registerTypeAdapter(User.class, new UserDeserializer()) + .registerTypeAdapter(questCollectListType, new QuestCollectDeserializer()) + .registerTypeAdapter(chatMessageListType, new ChatMessageListDeserializer()) + .registerTypeAdapter(challengeListType, new ChallengeListDeserializer()) + .registerTypeAdapter(challengeRealmListType, new ChallengeListDeserializer()) + .registerTypeAdapter(questDropItemListType, new QuestDropItemsListSerialization()) + .registerTypeAdapter(Quest.class, new QuestDeserializer()) + .registerTypeAdapter(Member.class, new MemberSerialization()) + .registerTypeAdapter(WorldState.class, new WorldStateSerialization()) + .setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'") + .create(); + return GsonConverterFactory.create(gson); + } +} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/ApiClientImpl.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/ApiClientImpl.kt index 3b7b706f1..a45a7b20b 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/ApiClientImpl.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/ApiClientImpl.kt @@ -11,6 +11,7 @@ import com.habitrpg.android.habitica.BuildConfig import com.habitrpg.android.habitica.HabiticaBaseApplication import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.api.ApiService +import com.habitrpg.android.habitica.api.GSonFactoryCreator import com.habitrpg.android.habitica.api.HostConfig import com.habitrpg.android.habitica.api.Server import com.habitrpg.android.habitica.data.ApiClient @@ -686,103 +687,7 @@ class ApiClientImpl//private OnHabitsAPIResult mResultListener; private const val TAG = "ApiClientImpl" fun createGsonFactory(): GsonConverterFactory { - val taskTagClassListType = object : TypeToken>() { - - }.type - val skillListType = object : TypeToken>() { - - }.type - val customizationListType = object : TypeToken>() { - - }.type - val tutorialStepListType = object : TypeToken>() { - - }.type - val faqArticleListType = object : TypeToken>() { - - }.type - val itemDataListType = object : TypeToken>() { - - }.type - val eggListType = object : TypeToken>() { - - }.type - val foodListType = object : TypeToken>() { - - }.type - val hatchingPotionListType = object : TypeToken>() { - - }.type - val questContentListType = object : TypeToken>() { - - }.type - val petMapType = object : TypeToken>() { - - }.type - val mountMapType = object : TypeToken>() { - - }.type - val petListType = object : TypeToken>() { - - }.type - val mountListType = object : TypeToken>() { - - }.type - val questCollectListType = object : TypeToken>() { - - }.type - val chatMessageListType = object : TypeToken>() { - - }.type - val challengeListType = object : TypeToken>() { - - }.type - val challengeRealmListType = object : TypeToken>() { - - }.type - val questDropItemListType = object : TypeToken>() { - - }.type - - //Exclusion strategy needed for DBFlow https://github.com/Raizlabs/DBFlow/issues/121 - val gson = GsonBuilder() - .registerTypeAdapter(taskTagClassListType, TaskTagDeserializer()) - .registerTypeAdapter(Boolean::class.java, BooleanAsIntAdapter()) - .registerTypeAdapter(Boolean::class.javaPrimitiveType, BooleanAsIntAdapter()) - .registerTypeAdapter(skillListType, SkillDeserializer()) - .registerTypeAdapter(TaskList::class.java, TaskListDeserializer()) - .registerTypeAdapter(Purchases::class.java, PurchasedDeserializer()) - .registerTypeAdapter(customizationListType, CustomizationDeserializer()) - .registerTypeAdapter(tutorialStepListType, TutorialStepListDeserializer()) - .registerTypeAdapter(faqArticleListType, FAQArticleListDeserilializer()) - .registerTypeAdapter(Group::class.java, GroupSerialization()) - .registerTypeAdapter(Date::class.java, DateDeserializer()) - .registerTypeAdapter(itemDataListType, EquipmentListDeserializer()) - .registerTypeAdapter(eggListType, EggListDeserializer()) - .registerTypeAdapter(foodListType, FoodListDeserializer()) - .registerTypeAdapter(hatchingPotionListType, HatchingPotionListDeserializer()) - .registerTypeAdapter(questContentListType, QuestListDeserializer()) - .registerTypeAdapter(petListType, PetListDeserializer()) - .registerTypeAdapter(mountListType, MountListDeserializer()) - .registerTypeAdapter(petMapType, PetMapDeserializer()) - .registerTypeAdapter(mountMapType, MountMapDeserializer()) - .registerTypeAdapter(ChatMessage::class.java, ChatMessageDeserializer()) - .registerTypeAdapter(Task::class.java, TaskSerializer()) - .registerTypeAdapter(ContentResult::class.java, ContentDeserializer()) - .registerTypeAdapter(FeedResponse::class.java, FeedResponseDeserializer()) - .registerTypeAdapter(Challenge::class.java, ChallengeDeserializer()) - .registerTypeAdapter(User::class.java, UserDeserializer()) - .registerTypeAdapter(questCollectListType, QuestCollectDeserializer()) - .registerTypeAdapter(chatMessageListType, ChatMessageListDeserializer()) - .registerTypeAdapter(challengeListType, ChallengeListDeserializer()) - .registerTypeAdapter(challengeRealmListType, ChallengeListDeserializer()) - .registerTypeAdapter(questDropItemListType, QuestDropItemsListSerialization()) - .registerTypeAdapter(Quest::class.java, QuestDeserializer()) - .registerTypeAdapter(Member::class.java, MemberSerialization()) - .registerTypeAdapter(WorldState::class.java, WorldStateSerialization()) - .setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'") - .create() - return GsonConverterFactory.create(gson) + return GSonFactoryCreator.create() } } } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/extensions/AlertDialog-Extensions.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/extensions/AlertDialog-Extensions.kt index 89a0eb1b1..8bb8b534a 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/extensions/AlertDialog-Extensions.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/extensions/AlertDialog-Extensions.kt @@ -1,7 +1,10 @@ package com.habitrpg.android.habitica.extensions import android.app.AlertDialog +import android.app.Dialog import android.content.DialogInterface +import android.support.annotation.IdRes +import android.view.View import com.habitrpg.android.habitica.R public fun AlertDialog.Builder.setOkButton(listener: ((DialogInterface, Int) -> Unit)? = null): AlertDialog.Builder { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/extensions/ViewExt.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/extensions/ViewExt.kt index 0043f0201..29850e195 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/extensions/ViewExt.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/extensions/ViewExt.kt @@ -11,11 +11,6 @@ fun View.setScaledPadding(context: Context?, left: Int, top: Int, right: Int, bo this.setPadding(left.dpToPx(context), top.dpToPx(context), right.dpToPx(context), bottom.dpToPx(context)) } -fun View.bindView(@IdRes res: Int) : Lazy { - @Suppress("UNCHECKED_CAST") - return lazy(LazyThreadSafetyMode.NONE) { findViewById(res) } -} - var T.backgroundCompat: Drawable? get() { return background diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/extensions/ViewHolder-Extensions.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/extensions/ViewHolder-Extensions.kt deleted file mode 100644 index e5b015b31..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/extensions/ViewHolder-Extensions.kt +++ /dev/null @@ -1,22 +0,0 @@ -package com.habitrpg.android.habitica.extensions - -import android.content.Context -import android.support.annotation.ColorRes -import android.support.annotation.IdRes -import android.support.v4.content.ContextCompat -import android.view.View - -fun bindView(container: View, @IdRes res: Int) : Lazy { - @Suppress("UNCHECKED_CAST") - return lazy(LazyThreadSafetyMode.NONE) { container.findViewById(res) } -} - -fun bindOptionalView(container: View?, @IdRes res: Int) : Lazy { - @Suppress("UNCHECKED_CAST") - return lazy(LazyThreadSafetyMode.NONE) { container?.findViewById(res) } -} - -fun bindColor(context: Context, @ColorRes res: Int) : Lazy { - @Suppress("UNCHECKED_CAST") - return lazy(LazyThreadSafetyMode.NONE) { ContextCompat.getColor(context, res) } -} \ No newline at end of file diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/TaskGroupPlan.java b/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/TaskGroupPlan.java index f03dddbbb..e2acdb96d 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/TaskGroupPlan.java +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/TaskGroupPlan.java @@ -9,5 +9,7 @@ public class TaskGroupPlan extends RealmObject { @PrimaryKey String task_id; - public boolean approvalRequested, approvalApproved, approvalRequired; + public boolean approvalRequested; + public boolean approvalApproved; + public boolean approvalRequired; } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/AvatarWithBarsViewModel.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/AvatarWithBarsViewModel.kt index f680d885f..da27bad44 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/AvatarWithBarsViewModel.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/AvatarWithBarsViewModel.kt @@ -11,11 +11,11 @@ import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.events.BoughtGemsEvent import com.habitrpg.android.habitica.events.commands.OpenGemPurchaseFragmentCommand import com.habitrpg.android.habitica.events.commands.OpenMenuItemCommand -import com.habitrpg.android.habitica.extensions.bindView import com.habitrpg.android.habitica.models.Avatar import com.habitrpg.android.habitica.models.user.Stats import com.habitrpg.android.habitica.models.user.User import com.habitrpg.android.habitica.ui.fragments.NavigationDrawerFragment +import com.habitrpg.android.habitica.ui.helpers.bindView import com.habitrpg.android.habitica.ui.views.CurrencyViews import com.habitrpg.android.habitica.ui.views.HabiticaIconsHelper import com.habitrpg.android.habitica.ui.views.ValueBar diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/ChallengeDetailActivity.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/ChallengeDetailActivity.java index ae18d44e1..a5c157f21 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/ChallengeDetailActivity.java +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/ChallengeDetailActivity.java @@ -356,7 +356,7 @@ public class ChallengeDetailActivity extends BaseActivity { if (challengeName != null) { challengeName.setText(EmojiParser.parseEmojis(challenge.name)); } - challengeDescription.setText(MarkdownParser.parseMarkdown(challenge.description)); + challengeDescription.setText(MarkdownParser.INSTANCE.parseMarkdown(challenge.description)); memberCountTextView.setText(String.valueOf(challenge.memberCount)); @@ -370,7 +370,7 @@ public class ChallengeDetailActivity extends BaseActivity { @OnClick(R.id.btn_show_more) void onShowMore() { - ChallengeDetailDialogHolder.showDialog(ChallengeDetailActivity.this, + ChallengeDetailDialogHolder.Companion.showDialog(ChallengeDetailActivity.this, ChallengeDetailActivity.this.challengeRepository, challenge, challenge1 -> ChallengeDetailActivity.this.onBackPressed()); diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/FullProfileActivity.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/FullProfileActivity.java index ff4cd1bb9..ad716e7ae 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/FullProfileActivity.java +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/FullProfileActivity.java @@ -225,7 +225,7 @@ public class FullProfileActivity extends BaseActivity { String blurbText = profile.getBlurb(); if (blurbText != null && !blurbText.isEmpty()) { - blurbTextView.setText(MarkdownParser.parseMarkdown(blurbText)); + blurbTextView.setText(MarkdownParser.INSTANCE.parseMarkdown(blurbText)); } userIdText.setText(userId); copyUserIdButton.setVisibility(View.VISIBLE); diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/GroupFormActivity.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/GroupFormActivity.java index 6b311c32b..9c0dcb502 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/GroupFormActivity.java +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/GroupFormActivity.java @@ -187,7 +187,7 @@ public class GroupFormActivity extends BaseActivity { Intent resultIntent = new Intent(); Bundle bundle = new Bundle(); bundle.putString("name", this.groupNameEditText.getText().toString()); - bundle.putString("description", MarkdownParser.parseCompiled(this.groupDescriptionEditText.getText())); + bundle.putString("description", MarkdownParser.INSTANCE.parseCompiled(this.groupDescriptionEditText.getText())); bundle.putString("leader", this.groupLeader); resultIntent.putExtras(bundle); setResult(Activity.RESULT_OK, resultIntent); diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/MaintenanceActivity.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/MaintenanceActivity.java index d6a302512..e472f2448 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/MaintenanceActivity.java +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/MaintenanceActivity.java @@ -55,7 +55,7 @@ public class MaintenanceActivity extends BaseActivity { this.titleTextView.setText(data.getString("title")); imageView.setImageURI(Uri.parse(data.getString("imageUrl"))); - this.descriptionTextView.setText(MarkdownParser.parseMarkdown(data.getString("description"))); + this.descriptionTextView.setText(MarkdownParser.INSTANCE.parseMarkdown(data.getString("description"))); this.descriptionTextView.setMovementMethod(LinkMovementMethod.getInstance()); isDeprecationNotice = data.getBoolean("deprecationNotice"); diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/PartyInviteActivity.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/PartyInviteActivity.java index f44d265f9..5933f5ca7 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/PartyInviteActivity.java +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/PartyInviteActivity.java @@ -118,7 +118,7 @@ public class PartyInviteActivity extends BaseActivity { public Fragment getItem(int position) { PartyInviteFragment fragment = new PartyInviteFragment(); - fragment.isEmailInvite = position == 0; + fragment.setEmailInvite(position == 0); if (fragments.size() > position) { fragments.set(position, fragment); } else { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/SetupActivity.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/SetupActivity.java index df366e1f7..0a654ce15 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/SetupActivity.java +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/SetupActivity.java @@ -255,9 +255,9 @@ public class SetupActivity extends BaseActivity implements ViewPager.OnPageChang switch (position) { case 1: { avatarSetupFragment = new AvatarSetupFragment(); - avatarSetupFragment.activity = SetupActivity.this; + avatarSetupFragment.setActivity(SetupActivity.this); avatarSetupFragment.setUser(user); - avatarSetupFragment.width = pager.getWidth(); + avatarSetupFragment.setWidth(pager.getWidth()); fragment = avatarSetupFragment; break; } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/TaskFormActivity.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/TaskFormActivity.java index a905ec123..8b27e1b5f 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/TaskFormActivity.java +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/TaskFormActivity.java @@ -1087,7 +1087,7 @@ public class TaskFormActivity extends BaseActivity implements AdapterView.OnItem private boolean saveTask(Task task) { - String text = MarkdownParser.parseCompiled(taskText.getText()); + String text = MarkdownParser.INSTANCE.parseCompiled(taskText.getText()); if (text == null || text.isEmpty()) { return false; } @@ -1099,7 +1099,7 @@ public class TaskFormActivity extends BaseActivity implements AdapterView.OnItem taskRepository.executeTransaction(realm -> { try { task.setText(text); - task.setNotes(MarkdownParser.parseCompiled(taskNotes.getText())); + task.setNotes(MarkdownParser.INSTANCE.parseCompiled(taskNotes.getText())); } catch (IllegalArgumentException ignored) { } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/CustomizationRecyclerViewAdapter.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/CustomizationRecyclerViewAdapter.kt index 87502144d..50fac84fb 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/CustomizationRecyclerViewAdapter.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/CustomizationRecyclerViewAdapter.kt @@ -12,7 +12,7 @@ import android.widget.* import com.facebook.drawee.view.SimpleDraweeView import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.events.commands.OpenMenuItemCommand -import com.habitrpg.android.habitica.extensions.bindView +import com.habitrpg.android.habitica.ui.helpers.bindView import com.habitrpg.android.habitica.extensions.notNull import com.habitrpg.android.habitica.models.inventory.Customization import com.habitrpg.android.habitica.models.inventory.CustomizationSet diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/NavigationDrawerAdapter.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/NavigationDrawerAdapter.kt index acecca657..0a57dabac 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/NavigationDrawerAdapter.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/NavigationDrawerAdapter.kt @@ -8,8 +8,8 @@ import android.view.ViewGroup import android.widget.TextView import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.extensions.backgroundCompat -import com.habitrpg.android.habitica.extensions.bindOptionalView import com.habitrpg.android.habitica.extensions.inflate +import com.habitrpg.android.habitica.ui.helpers.bindOptionalView import com.habitrpg.android.habitica.ui.menu.HabiticaDrawerItem import io.reactivex.BackpressureStrategy import io.reactivex.Flowable diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/inventory/EquipmentRecyclerViewAdapter.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/inventory/EquipmentRecyclerViewAdapter.kt index 6292393bc..77e35fda6 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/inventory/EquipmentRecyclerViewAdapter.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/inventory/EquipmentRecyclerViewAdapter.kt @@ -9,7 +9,7 @@ import android.view.ViewGroup import android.widget.TextView import com.facebook.drawee.view.SimpleDraweeView import com.habitrpg.android.habitica.R -import com.habitrpg.android.habitica.extensions.bindView +import com.habitrpg.android.habitica.ui.helpers.bindView import com.habitrpg.android.habitica.models.inventory.Equipment import com.habitrpg.android.habitica.ui.helpers.DataBindingUtils import io.reactivex.subjects.PublishSubject diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/inventory/ShopRecyclerAdapter.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/inventory/ShopRecyclerAdapter.kt index 1c1171fd9..bc48df65e 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/inventory/ShopRecyclerAdapter.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/inventory/ShopRecyclerAdapter.kt @@ -10,7 +10,7 @@ import android.widget.Button import android.widget.TextView import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.events.commands.OpenGemPurchaseFragmentCommand -import com.habitrpg.android.habitica.extensions.bindView +import com.habitrpg.android.habitica.ui.helpers.bindView import com.habitrpg.android.habitica.extensions.inflate import com.habitrpg.android.habitica.models.inventory.Item import com.habitrpg.android.habitica.models.shops.Shop diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/inventory/StableRecyclerAdapter.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/inventory/StableRecyclerAdapter.kt index 3bcc7fd4b..276f6ae51 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/inventory/StableRecyclerAdapter.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/inventory/StableRecyclerAdapter.kt @@ -7,7 +7,7 @@ import android.view.ViewGroup import android.widget.TextView import com.facebook.drawee.view.SimpleDraweeView import com.habitrpg.android.habitica.R -import com.habitrpg.android.habitica.extensions.bindView +import com.habitrpg.android.habitica.ui.helpers.bindView import com.habitrpg.android.habitica.models.inventory.Animal import com.habitrpg.android.habitica.ui.activities.MainActivity import com.habitrpg.android.habitica.ui.fragments.inventory.stable.MountDetailRecyclerFragment diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/social/ChatRecyclerViewAdapter.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/social/ChatRecyclerViewAdapter.java index a8a2e1813..7a5fe5544 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/social/ChatRecyclerViewAdapter.java +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/social/ChatRecyclerViewAdapter.java @@ -180,7 +180,7 @@ public class ChatRecyclerViewAdapter extends RealmRecyclerViewAdapter { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/BaseFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/BaseFragment.kt index 9cf7d4432..1d39cfb6e 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/BaseFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/BaseFragment.kt @@ -1,13 +1,10 @@ package com.habitrpg.android.habitica.ui.fragments import android.os.Bundle -import android.support.annotation.CallSuper import android.support.v4.app.DialogFragment import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import butterknife.ButterKnife -import butterknife.Unbinder import com.habitrpg.android.habitica.HabiticaApplication import com.habitrpg.android.habitica.HabiticaBaseApplication import com.habitrpg.android.habitica.components.AppComponent @@ -31,7 +28,6 @@ abstract class BaseFragment : DialogFragment() { var tutorialStepIdentifier: String? = null var tutorialText: String? = null - var unbinder: Unbinder? = null protected var tutorialCanBeDeferred = true var tutorialTexts: MutableList = ArrayList() @@ -66,15 +62,6 @@ abstract class BaseFragment : DialogFragment() { abstract fun injectFragment(component: AppComponent) - @CallSuper - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - if (unbinder == null) { - unbinder = ButterKnife.bind(this, view) - } - } - override fun onResume() { super.onResume() showTutorialIfNeeded() @@ -115,10 +102,6 @@ abstract class BaseFragment : DialogFragment() { if (EventBus.getDefault().isRegistered(this)) { EventBus.getDefault().unregister(this) } - if (unbinder != null) { - unbinder!!.unbind() - unbinder = null - } if (!compositeSubscription.isDisposed) { compositeSubscription.dispose() } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/faq/FAQDetailFragment.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/faq/FAQDetailFragment.java deleted file mode 100644 index cb76a87ee..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/faq/FAQDetailFragment.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.habitrpg.android.habitica.ui.fragments.faq; - -import android.os.Bundle; -import android.text.method.LinkMovementMethod; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.TextView; - -import com.habitrpg.android.habitica.R; -import com.habitrpg.android.habitica.components.AppComponent; -import com.habitrpg.android.habitica.models.FAQArticle; -import com.habitrpg.android.habitica.ui.fragments.BaseMainFragment; -import com.habitrpg.android.habitica.ui.helpers.MarkdownParser; - -import butterknife.BindView; -import butterknife.ButterKnife; - -public class FAQDetailFragment extends BaseMainFragment { - @BindView(R.id.questionTextView) - TextView questionTextView; - - @BindView(R.id.answerTextView) - TextView answerTextView; - - private FAQArticle article; - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - super.onCreateView(inflater, container, savedInstanceState); - View view = inflater.inflate(R.layout.fragment_faq_detail, container, false); - - setUnbinder(ButterKnife.bind(this, view)); - - if (this.article != null) { - this.questionTextView.setText(this.article.getQuestion()); - this.answerTextView.setText(MarkdownParser.parseMarkdown(this.article.getAnswer())); - } - this.answerTextView.setMovementMethod(LinkMovementMethod.getInstance()); - return view; - } - - @Override - public void injectFragment(AppComponent component) { - } - - public void setArticle(FAQArticle article) { - this.article = article; - if (this.questionTextView != null) { - this.questionTextView.setText(this.article.getQuestion()); - } - if (this.answerTextView != null) { - this.answerTextView.setText(MarkdownParser.parseMarkdown(this.article.getAnswer())); - } - } -} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/faq/FAQDetailFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/faq/FAQDetailFragment.kt new file mode 100644 index 000000000..d4172348c --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/faq/FAQDetailFragment.kt @@ -0,0 +1,56 @@ +package com.habitrpg.android.habitica.ui.fragments.faq + +import android.os.Bundle +import android.text.method.LinkMovementMethod +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.TextView + +import com.habitrpg.android.habitica.R +import com.habitrpg.android.habitica.components.AppComponent +import com.habitrpg.android.habitica.extensions.inflate +import com.habitrpg.android.habitica.models.FAQArticle +import com.habitrpg.android.habitica.ui.fragments.BaseMainFragment +import com.habitrpg.android.habitica.ui.helpers.MarkdownParser + +import com.habitrpg.android.habitica.ui.helpers.bindView +import com.habitrpg.android.habitica.ui.helpers.resetViews + +class FAQDetailFragment : BaseMainFragment() { + private val questionTextView: TextView? by bindView(R.id.questionTextView) + private val answerTextView: TextView? by bindView(R.id.answerTextView) + + private var article: FAQArticle? = null + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + super.onCreateView(inflater, container, savedInstanceState) + return container?.inflate(R.layout.fragment_faq_detail) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + resetViews() + + if (this.article != null) { + this.questionTextView!!.text = this.article!!.question + //TODO: FIX + this.answerTextView?.text = MarkdownParser.parseMarkdown(article?.answer) + } + this.answerTextView!!.movementMethod = LinkMovementMethod.getInstance() + } + + override fun injectFragment(component: AppComponent) {} + + fun setArticle(article: FAQArticle) { + this.article = article + if (this.questionTextView != null) { + this.questionTextView!!.text = this.article!!.question + } + if (this.answerTextView != null) { + //TODO: FIX + this.answerTextView?.text = MarkdownParser.parseMarkdown(article.answer) + } + } +} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/faq/FAQOverviewFragment.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/faq/FAQOverviewFragment.java deleted file mode 100644 index 5ba340166..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/faq/FAQOverviewFragment.java +++ /dev/null @@ -1,77 +0,0 @@ -package com.habitrpg.android.habitica.ui.fragments.faq; - -import android.os.Bundle; -import android.support.v7.widget.DividerItemDecoration; -import android.support.v7.widget.LinearLayoutManager; -import android.support.v7.widget.RecyclerView; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; - -import com.habitrpg.android.habitica.R; -import com.habitrpg.android.habitica.components.AppComponent; -import com.habitrpg.android.habitica.data.FAQRepository; -import com.habitrpg.android.habitica.helpers.RxErrorHandler; -import com.habitrpg.android.habitica.ui.adapter.FAQOverviewRecyclerAdapter; -import com.habitrpg.android.habitica.ui.fragments.BaseMainFragment; -import com.habitrpg.android.habitica.ui.helpers.SafeDefaultItemAnimator; - -import javax.inject.Inject; - -import butterknife.BindView; -import butterknife.ButterKnife; - -public class FAQOverviewFragment extends BaseMainFragment { - @Inject - FAQRepository faqRepository; - - @BindView(R.id.recyclerView) - RecyclerView recyclerView; - - FAQOverviewRecyclerAdapter adapter; - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - super.onCreateView(inflater, container, savedInstanceState); - View view = inflater.inflate(R.layout.fragment_recyclerview, container, false); - - setUnbinder(ButterKnife.bind(this, view)); - adapter = new FAQOverviewRecyclerAdapter(); - adapter.getResetWalkthroughEvents().subscribe(aVoid -> this.userRepository.resetTutorial(user), RxErrorHandler.handleEmptyError()); - adapter.activity = activity; - recyclerView.setLayoutManager(new LinearLayoutManager(activity)); - recyclerView.addItemDecoration(new DividerItemDecoration(getActivity(), DividerItemDecoration.VERTICAL)); - recyclerView.setAdapter(adapter); - recyclerView.setItemAnimator(new SafeDefaultItemAnimator()); - this.loadArticles(); - - return view; - } - - @Override - public void onDestroy() { - faqRepository.close(); - super.onDestroy(); - } - - @Override - public void injectFragment(AppComponent component) { - component.inject(this); - } - - private void loadArticles() { - if (user == null || adapter == null) { - return; - } - faqRepository.getArticles().subscribe(adapter::setArticles, RxErrorHandler.handleEmptyError()); - } - - @Override - public String customTitle() { - if (!isAdded()) { - return ""; - } - return getString(R.string.FAQ); - } -} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/faq/FAQOverviewFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/faq/FAQOverviewFragment.kt new file mode 100644 index 000000000..c2a24fbcd --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/faq/FAQOverviewFragment.kt @@ -0,0 +1,73 @@ +package com.habitrpg.android.habitica.ui.fragments.faq + +import android.os.Bundle +import android.support.v7.widget.DividerItemDecoration +import android.support.v7.widget.LinearLayoutManager +import android.support.v7.widget.RecyclerView +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import com.habitrpg.android.habitica.R +import com.habitrpg.android.habitica.components.AppComponent +import com.habitrpg.android.habitica.data.FAQRepository +import com.habitrpg.android.habitica.extensions.inflate +import com.habitrpg.android.habitica.helpers.RxErrorHandler +import com.habitrpg.android.habitica.ui.adapter.FAQOverviewRecyclerAdapter +import com.habitrpg.android.habitica.ui.fragments.BaseMainFragment +import com.habitrpg.android.habitica.ui.helpers.SafeDefaultItemAnimator +import com.habitrpg.android.habitica.ui.helpers.bindView +import com.habitrpg.android.habitica.ui.helpers.resetViews +import io.reactivex.functions.Consumer +import javax.inject.Inject + +class FAQOverviewFragment : BaseMainFragment() { + @Inject + lateinit var faqRepository: FAQRepository + + private val recyclerView: RecyclerView? by bindView(R.id.recyclerView) + + internal var adapter: FAQOverviewRecyclerAdapter? = null + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle?): View? { + super.onCreateView(inflater, container, savedInstanceState) + return container?.inflate(R.layout.fragment_recyclerview) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + resetViews() + + adapter = FAQOverviewRecyclerAdapter() + adapter?.resetWalkthroughEvents?.subscribe(Consumer { this.userRepository.resetTutorial(user) }, RxErrorHandler.handleEmptyError()) + adapter?.activity = activity + recyclerView?.layoutManager = LinearLayoutManager(activity) + recyclerView?.addItemDecoration(DividerItemDecoration(getActivity()!!, DividerItemDecoration.VERTICAL)) + recyclerView?.adapter = adapter + recyclerView?.itemAnimator = SafeDefaultItemAnimator() + this.loadArticles() + } + + override fun onDestroy() { + faqRepository.close() + super.onDestroy() + } + + override fun injectFragment(component: AppComponent) { + component.inject(this) + } + + private fun loadArticles() { + if (user == null || adapter == null) { + return + } + faqRepository.articles.subscribe(Consumer { adapter?.setArticles(it) }, RxErrorHandler.handleEmptyError()) + } + + override fun customTitle(): String { + return if (!isAdded) { + "" + } else getString(R.string.FAQ) + } +} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/items/ItemRecyclerFragment.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/items/ItemRecyclerFragment.java deleted file mode 100644 index 3aa06873a..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/items/ItemRecyclerFragment.java +++ /dev/null @@ -1,224 +0,0 @@ -package com.habitrpg.android.habitica.ui.fragments.inventory.items; - -import android.os.Bundle; -import android.support.annotation.Nullable; -import android.support.v7.widget.DividerItemDecoration; -import android.support.v7.widget.LinearLayoutManager; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.view.Window; -import android.widget.Button; -import android.widget.TextView; - -import com.habitrpg.android.habitica.R; -import com.habitrpg.android.habitica.components.AppComponent; -import com.habitrpg.android.habitica.data.InventoryRepository; -import com.habitrpg.android.habitica.events.commands.OpenMenuItemCommand; -import com.habitrpg.android.habitica.helpers.RxErrorHandler; -import com.habitrpg.android.habitica.models.inventory.Egg; -import com.habitrpg.android.habitica.models.inventory.Food; -import com.habitrpg.android.habitica.models.inventory.HatchingPotion; -import com.habitrpg.android.habitica.models.inventory.Item; -import com.habitrpg.android.habitica.models.inventory.Pet; -import com.habitrpg.android.habitica.models.inventory.QuestContent; -import com.habitrpg.android.habitica.models.inventory.SpecialItem; -import com.habitrpg.android.habitica.models.user.User; -import com.habitrpg.android.habitica.ui.adapter.inventory.ItemRecyclerAdapter; -import com.habitrpg.android.habitica.ui.fragments.BaseFragment; -import com.habitrpg.android.habitica.ui.fragments.NavigationDrawerFragment; -import com.habitrpg.android.habitica.ui.helpers.RecyclerViewEmptySupport; -import com.habitrpg.android.habitica.ui.helpers.SafeDefaultItemAnimator; - -import org.greenrobot.eventbus.EventBus; - -import javax.inject.Inject; - -import butterknife.BindView; -import butterknife.ButterKnife; -import butterknife.OnClick; -import io.realm.OrderedRealmCollection; - -public class ItemRecyclerFragment extends BaseFragment { - - @Inject - InventoryRepository inventoryRepository; - - private static final String ITEM_TYPE_KEY = "CLASS_TYPE_KEY"; - @BindView(R.id.recyclerView) - public RecyclerViewEmptySupport recyclerView; - @BindView(R.id.emptyView) - public View emptyView; - @BindView(R.id.empty_text_view) - public TextView emptyTextView; - @BindView(R.id.titleTextView) - public TextView titleView; - @BindView(R.id.footerTextView) - public TextView footerView; - @BindView(R.id.openMarketButton) - public Button openMarketButton; - public ItemRecyclerAdapter adapter; - public String itemType; - public String itemTypeText; - public boolean isHatching; - public boolean isFeeding; - public Item hatchingItem; - public Pet feedingPet; - @Nullable - public User user; - LinearLayoutManager layoutManager = null; - - private View view; - - @Override - public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - super.onCreateView(inflater, container, savedInstanceState); - view = inflater.inflate(R.layout.fragment_items, container, false); - setUnbinder(ButterKnife.bind(this, view)); - - recyclerView.setEmptyView(emptyView); - emptyTextView.setText(getString(R.string.empty_items, itemTypeText)); - - android.support.v4.app.FragmentActivity context = getActivity(); - - layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager(); - - if (layoutManager == null) { - layoutManager = new LinearLayoutManager(context); - - recyclerView.setLayoutManager(layoutManager); - } - - adapter = (ItemRecyclerAdapter) recyclerView.getAdapter(); - if (adapter == null) { - adapter = new ItemRecyclerAdapter(null, true); - adapter.context = this.getActivity(); - adapter.isHatching = this.isHatching; - adapter.isFeeding = this.isFeeding; - adapter.fragment = this; - if (this.hatchingItem != null) { - adapter.hatchingItem = this.hatchingItem; - } - if (this.feedingPet != null) { - adapter.feedingPet = this.feedingPet; - } - recyclerView.setAdapter(adapter); - - getCompositeSubscription().add(adapter.getSellItemEvents() - .flatMap(item -> inventoryRepository.sellItem(user, item)) - .subscribe(item -> {}, RxErrorHandler.handleEmptyError())); - - getCompositeSubscription().add(adapter.getQuestInvitationEvents() - .flatMap(quest -> inventoryRepository.inviteToQuest(quest)) - .subscribe(group -> { - EventBus.getDefault().post(new OpenMenuItemCommand(NavigationDrawerFragment.SIDEBAR_PARTY)); - }, RxErrorHandler.handleEmptyError())); - } - recyclerView.addItemDecoration(new DividerItemDecoration(getActivity(), DividerItemDecoration.VERTICAL)); - recyclerView.setItemAnimator(new SafeDefaultItemAnimator()); - - if (savedInstanceState != null) { - this.itemType = savedInstanceState.getString(ITEM_TYPE_KEY, ""); - } - - if (this.isHatching) { - getDialog().requestWindowFeature(Window.FEATURE_NO_TITLE); - this.titleView.setText(getString(R.string.hatch_with, this.hatchingItem.getText())); - this.titleView.setVisibility(View.VISIBLE); - this.footerView.setText(getString(R.string.hatching_market_info)); - this.footerView.setVisibility(View.VISIBLE); - this.openMarketButton.setVisibility(View.VISIBLE); - } else if (this.isFeeding) { - getDialog().requestWindowFeature(Window.FEATURE_NO_TITLE); - this.titleView.setText(getString(R.string.dialog_feeding, this.feedingPet.getColorText(), this.feedingPet.getAnimalText())); - this.titleView.setVisibility(View.VISIBLE); - this.footerView.setText(getString(R.string.feeding_market_info)); - this.footerView.setVisibility(View.VISIBLE); - this.openMarketButton.setVisibility(View.VISIBLE); - } else { - this.titleView.setVisibility(View.GONE); - this.footerView.setVisibility(View.GONE); - this.openMarketButton.setVisibility(View.GONE); - } - - return view; - } - - @Override - public void onDestroy() { - inventoryRepository.close(); - super.onDestroy(); - } - - @Override - public void injectFragment(AppComponent component) { - component.inject(this); - } - - @Override - public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - this.loadItems(); - } - - @Override - public void onResume() { - if ((this.isHatching || this.isFeeding) && getDialog().getWindow() != null) { - android.view.WindowManager.LayoutParams params = getDialog().getWindow().getAttributes(); - params.width = ViewGroup.LayoutParams.MATCH_PARENT; - params.verticalMargin = 60; - getDialog().getWindow().setAttributes(params); - } - - super.onResume(); - } - - @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - outState.putString(ITEM_TYPE_KEY, this.itemType); - } - - private void loadItems() { - Class itemClass = null; - switch (itemType) { - case "eggs": - itemClass = Egg.class; - break; - case "hatchingPotions": - itemClass = HatchingPotion.class; - break; - case "food": - itemClass = Food.class; - break; - case "quests": - itemClass = QuestContent.class; - break; - case "special": - itemClass = SpecialItem.class; - break; - } - inventoryRepository.getOwnedItems(itemClass, user).firstElement().subscribe(items -> { - if (items.size() > 0) { - adapter.updateData((OrderedRealmCollection) items); - } - }, RxErrorHandler.handleEmptyError()); - - getCompositeSubscription().add(inventoryRepository.getOwnedPets().subscribe(adapter::setOwnedPets, RxErrorHandler.handleEmptyError())); - } - - @OnClick(R.id.openMarketButton) - public void onOpenMarketClicked() { - dismiss(); - openMarket(); - } - - @OnClick(R.id.openEmptyMarketButton) - public void onEmptyOpenMarketButtonClicked() { - openMarket(); - } - - private void openMarket() { - EventBus.getDefault().post(new OpenMenuItemCommand(NavigationDrawerFragment.SIDEBAR_SHOPS)); - } -} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/items/ItemRecyclerFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/items/ItemRecyclerFragment.kt new file mode 100644 index 000000000..0e62627e2 --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/items/ItemRecyclerFragment.kt @@ -0,0 +1,192 @@ +package com.habitrpg.android.habitica.ui.fragments.inventory.items + +import android.os.Bundle +import android.support.v7.widget.DividerItemDecoration +import android.support.v7.widget.LinearLayoutManager +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.view.Window +import android.widget.Button +import android.widget.TextView +import com.habitrpg.android.habitica.R +import com.habitrpg.android.habitica.components.AppComponent +import com.habitrpg.android.habitica.data.InventoryRepository +import com.habitrpg.android.habitica.events.commands.OpenMenuItemCommand +import com.habitrpg.android.habitica.extensions.inflate +import com.habitrpg.android.habitica.extensions.notNull +import com.habitrpg.android.habitica.helpers.RxErrorHandler +import com.habitrpg.android.habitica.models.inventory.* +import com.habitrpg.android.habitica.models.user.User +import com.habitrpg.android.habitica.ui.adapter.inventory.ItemRecyclerAdapter +import com.habitrpg.android.habitica.ui.fragments.BaseFragment +import com.habitrpg.android.habitica.ui.fragments.NavigationDrawerFragment +import com.habitrpg.android.habitica.ui.helpers.RecyclerViewEmptySupport +import com.habitrpg.android.habitica.ui.helpers.SafeDefaultItemAnimator +import com.habitrpg.android.habitica.ui.helpers.bindView +import com.habitrpg.android.habitica.ui.helpers.resetViews +import io.reactivex.functions.Consumer +import io.realm.OrderedRealmCollection +import org.greenrobot.eventbus.EventBus +import javax.inject.Inject + +class ItemRecyclerFragment : BaseFragment() { + + @Inject + lateinit var inventoryRepository: InventoryRepository + val recyclerView: RecyclerViewEmptySupport? by bindView(R.id.recyclerView) + val emptyView: View? by bindView(R.id.emptyView) + val emptyTextView: TextView? by bindView(R.id.empty_text_view) + val titleView: TextView? by bindView(R.id.titleTextView) + val footerView: TextView? by bindView(R.id.footerTextView) + val openMarketButton: Button? by bindView(R.id.openMarketButton) + val openEmptyMarketButton: Button? by bindView(R.id.openEmptyMarketButton) + var adapter: ItemRecyclerAdapter? = null + var itemType: String? = null + var itemTypeText: String? = null + var isHatching: Boolean = false + var isFeeding: Boolean = false + var hatchingItem: Item? = null + var feedingPet: Pet? = null + var user: User? = null + internal var layoutManager: LinearLayoutManager? = null + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + super.onCreateView(inflater, container, savedInstanceState) + return container?.inflate(R.layout.fragment_items) + } + + override fun onDestroy() { + inventoryRepository.close() + super.onDestroy() + } + + override fun injectFragment(component: AppComponent) { + component.inject(this) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + resetViews() + + recyclerView?.setEmptyView(emptyView) + emptyTextView?.text = getString(R.string.empty_items, itemTypeText) + + val context = activity + + layoutManager = recyclerView?.layoutManager as LinearLayoutManager? + + if (layoutManager == null) { + layoutManager = LinearLayoutManager(context) + + recyclerView?.layoutManager = layoutManager + } + + adapter = recyclerView?.adapter as ItemRecyclerAdapter? + if (adapter == null) { + adapter = ItemRecyclerAdapter(null, true) + adapter?.context = this.activity + adapter?.isHatching = this.isHatching + adapter?.isFeeding = this.isFeeding + adapter?.fragment = this + if (this.hatchingItem != null) { + adapter?.hatchingItem = this.hatchingItem + } + if (this.feedingPet != null) { + adapter?.feedingPet = this.feedingPet + } + recyclerView?.adapter = adapter + + adapter?.notNull { + compositeSubscription.add(it.sellItemEvents + .flatMap { item -> inventoryRepository.sellItem(user, item) } + .subscribe(Consumer { }, RxErrorHandler.handleEmptyError())) + + compositeSubscription.add(it.questInvitationEvents + .flatMap { quest -> inventoryRepository.inviteToQuest(quest) } + .subscribe(Consumer { EventBus.getDefault().post(OpenMenuItemCommand(NavigationDrawerFragment.SIDEBAR_PARTY)) }, RxErrorHandler.handleEmptyError())) + } + } + activity.notNull { + recyclerView?.addItemDecoration(DividerItemDecoration(it, DividerItemDecoration.VERTICAL)) + } + recyclerView?.itemAnimator = SafeDefaultItemAnimator() + + if (savedInstanceState != null) { + this.itemType = savedInstanceState.getString(ITEM_TYPE_KEY, "") + } + + if (this.isHatching) { + dialog.requestWindowFeature(Window.FEATURE_NO_TITLE) + this.titleView?.text = getString(R.string.hatch_with, this.hatchingItem?.text) + this.titleView?.visibility = View.VISIBLE + this.footerView?.text = getString(R.string.hatching_market_info) + this.footerView?.visibility = View.VISIBLE + this.openMarketButton?.visibility = View.VISIBLE + } else if (this.isFeeding) { + dialog.requestWindowFeature(Window.FEATURE_NO_TITLE) + this.titleView?.text = getString(R.string.dialog_feeding, this.feedingPet?.colorText, this.feedingPet?.animalText) + this.titleView?.visibility = View.VISIBLE + this.footerView?.text = getString(R.string.feeding_market_info) + this.footerView?.visibility = View.VISIBLE + this.openMarketButton?.visibility = View.VISIBLE + } else { + this.titleView?.visibility = View.GONE + this.footerView?.visibility = View.GONE + this.openMarketButton?.visibility = View.GONE + } + + openMarketButton?.setOnClickListener { + dismiss() + openMarket() + } + + openEmptyMarketButton?.setOnClickListener { openMarket() } + + this.loadItems() + } + + override fun onResume() { + if ((this.isHatching || this.isFeeding) && dialog.window != null) { + val params = dialog.window?.attributes + params?.width = ViewGroup.LayoutParams.MATCH_PARENT + params?.verticalMargin = 60f + dialog.window?.attributes = params + } + + super.onResume() + } + + override fun onSaveInstanceState(outState: Bundle) { + super.onSaveInstanceState(outState) + outState.putString(ITEM_TYPE_KEY, this.itemType) + } + + private fun loadItems() { + var itemClass: Class? = null + when (itemType) { + "eggs" -> itemClass = Egg::class.java + "hatchingPotions" -> itemClass = HatchingPotion::class.java + "food" -> itemClass = Food::class.java + "quests" -> itemClass = QuestContent::class.java + "special" -> itemClass = SpecialItem::class.java + } + inventoryRepository.getOwnedItems(itemClass, user).firstElement().subscribe(Consumer { items -> + if (items.size > 0) { + adapter?.updateData(items as OrderedRealmCollection) + } + }, RxErrorHandler.handleEmptyError()) + + compositeSubscription.add(inventoryRepository?.ownedPets.subscribe(Consumer { adapter?.setOwnedPets(it) }, RxErrorHandler.handleEmptyError())) + } + + private fun openMarket() { + EventBus.getDefault().post(OpenMenuItemCommand(NavigationDrawerFragment.SIDEBAR_SHOPS)) + } + + companion object { + + private val ITEM_TYPE_KEY = "CLASS_TYPE_KEY" + } +} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/items/ItemsFragment.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/items/ItemsFragment.java index 590c9fabc..6e030146b 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/items/ItemsFragment.java +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/items/ItemsFragment.java @@ -53,29 +53,29 @@ public class ItemsFragment extends BaseMainFragment { switch (position) { case 0: { - fragment.itemType = "eggs"; + fragment.setItemType("eggs"); break; } case 1: { - fragment.itemType = "hatchingPotions"; + fragment.setItemType("hatchingPotions"); break; } case 2: { - fragment.itemType = "food"; + fragment.setItemType("food"); break; } case 3: { - fragment.itemType = "quests"; + fragment.setItemType("quests"); break; } case 4: { - fragment.itemType = "special"; + fragment.setItemType("special"); } } - fragment.isHatching = false; - fragment.isFeeding = false; - fragment.itemTypeText = this.getPageTitle(position).toString(); - fragment.user = ItemsFragment.this.user; + fragment.setHatching(false); + fragment.setFeeding(false); + fragment.setItemTypeText(this.getPageTitle(position).toString()); + fragment.setUser(ItemsFragment.this.user); return fragment; } @@ -116,14 +116,14 @@ public class ItemsFragment extends BaseMainFragment { if (event.usingEgg == null || event.usingHatchingPotion == null) { ItemRecyclerFragment fragment = new ItemRecyclerFragment(); if (event.usingEgg != null) { - fragment.itemType = "hatchingPotions"; - fragment.hatchingItem = event.usingEgg; + fragment.setItemType("hatchingPotions"); + fragment.setHatchingItem(event.usingEgg); } else { - fragment.itemType = "eggs"; - fragment.hatchingItem = event.usingHatchingPotion; + fragment.setItemType("eggs"); + fragment.setHatchingItem(event.usingHatchingPotion); } - fragment.isHatching = true; - fragment.isFeeding = false; + fragment.setHatching(true); + fragment.setFeeding(false); fragment.show(getFragmentManager(), "hatchingDialog"); } } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/stable/StableFragment.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/stable/StableFragment.java index a7df8dcec..506a9a7f1 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/stable/StableFragment.java +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/stable/StableFragment.java @@ -49,16 +49,16 @@ public class StableFragment extends BaseMainFragment { switch (position) { case 0: { - fragment.itemType = "pets"; + fragment.setItemType("pets"); break; } case 1: { - fragment.itemType = "mounts"; + fragment.setItemType("mounts"); break; } } - fragment.user = StableFragment.this.user; - fragment.itemTypeText = this.getPageTitle(position).toString(); + fragment.setUser(StableFragment.this.user); + fragment.setItemTypeText(this.getPageTitle(position).toString()); return fragment; } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/stable/StableRecyclerFragment.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/stable/StableRecyclerFragment.java deleted file mode 100644 index 8ff534268..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/stable/StableRecyclerFragment.java +++ /dev/null @@ -1,188 +0,0 @@ -package com.habitrpg.android.habitica.ui.fragments.inventory.stable; - -import android.os.Bundle; -import android.support.annotation.Nullable; -import android.support.v7.widget.GridLayoutManager; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.TextView; - -import com.habitrpg.android.habitica.R; -import com.habitrpg.android.habitica.components.AppComponent; -import com.habitrpg.android.habitica.data.InventoryRepository; -import com.habitrpg.android.habitica.helpers.RxErrorHandler; -import com.habitrpg.android.habitica.models.inventory.Animal; -import com.habitrpg.android.habitica.models.inventory.Mount; -import com.habitrpg.android.habitica.models.inventory.Pet; -import com.habitrpg.android.habitica.models.user.User; -import com.habitrpg.android.habitica.ui.activities.MainActivity; -import com.habitrpg.android.habitica.ui.adapter.inventory.StableRecyclerAdapter; -import com.habitrpg.android.habitica.ui.fragments.BaseFragment; -import com.habitrpg.android.habitica.ui.helpers.MarginDecoration; -import com.habitrpg.android.habitica.ui.helpers.RecyclerViewEmptySupport; -import com.habitrpg.android.habitica.ui.helpers.SafeDefaultItemAnimator; - -import java.util.ArrayList; -import java.util.List; - -import javax.inject.Inject; - -import butterknife.BindView; -import butterknife.ButterKnife; -import io.reactivex.Flowable; -import io.reactivex.Single; - -public class StableRecyclerFragment extends BaseFragment { - private static final String ITEM_TYPE_KEY = "CLASS_TYPE_KEY"; - - @Inject - InventoryRepository inventoryRepository; - - @BindView(R.id.recyclerView) - public RecyclerViewEmptySupport recyclerView; - @BindView(R.id.emptyView) - public TextView emptyView; - public StableRecyclerAdapter adapter; - public String itemType; - public String itemTypeText; - public User user; - GridLayoutManager layoutManager = null; - - private View view; - - @Override - public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - super.onCreateView(inflater, container, savedInstanceState); - view = inflater.inflate(R.layout.fragment_recyclerview, container, false); - - setUnbinder(ButterKnife.bind(this, view)); - - recyclerView.setEmptyView(emptyView); - emptyView.setText(getString(R.string.empty_items, itemTypeText)); - - layoutManager = new GridLayoutManager(getActivity(), 2); - layoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { - @Override - public int getSpanSize(int position) { - if (adapter.getItemViewType(position) == 0) { - return layoutManager.getSpanCount(); - } else { - return 1; - } - } - }); - recyclerView.setLayoutManager(layoutManager); - recyclerView.addItemDecoration(new MarginDecoration(getActivity())); - - - adapter = (StableRecyclerAdapter) recyclerView.getAdapter(); - if (adapter == null) { - adapter = new StableRecyclerAdapter(); - adapter.setActivity((MainActivity) this.getActivity()); - adapter.setItemType(this.itemType); - recyclerView.setAdapter(adapter); - recyclerView.setItemAnimator(new SafeDefaultItemAnimator()); - } - - if (savedInstanceState != null) { - this.itemType = savedInstanceState.getString(ITEM_TYPE_KEY, ""); - } - - return view; - } - - @Override - public void onDestroy() { - inventoryRepository.close(); - super.onDestroy(); - } - - @Override - public void injectFragment(AppComponent component) { - component.inject(this); - } - - @Override - public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - this.loadItems(); - final View finalView = view; - finalView.post(() -> setGridSpanCount(finalView.getWidth())); - } - - @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - outState.putString(ITEM_TYPE_KEY, this.itemType); - } - - - private void setGridSpanCount(int width) { - int spanCount = 0; - if (getContext() != null && getContext().getResources() != null) { - float itemWidth; - itemWidth = getContext().getResources().getDimension(R.dimen.pet_width); - - spanCount = (int) (width / itemWidth); - } - if (spanCount == 0) { - spanCount = 1; - } - layoutManager.setSpanCount(spanCount); - } - - private void loadItems() { - Flowable observable; - - if ("pets".equals(itemType)) { - observable = inventoryRepository.getPets().firstElement().toFlowable().flatMap(Flowable::fromIterable); - } else { - observable = inventoryRepository.getMounts().firstElement().toFlowable().flatMap(Flowable::fromIterable); - } - - observable.toList().flatMap(unsortedAnimals -> { - List items = new ArrayList<>(); - if (unsortedAnimals.size() == 0) { - return Single.just(items); - } - String lastSectionTitle = ""; - - Animal lastAnimal = unsortedAnimals.get(0); - for (Animal animal : unsortedAnimals) { - if (!animal.getAnimal().equals(lastAnimal.getAnimal()) || animal == unsortedAnimals.get(unsortedAnimals.size()-1)) { - if (!((lastAnimal.getAnimalGroup().equals("premiumPets") || lastAnimal.getAnimalGroup().equals("specialPets") - || lastAnimal.getAnimalGroup().equals("specialMounts") || lastAnimal.getAnimalGroup().equals("premiumMounts")) - && lastAnimal.getNumberOwned() == 0)) { - items.add(lastAnimal); - } - lastAnimal = animal; - } - if (!animal.getAnimalGroup().equals(lastSectionTitle)) { - if (items.size() > 0 && items.get(items.size() - 1).getClass().equals(String.class)) { - items.remove(items.size() - 1); - } - items.add(animal.getAnimalGroup()); - lastSectionTitle = animal.getAnimalGroup(); - } - if (user != null && user.getItems() != null) { - switch (itemType) { - case "pets": - Pet pet = (Pet) animal; - if (pet.getTrained() > 0) { - lastAnimal.setNumberOwned(lastAnimal.getNumberOwned() + 1); - } - break; - case "mounts": - Mount mount = (Mount) animal; - if (mount.getOwned()) { - lastAnimal.setNumberOwned(lastAnimal.getNumberOwned() + 1); - } - break; - } - } - } - return Single.just(items); - }).subscribe(items -> adapter.setItemList(items), RxErrorHandler.handleEmptyError()); - } -} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/stable/StableRecyclerFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/stable/StableRecyclerFragment.kt new file mode 100644 index 000000000..0209fdf64 --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/stable/StableRecyclerFragment.kt @@ -0,0 +1,175 @@ +package com.habitrpg.android.habitica.ui.fragments.inventory.stable + +import android.os.Bundle +import android.support.v7.widget.GridLayoutManager +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.TextView + +import com.habitrpg.android.habitica.R +import com.habitrpg.android.habitica.components.AppComponent +import com.habitrpg.android.habitica.data.InventoryRepository +import com.habitrpg.android.habitica.helpers.RxErrorHandler +import com.habitrpg.android.habitica.models.inventory.Animal +import com.habitrpg.android.habitica.models.inventory.Mount +import com.habitrpg.android.habitica.models.inventory.Pet +import com.habitrpg.android.habitica.models.user.User +import com.habitrpg.android.habitica.ui.adapter.inventory.StableRecyclerAdapter +import com.habitrpg.android.habitica.ui.fragments.BaseFragment + +import java.util.ArrayList + +import javax.inject.Inject + +import com.habitrpg.android.habitica.extensions.inflate +import com.habitrpg.android.habitica.extensions.notNull +import com.habitrpg.android.habitica.ui.activities.MainActivity +import com.habitrpg.android.habitica.ui.helpers.* +import io.reactivex.Flowable +import io.reactivex.Single +import io.reactivex.functions.Consumer + +class StableRecyclerFragment : BaseFragment() { + + @Inject + lateinit var inventoryRepository: InventoryRepository + + private val recyclerView: RecyclerViewEmptySupport? by bindView(R.id.recyclerView) + private val emptyView: TextView? by bindView(R.id.emptyView) + var adapter: StableRecyclerAdapter? = null + var itemType: String? = null + var itemTypeText: String? = null + var user: User? = null + internal var layoutManager: GridLayoutManager? = null + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + super.onCreateView(inflater, container, savedInstanceState) + + if (savedInstanceState != null) { + this.itemType = savedInstanceState.getString(ITEM_TYPE_KEY, "") + } + + return container?.inflate(R.layout.fragment_recyclerview) + } + + override fun onDestroy() { + inventoryRepository.close() + super.onDestroy() + } + + override fun injectFragment(component: AppComponent) { + component.inject(this) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + resetViews() + + recyclerView?.setEmptyView(emptyView) + emptyView?.text = getString(R.string.empty_items, itemTypeText) + + layoutManager = GridLayoutManager(activity, 2) + layoutManager?.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() { + override fun getSpanSize(position: Int): Int { + return if (adapter?.getItemViewType(position) == 0) { + layoutManager?.spanCount ?: 1 + } else { + 1 + } + } + } + recyclerView?.layoutManager = layoutManager + activity.notNull { + recyclerView?.addItemDecoration(MarginDecoration(it)) + } + + + adapter = recyclerView?.adapter as StableRecyclerAdapter + if (adapter == null) { + adapter = StableRecyclerAdapter() + adapter?.activity = this.activity as MainActivity? + adapter?.itemType = this.itemType + recyclerView?.adapter = adapter + recyclerView?.itemAnimator = SafeDefaultItemAnimator() + } + + this.loadItems() + view.post { setGridSpanCount(view.width) } + } + + override fun onSaveInstanceState(outState: Bundle) { + super.onSaveInstanceState(outState) + outState.putString(ITEM_TYPE_KEY, this.itemType) + } + + + private fun setGridSpanCount(width: Int) { + var spanCount = 0 + if (context != null && context?.resources != null) { + val itemWidth: Float = context?.resources?.getDimension(R.dimen.pet_width) ?: 0.toFloat() + + spanCount = (width / itemWidth).toInt() + } + if (spanCount == 0) { + spanCount = 1 + } + layoutManager?.spanCount = spanCount + } + + private fun loadItems() { + val observable: Flowable = if ("pets" == itemType) { + inventoryRepository.pets.firstElement().toFlowable().flatMap { Flowable.fromIterable(it) } + } else { + inventoryRepository.mounts.firstElement().toFlowable().flatMap { Flowable.fromIterable(it) } + } + + observable.toList().flatMap { unsortedAnimals -> + val items = ArrayList() + if (unsortedAnimals.size == 0) { + return@flatMap Single.just>(items) + } + var lastSectionTitle = "" + + var lastAnimal: Animal = unsortedAnimals[0] + for (animal in unsortedAnimals) { + if (animal.animal != lastAnimal.animal || animal === unsortedAnimals[unsortedAnimals.size - 1]) { + if (!((lastAnimal.animalGroup == "premiumPets" || lastAnimal.animalGroup == "specialPets" + || lastAnimal.animalGroup == "specialMounts" || lastAnimal.animalGroup == "premiumMounts") && lastAnimal.numberOwned == 0)) { + items.add(lastAnimal) + } + lastAnimal = animal + } + if (animal.animalGroup != lastSectionTitle) { + if (items.size > 0 && items[items.size - 1].javaClass == String::class.java) { + items.removeAt(items.size - 1) + } + items.add(animal.animalGroup) + lastSectionTitle = animal.animalGroup + } + if (user != null && user?.items != null) { + when (itemType) { + "pets" -> { + val pet = animal as Pet + if (pet.trained > 0) { + lastAnimal.numberOwned = lastAnimal.numberOwned + 1 + } + } + "mounts" -> { + val mount = animal as Mount + if (mount.owned) { + lastAnimal.numberOwned = lastAnimal.numberOwned + 1 + } + } + } + } + } + Single.just>(items) + }.subscribe(Consumer { items -> adapter?.setItemList(items) }, RxErrorHandler.handleEmptyError()) + } + + companion object { + private const val ITEM_TYPE_KEY = "CLASS_TYPE_KEY" + } +} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/preferences/AuthenticationPreferenceFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/preferences/AuthenticationPreferenceFragment.kt index 6cde9cc67..6395df324 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/preferences/AuthenticationPreferenceFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/preferences/AuthenticationPreferenceFragment.kt @@ -188,9 +188,11 @@ class AuthenticationPreferenceFragment: BasePreferencesFragment() { } private fun showSubscriptionStatusDialog() { - val view = SubscriptionDetailsView(context) - view.setPlan(user?.purchased?.plan) context.notNull { context -> + val view = SubscriptionDetailsView(context) + user?.purchased?.plan?.notNull { + view.setPlan(it) + } val dialog = AlertDialog.Builder(context) .setView(view) .setTitle(R.string.subscription_status) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/setup/AvatarSetupFragment.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/setup/AvatarSetupFragment.java deleted file mode 100644 index f25fb2c05..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/setup/AvatarSetupFragment.java +++ /dev/null @@ -1,269 +0,0 @@ -package com.habitrpg.android.habitica.ui.fragments.setup; - -import android.content.res.Resources; -import android.os.Build; -import android.os.Bundle; -import android.support.annotation.Nullable; -import android.support.design.widget.TabLayout; -import android.support.v7.widget.LinearLayoutManager; -import android.support.v7.widget.RecyclerView; -import android.util.TypedValue; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.RelativeLayout; - -import com.habitrpg.android.habitica.R; -import com.habitrpg.android.habitica.components.AppComponent; -import com.habitrpg.android.habitica.data.ApiClient; -import com.habitrpg.android.habitica.data.SetupCustomizationRepository; -import com.habitrpg.android.habitica.events.commands.UpdateUserCommand; -import com.habitrpg.android.habitica.models.SetupCustomization; -import com.habitrpg.android.habitica.models.user.User; -import com.habitrpg.android.habitica.ui.AvatarView; -import com.habitrpg.android.habitica.ui.SpeechBubbleView; -import com.habitrpg.android.habitica.ui.activities.SetupActivity; -import com.habitrpg.android.habitica.ui.adapter.setup.CustomizationSetupAdapter; -import com.habitrpg.android.habitica.ui.fragments.BaseFragment; -import com.habitrpg.android.habitica.ui.views.setup.AvatarCategoryView; - -import org.greenrobot.eventbus.EventBus; - -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Random; - -import javax.inject.Inject; - -import butterknife.BindView; -import butterknife.ButterKnife; -import butterknife.OnClick; - -public class AvatarSetupFragment extends BaseFragment { - - public SetupActivity activity; - public int width; - View view; - @BindView(R.id.avatarView) - AvatarView avatarView; - @BindView(R.id.customization_list) - RecyclerView customizationList; - @BindView(R.id.subcategory_tabs) - TabLayout subCategoryTabs; - @BindView(R.id.body_button) - AvatarCategoryView bodyButton; - @BindView(R.id.skin_button) - AvatarCategoryView skinButton; - @BindView(R.id.hair_button) - AvatarCategoryView hairButton; - @BindView(R.id.extras_button) - AvatarCategoryView extrasButton; - @BindView(R.id.caret_view) - ImageView caretView; - @BindView(R.id.speech_bubble) - SpeechBubbleView speechBubbleView; - - CustomizationSetupAdapter adapter; - LinearLayoutManager layoutManager; - @Inject - SetupCustomizationRepository customizationRepository; - @Inject - ApiClient apiClient; - - private User user; - private List subcategories; - private AvatarCategoryView activeButton; - private String activeCategory; - private String activeSubCategory; - private Random random; - - @Nullable - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - super.onCreateView(inflater, container, savedInstanceState); - view = inflater.inflate(R.layout.fragment_setup_avatar, container, false); - - setUnbinder(ButterKnife.bind(this, view)); - this.adapter = new CustomizationSetupAdapter(); - if (this.user != null) { - this.adapter.userSize = this.user.getPreferences().getSize(); - } else { - this.adapter.userSize = "slim"; - } - this.adapter.user = this.user; - this.layoutManager = new LinearLayoutManager(activity); - this.layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL); - this.customizationList.setLayoutManager(this.layoutManager); - - this.customizationList.setAdapter(this.adapter); - - this.subCategoryTabs.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() { - @Override - public void onTabSelected(TabLayout.Tab tab) { - int position = tab.getPosition(); - if (subcategories != null && position < subcategories.size()) { - activeSubCategory = subcategories.get(position); - } - loadCustomizations(); - } - - @Override - public void onTabUnselected(TabLayout.Tab tab) { - - } - - @Override - public void onTabReselected(TabLayout.Tab tab) { - - } - }); - - this.selectedBodyCategory(); - - this.random = new Random(); - - if (this.user != null) { - this.updateAvatar(); - } - return view; - } - - @Override - public void setUserVisibleHint(boolean isVisibleToUser) { - super.setUserVisibleHint(isVisibleToUser); - if (isVisibleToUser && getContext() != null) { - speechBubbleView.animateText(getContext().getString(R.string.avatar_setup_description)); - } - } - - @Override - public void injectFragment(AppComponent component) { - component.inject(this); - } - - private void loadCustomizations() { - if (this.user == null || this.adapter == null || this.activeCategory == null) { - return; - } - - this.adapter.setCustomizationList(customizationRepository.getCustomizations(activeCategory, activeSubCategory, user)); - } - - public void setUser(@Nullable User user) { - this.user = user; - if (avatarView != null) { - updateAvatar(); - } - if (this.adapter != null) { - this.adapter.user = user; - this.adapter.notifyDataSetChanged(); - } - } - - private void updateAvatar() { - avatarView.setAvatar(user); - } - - - @OnClick(R.id.body_button) - protected void selectedBodyCategory() { - activateButton(bodyButton); - this.activeCategory = "body"; - this.subCategoryTabs.removeAllTabs(); - this.subcategories = Arrays.asList("size", "shirt"); - this.subCategoryTabs.addTab(subCategoryTabs.newTab().setText(R.string.avatar_size)); - this.subCategoryTabs.addTab(subCategoryTabs.newTab().setText(R.string.avatar_shirt)); - loadCustomizations(); - } - - @OnClick(R.id.skin_button) - protected void selectedSkinCategory() { - activateButton(skinButton); - this.activeCategory = "skin"; - this.subCategoryTabs.removeAllTabs(); - this.subcategories = Collections.singletonList("color"); - this.subCategoryTabs.addTab(subCategoryTabs.newTab().setText(R.string.avatar_skin_color)); - loadCustomizations(); - } - - @OnClick(R.id.hair_button) - protected void selectedHairCategory() { - activateButton(hairButton); - this.activeCategory = "hair"; - this.subCategoryTabs.removeAllTabs(); - this.subcategories = Arrays.asList("bangs", "color", "ponytail"); - this.subCategoryTabs.addTab(subCategoryTabs.newTab().setText(R.string.avatar_hair_bangs)); - this.subCategoryTabs.addTab(subCategoryTabs.newTab().setText(R.string.avatar_hair_color)); - this.subCategoryTabs.addTab(subCategoryTabs.newTab().setText(R.string.avatar_hair_ponytail)); - loadCustomizations(); - } - - @OnClick(R.id.extras_button) - protected void selectedExtrasCategory() { - activateButton(extrasButton); - this.activeCategory = "extras"; - this.subCategoryTabs.removeAllTabs(); - this.subcategories = Arrays.asList("glasses", "flower", "wheelchair"); - this.subCategoryTabs.addTab(subCategoryTabs.newTab().setText(R.string.avatar_glasses)); - this.subCategoryTabs.addTab(subCategoryTabs.newTab().setText(R.string.avatar_flower)); - this.subCategoryTabs.addTab(subCategoryTabs.newTab().setText(R.string.avatar_wheelchair)); - loadCustomizations(); - } - - @OnClick(R.id.randomize_button) - protected void randomizeCharacter() { - if (user == null) { - return; - } - UpdateUserCommand command = new UpdateUserCommand(); - Map updateData = new HashMap<>(); - updateData.put("preferences.size", chooseRandomKey(customizationRepository.getCustomizations("body", "size", user), false)); - updateData.put("preferences.shirt", chooseRandomKey(customizationRepository.getCustomizations("body", "shirt", user), false)); - updateData.put("preferences.skin", chooseRandomKey(customizationRepository.getCustomizations("skin", "color", user), false)); - updateData.put("preferences.hair.color", chooseRandomKey(customizationRepository.getCustomizations("hair", "color", user), false)); - updateData.put("preferences.hair.base", chooseRandomKey(customizationRepository.getCustomizations("hair", "ponytail", user), false)); - updateData.put("preferences.hair.bangs", chooseRandomKey(customizationRepository.getCustomizations("hair", "bangs", user), false)); - updateData.put("preferences.hair.flower", chooseRandomKey(customizationRepository.getCustomizations("extras", "flower", user), true)); - updateData.put("preferences.chair", chooseRandomKey(customizationRepository.getCustomizations("extras", "wheelchair", user), true)); - command.updateData = updateData; - - EventBus.getDefault().post(command); - } - - @Nullable - private String chooseRandomKey(List customizations, boolean weighFirstOption) { - if (customizations.size() == 0) { - return null; - } - if (weighFirstOption) { - if (random.nextInt(10) > 3) { - return customizations.get(0).getKey(); - } - } - return customizations.get(random.nextInt(customizations.size())).getKey(); - } - - private void activateButton(AvatarCategoryView button) { - if (this.activeButton != null) { - this.activeButton.setActive(false); - } - this.activeButton = button; - this.activeButton.setActive(true); - int[] location = new int[2]; - RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams)this.caretView.getLayoutParams(); - this.activeButton.getLocationOnScreen(location); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { - Resources r = getResources(); - int px = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 40, r.getDisplayMetrics()); - params.setMarginStart(location[0]+px); - this.caretView.setLayoutParams(params); - } else { - caretView.setVisibility(View.GONE); - } - - } -} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/setup/AvatarSetupFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/setup/AvatarSetupFragment.kt new file mode 100644 index 000000000..cb0c4a891 --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/setup/AvatarSetupFragment.kt @@ -0,0 +1,246 @@ +package com.habitrpg.android.habitica.ui.fragments.setup + +import android.os.Build +import android.os.Bundle +import android.support.design.widget.TabLayout +import android.support.v7.widget.LinearLayoutManager +import android.support.v7.widget.RecyclerView +import android.util.TypedValue +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.Button +import android.widget.ImageView +import android.widget.RelativeLayout +import butterknife.OnClick +import com.habitrpg.android.habitica.R +import com.habitrpg.android.habitica.components.AppComponent +import com.habitrpg.android.habitica.data.ApiClient +import com.habitrpg.android.habitica.data.SetupCustomizationRepository +import com.habitrpg.android.habitica.events.commands.UpdateUserCommand +import com.habitrpg.android.habitica.extensions.inflate +import com.habitrpg.android.habitica.extensions.notNull +import com.habitrpg.android.habitica.models.SetupCustomization +import com.habitrpg.android.habitica.models.user.User +import com.habitrpg.android.habitica.ui.AvatarView +import com.habitrpg.android.habitica.ui.SpeechBubbleView +import com.habitrpg.android.habitica.ui.activities.SetupActivity +import com.habitrpg.android.habitica.ui.adapter.setup.CustomizationSetupAdapter +import com.habitrpg.android.habitica.ui.fragments.BaseFragment +import com.habitrpg.android.habitica.ui.helpers.bindView +import com.habitrpg.android.habitica.ui.helpers.resetViews +import com.habitrpg.android.habitica.ui.views.setup.AvatarCategoryView +import org.greenrobot.eventbus.EventBus +import java.util.* +import javax.inject.Inject + +class AvatarSetupFragment : BaseFragment() { + + @Inject + lateinit var customizationRepository: SetupCustomizationRepository + @Inject + lateinit var apiClient: ApiClient + + var activity: SetupActivity? = null + var width: Int = 0 + private val avatarView: AvatarView? by bindView(R.id.avatarView) + private val customizationList: RecyclerView? by bindView(R.id.customization_list) + private val subCategoryTabs: TabLayout? by bindView(R.id.subcategory_tabs) + private val bodyButton: AvatarCategoryView? by bindView(R.id.body_button) + private val skinButton: AvatarCategoryView? by bindView(R.id.skin_button) + private val hairButton: AvatarCategoryView? by bindView(R.id.hair_button) + private val extrasButton: AvatarCategoryView? by bindView(R.id.extras_button) + private val caretView: ImageView? by bindView(R.id.caret_view) + private val speechBubbleView: SpeechBubbleView? by bindView(R.id.speech_bubble) + private val randomizeButton: Button? by bindView(R.id.randomize_button) + + internal var adapter: CustomizationSetupAdapter? = null + internal var layoutManager: LinearLayoutManager = LinearLayoutManager(activity) + + private var user: User? = null + private var subcategories: List = emptyList() + private var activeButton: AvatarCategoryView? = null + private var activeCategory: String? = null + private var activeSubCategory: String? = null + private var random = Random() + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + super.onCreateView(inflater, container, savedInstanceState) + return container?.inflate(R.layout.fragment_setup_avatar) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + resetViews() + + this.adapter = CustomizationSetupAdapter() + this.adapter?.userSize = this.user?.preferences?.size ?: "slim" + + this.adapter?.user = this.user + this.layoutManager = LinearLayoutManager(activity) + this.layoutManager.orientation = LinearLayoutManager.HORIZONTAL + this.customizationList?.layoutManager = this.layoutManager + + this.customizationList?.adapter = this.adapter + + this.subCategoryTabs?.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener { + override fun onTabSelected(tab: TabLayout.Tab) { + val position = tab.position + if (position < subcategories.size) { + activeSubCategory = subcategories[position] + } + loadCustomizations() + } + + override fun onTabUnselected(tab: TabLayout.Tab) { + + } + + override fun onTabReselected(tab: TabLayout.Tab) { + + } + }) + + bodyButton?.setOnClickListener { selectedBodyCategory() } + skinButton?.setOnClickListener { selectedSkinCategory() } + hairButton?.setOnClickListener { selectedHairCategory() } + extrasButton?.setOnClickListener { selectedExtrasCategory() } + randomizeButton?.setOnClickListener { randomizeCharacter() } + + this.selectedBodyCategory() + + if (this.user != null) { + this.updateAvatar() + } + } + + override fun setUserVisibleHint(isVisibleToUser: Boolean) { + super.setUserVisibleHint(isVisibleToUser) + if (isVisibleToUser && context != null) { + speechBubbleView?.animateText(context?.getString(R.string.avatar_setup_description)) + } + } + + override fun injectFragment(component: AppComponent) { + component.inject(this) + } + + private fun loadCustomizations() { + if (this.user == null || this.adapter == null || this.activeCategory == null) { + return + } + + this.adapter?.setCustomizationList(customizationRepository.getCustomizations(activeCategory, activeSubCategory, user)) + } + + fun setUser(user: User?) { + this.user = user + if (avatarView != null) { + updateAvatar() + } + if (this.adapter != null) { + this.adapter?.user = user + this.adapter?.notifyDataSetChanged() + } + } + + private fun updateAvatar() { + user.notNull { + avatarView?.setAvatar(it) + } + } + + + fun selectedBodyCategory() { + activateButton(bodyButton) + this.activeCategory = "body" + this.subCategoryTabs?.removeAllTabs() + this.subcategories = Arrays.asList("size", "shirt") + subCategoryTabs?.newTab()?.setText(R.string.avatar_size).notNull { this.subCategoryTabs?.addTab(it) } + subCategoryTabs?.newTab()?.setText(R.string.avatar_shirt).notNull { this.subCategoryTabs?.addTab(it) } + loadCustomizations() + } + + fun selectedSkinCategory() { + activateButton(skinButton) + this.activeCategory = "skin" + this.subCategoryTabs?.removeAllTabs() + this.subcategories = listOf("color") + subCategoryTabs?.newTab()?.setText(R.string.avatar_skin_color).notNull { this.subCategoryTabs?.addTab(it) } + loadCustomizations() + } + + fun selectedHairCategory() { + activateButton(hairButton) + this.activeCategory = "hair" + this.subCategoryTabs?.removeAllTabs() + this.subcategories = Arrays.asList("bangs", "color", "ponytail") + subCategoryTabs?.newTab()?.setText(R.string.avatar_hair_bangs).notNull { this.subCategoryTabs?.addTab(it) } + subCategoryTabs?.newTab()?.setText(R.string.avatar_hair_color).notNull { this.subCategoryTabs?.addTab(it) } + subCategoryTabs?.newTab()?.setText(R.string.avatar_hair_ponytail).notNull { this.subCategoryTabs?.addTab(it) } + loadCustomizations() + } + + fun selectedExtrasCategory() { + activateButton(extrasButton) + this.activeCategory = "extras" + this.subCategoryTabs?.removeAllTabs() + this.subcategories = Arrays.asList("glasses", "flower", "wheelchair") + subCategoryTabs?.newTab()?.setText(R.string.avatar_glasses).notNull { this.subCategoryTabs?.addTab(it) } + subCategoryTabs?.newTab()?.setText(R.string.avatar_flower).notNull { this.subCategoryTabs?.addTab(it) } + subCategoryTabs?.newTab()?.setText(R.string.avatar_wheelchair).notNull { this.subCategoryTabs?.addTab(it) } + loadCustomizations() + } + + fun randomizeCharacter() { + if (user == null) { + return + } + val command = UpdateUserCommand() + val updateData = HashMap() + updateData["preferences.size"] = chooseRandomKey(customizationRepository.getCustomizations("body", "size", user), false) + updateData["preferences.shirt"] = chooseRandomKey(customizationRepository.getCustomizations("body", "shirt", user), false) + updateData["preferences.skin"] = chooseRandomKey(customizationRepository.getCustomizations("skin", "color", user), false) + updateData["preferences.hair.color"] = chooseRandomKey(customizationRepository.getCustomizations("hair", "color", user), false) + updateData["preferences.hair.base"] = chooseRandomKey(customizationRepository.getCustomizations("hair", "ponytail", user), false) + updateData["preferences.hair.bangs"] = chooseRandomKey(customizationRepository.getCustomizations("hair", "bangs", user), false) + updateData["preferences.hair.flower"] = chooseRandomKey(customizationRepository.getCustomizations("extras", "flower", user), true) + updateData["preferences.chair"] = chooseRandomKey(customizationRepository.getCustomizations("extras", "wheelchair", user), true) + command.updateData = updateData + + EventBus.getDefault().post(command) + } + + private fun chooseRandomKey(customizations: List, weighFirstOption: Boolean): String { + if (customizations.isEmpty()) { + return "" + } + if (weighFirstOption) { + if (random.nextInt(10) > 3) { + return customizations[0].key + } + } + return customizations[random.nextInt(customizations.size)].key + } + + private fun activateButton(button: AvatarCategoryView?) { + if (this.activeButton != null) { + this.activeButton?.setActive(false) + } + this.activeButton = button + this.activeButton?.setActive(true) + val location = IntArray(2) + val params = this.caretView?.layoutParams as RelativeLayout.LayoutParams + this.activeButton?.getLocationOnScreen(location) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + val r = resources + val px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 40f, r.displayMetrics).toInt() + params.marginStart = location[0] + px + this.caretView?.layoutParams = params + } else { + caretView?.visibility = View.GONE + } + + } +} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/setup/IntroFragment.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/setup/IntroFragment.java deleted file mode 100644 index c9029ca6c..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/setup/IntroFragment.java +++ /dev/null @@ -1,128 +0,0 @@ -package com.habitrpg.android.habitica.ui.fragments.setup; - -import android.graphics.drawable.Drawable; -import android.os.Bundle; -import android.support.annotation.Nullable; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.TextView; - -import com.habitrpg.android.habitica.R; -import com.habitrpg.android.habitica.components.AppComponent; -import com.habitrpg.android.habitica.ui.fragments.BaseFragment; - -import butterknife.BindView; -import butterknife.ButterKnife; - -public class IntroFragment extends BaseFragment { - - @BindView(R.id.subtitleTextView) - TextView subtitleTextView; - - @BindView(R.id.titleTextView) - TextView titleTextView; - - @BindView(R.id.titleImageView) - ImageView titleImageView; - - @BindView(R.id.descriptionTextView) - TextView descriptionTextView; - - @BindView(R.id.imageView) - ImageView imageView; - - @BindView(R.id.container_view) - ViewGroup containerView; - - Drawable image; - Drawable titleImage; - String subtitle; - String title; - String description; - Integer backgroundColor; - - @Nullable - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - super.onCreateView(inflater, container, savedInstanceState); - View v = inflater.inflate(R.layout.fragment_intro, container, false); - - setUnbinder(ButterKnife.bind(this, v)); - - if (this.image != null) { - this.imageView.setImageDrawable(this.image); - } - - if (this.titleImage != null) { - this.titleImageView.setImageDrawable(this.titleImage); - } - - if (this.subtitle != null) { - this.subtitleTextView.setText(this.subtitle); - } - - if (this.title != null) { - this.titleTextView.setText(this.title); - } - - if (this.description != null) { - this.descriptionTextView.setText(this.description); - } - - if (this.backgroundColor != null) { - this.containerView.setBackgroundColor(this.backgroundColor); - } - - return v; - } - - @Override - public void injectFragment(AppComponent component) { - component.inject(this); - } - - public void setImage(Drawable image) { - this.image = image; - if (this.imageView != null && image != null) { - this.imageView.setImageDrawable(image); - } - } - - public void setTitleImage(Drawable image) { - this.titleImage = image; - if (this.titleImageView != null && image != null) { - this.titleImageView.setImageDrawable(image); - } - } - - public void setSubtitle(String text) { - this.subtitle = text; - if (this.subtitleTextView != null && text != null) { - this.subtitleTextView.setText(text); - } - } - - public void setTitle(String text) { - this.title = text; - if (this.titleTextView != null && text != null) { - this.titleTextView.setText(text); - } - } - - public void setDescription(String text) { - this.description = text; - if (this.descriptionTextView != null && text != null) { - this.descriptionTextView.setText(text); - } - } - - public void setBackgroundColor(int color) { - this.backgroundColor = color; - if (containerView != null) { - containerView.setBackgroundColor(color); - } - } - -} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/setup/IntroFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/setup/IntroFragment.kt new file mode 100644 index 000000000..15b76d9b5 --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/setup/IntroFragment.kt @@ -0,0 +1,104 @@ +package com.habitrpg.android.habitica.ui.fragments.setup + +import android.graphics.drawable.Drawable +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.TextView +import com.habitrpg.android.habitica.R +import com.habitrpg.android.habitica.components.AppComponent +import com.habitrpg.android.habitica.extensions.inflate +import com.habitrpg.android.habitica.extensions.notNull +import com.habitrpg.android.habitica.ui.fragments.BaseFragment +import com.habitrpg.android.habitica.ui.helpers.bindView +import com.habitrpg.android.habitica.ui.helpers.resetViews + +class IntroFragment : BaseFragment() { + + private val subtitleTextView: TextView? by bindView(R.id.subtitleTextView) + private val titleTextView: TextView? by bindView(R.id.titleTextView) + private val titleImageView: ImageView? by bindView(R.id.titleImageView) + private val descriptionTextView: TextView? by bindView(R.id.descriptionTextView) + private val imageView: ImageView? by bindView(R.id.imageView) + private val containerView: ViewGroup? by bindView(R.id.container_view) + + private var image: Drawable? = null + private var titleImage: Drawable? = null + private var subtitle: String? = null + private var title: String? = null + private var description: String? = null + private var backgroundColor: Int? = null + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + super.onCreateView(inflater, container, savedInstanceState) + return container?.inflate(R.layout.fragment_intro) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + resetViews() + + if (this.image != null) { + this.imageView?.setImageDrawable(this.image) + } + + if (this.titleImage != null) { + this.titleImageView?.setImageDrawable(this.titleImage) + } + + if (this.subtitle != null) { + this.subtitleTextView?.text = this.subtitle + } + + if (this.title != null) { + this.titleTextView?.text = this.title + } + + if (this.description != null) { + this.descriptionTextView?.text = this.description + } + + backgroundColor.notNull { + this.containerView?.setBackgroundColor(it) + } + } + + override fun injectFragment(component: AppComponent) { + component.inject(this) + } + + fun setImage(image: Drawable?) { + this.image = image + if (image != null) { + this.imageView?.setImageDrawable(image) + } + } + + fun setTitleImage(image: Drawable?) { + this.titleImage = image + this.titleImageView?.setImageDrawable(image) + } + + fun setSubtitle(text: String?) { + this.subtitle = text + subtitleTextView?.text = text + } + + fun setTitle(text: String?) { + this.title = text + titleTextView?.text = text + } + + fun setDescription(text: String?) { + descriptionTextView?.text = text + } + + fun setBackgroundColor(color: Int) { + this.backgroundColor = color + containerView?.setBackgroundColor(color) + } + +} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/setup/TaskSetupFragment.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/setup/TaskSetupFragment.java deleted file mode 100644 index 1792a02bf..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/setup/TaskSetupFragment.java +++ /dev/null @@ -1,187 +0,0 @@ -package com.habitrpg.android.habitica.ui.fragments.setup; - -import android.os.Bundle; -import android.support.annotation.Nullable; -import android.support.v7.widget.GridLayoutManager; -import android.support.v7.widget.RecyclerView; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; - -import com.habitrpg.android.habitica.R; -import com.habitrpg.android.habitica.components.AppComponent; -import com.habitrpg.android.habitica.models.tasks.Days; -import com.habitrpg.android.habitica.models.tasks.Task; -import com.habitrpg.android.habitica.models.user.User; -import com.habitrpg.android.habitica.ui.AvatarView; -import com.habitrpg.android.habitica.ui.SpeechBubbleView; -import com.habitrpg.android.habitica.ui.activities.SetupActivity; -import com.habitrpg.android.habitica.ui.adapter.setup.TaskSetupAdapter; -import com.habitrpg.android.habitica.ui.fragments.BaseFragment; - -import java.util.ArrayList; -import java.util.Date; -import java.util.List; - -import butterknife.BindView; -import butterknife.ButterKnife; - -public class TaskSetupFragment extends BaseFragment { - - - public SetupActivity activity; - public int width; - View view; - @BindView(R.id.recyclerView) - RecyclerView recyclerView; - @BindView(R.id.avatarView) - AvatarView avatarView; - @BindView(R.id.speech_bubble) - SpeechBubbleView speechBubbleView; - TaskSetupAdapter adapter; - private String[][] taskGroups; - private Object[][] tasks; - private User user; - - @Nullable - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - super.onCreateView(inflater, container, savedInstanceState); - view = inflater.inflate(R.layout.fragment_setup_tasks, container, false); - - this.setTasks(); - - setUnbinder(ButterKnife.bind(this, view)); - this.adapter = new TaskSetupAdapter(); - this.adapter.setTaskList(this.taskGroups); - this.recyclerView.setLayoutManager(new GridLayoutManager(activity, 2)); - this.recyclerView.setAdapter(this.adapter); - - if (this.user != null) { - this.updateAvatar(); - } - - return view; - } - - @Override - public void setUserVisibleHint(boolean isVisibleToUser) { - super.setUserVisibleHint(isVisibleToUser); - if (isVisibleToUser && getContext() != null) { - speechBubbleView.animateText(getContext().getString(R.string.task_setup_description)); - } - } - - public void setUser(@Nullable User user) { - this.user = user; - if (avatarView != null) { - updateAvatar(); - } - } - - private void updateAvatar() { - avatarView.setAvatar(user); - } - - @Override - public void injectFragment(AppComponent component) { - component.inject(this); - } - - private void setTasks() { - this.taskGroups = new String[][]{ - {getString(R.string.setup_group_work), "work"}, - {getString(R.string.setup_group_exercise), "exercise"}, - {getString(R.string.setup_group_health), "healthWellness"}, - {getString(R.string.setup_group_school), "school"}, - {getString(R.string.setup_group_teams), "teams"}, - {getString(R.string.setup_group_chores), "chores"}, - {getString(R.string.setup_group_creativity), "creativity"}, - {getString(R.string.setuP_group_other), "other"} - }; - - this.tasks = new Object[][]{ - {"work", "habit", getString(R.string.setup_task_work_1), true, false}, - {"work", "daily", getString(R.string.setup_task_work_2)}, - {"work", "todo", getString(R.string.setup_task_work_3)}, - - {"exercise", "habit", getString(R.string.setup_task_exercise_1), true, false}, - {"exercise", "daily", getString(R.string.setup_task_exercise_2)}, - {"exercise", "todo", getString(R.string.setup_task_exercise_3)}, - - {"healthWellness", "habit", getString(R.string.setup_task_healthWellness_1), true, true}, - {"healthWellness", "daily", getString(R.string.setup_task_healthWellness_2)}, - {"healthWellness", "todo", getString(R.string.setup_task_healthWellness_3)}, - - {"school", "habit", getString(R.string.setup_task_school_1), true, true}, - {"school", "daily", getString(R.string.setup_task_school_2)}, - {"school", "todo", getString(R.string.setup_task_school_3)}, - - {"teams", "habit", getString(R.string.setup_task_teams_1), true, false}, - {"teams", "daily", getString(R.string.setup_task_teams_2)}, - {"teams", "todo", getString(R.string.setup_task_teams_3)}, - - {"chores", "habit", getString(R.string.setup_task_chores_1), true, false}, - {"chores", "daily", getString(R.string.setup_task_chores_2)}, - {"chores", "todo", getString(R.string.setup_task_chores_3)}, - - {"creativity", "habit", getString(R.string.setup_task_creativity_1), true, false}, - {"creativity", "daily", getString(R.string.setup_task_creativity_2)}, - {"creativity", "todo", getString(R.string.setup_task_creativity_3)}, - }; - } - - public List createSampleTasks() { - List groups = new ArrayList<>(); - int i = 0; - for (Boolean checked : this.adapter.checkedList) { - if (checked) { - groups.add(this.taskGroups[i][1]); - } - i++; - } - List tasks = new ArrayList<>(); - for (Object[] task : this.tasks) { - String taskGroup = (String) task[0]; - if (groups.contains(taskGroup)) { - Task taskObject; - if (task.length == 5) { - taskObject = this.makeTaskObject((String) task[1], (String) task[2], (Boolean) task[3], (Boolean) task[4]); - } else { - taskObject = this.makeTaskObject((String) task[1], (String) task[2], null, null); - } - tasks.add(taskObject); - } - } - return tasks; - } - - private Task makeTaskObject(String type, String text, @Nullable Boolean up, @Nullable Boolean down) { - Task task = new Task(); - task.setText(text); - task.setPriority(1.0f); - task.setType(type); - - if (type.equals("habit")) { - task.setUp(up); - task.setDown(down); - } - - if (type.equals("daily")) { - task.setFrequency("weekly"); - task.setStartDate(new Date()); - Days days = new Days(); - days.setM(true); - days.setT(true); - days.setW(true); - days.setTh(true); - days.setF(true); - days.setS(true); - days.setSu(true); - task.setRepeat(days); - } - - return task; - } - -} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/setup/TaskSetupFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/setup/TaskSetupFragment.kt new file mode 100644 index 000000000..6567157e9 --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/setup/TaskSetupFragment.kt @@ -0,0 +1,147 @@ +package com.habitrpg.android.habitica.ui.fragments.setup + +import android.os.Bundle +import android.support.v7.widget.GridLayoutManager +import android.support.v7.widget.RecyclerView +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import com.habitrpg.android.habitica.R +import com.habitrpg.android.habitica.components.AppComponent +import com.habitrpg.android.habitica.extensions.inflate +import com.habitrpg.android.habitica.extensions.notNull +import com.habitrpg.android.habitica.models.tasks.Days +import com.habitrpg.android.habitica.models.tasks.Task +import com.habitrpg.android.habitica.models.user.User +import com.habitrpg.android.habitica.ui.AvatarView +import com.habitrpg.android.habitica.ui.SpeechBubbleView +import com.habitrpg.android.habitica.ui.activities.SetupActivity +import com.habitrpg.android.habitica.ui.adapter.setup.TaskSetupAdapter +import com.habitrpg.android.habitica.ui.fragments.BaseFragment +import com.habitrpg.android.habitica.ui.helpers.bindView +import com.habitrpg.android.habitica.ui.helpers.resetViews +import java.util.* + +class TaskSetupFragment : BaseFragment() { + + + var activity: SetupActivity? = null + var width: Int = 0 + private val recyclerView: RecyclerView? by bindView(R.id.recyclerView) + private val avatarView: AvatarView? by bindView(R.id.avatarView) + private val speechBubbleView: SpeechBubbleView? by bindView(R.id.speech_bubble) + internal var adapter: TaskSetupAdapter = TaskSetupAdapter() + private var taskGroups: Array> = arrayOf() + private var tasks: Array> = arrayOf() + private var user: User? = null + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + super.onCreateView(inflater, container, savedInstanceState) + return container?.inflate(R.layout.fragment_setup_tasks) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + resetViews() + + this.setTasks() + + this.adapter = TaskSetupAdapter() + this.adapter.setTaskList(this.taskGroups) + this.recyclerView?.layoutManager = GridLayoutManager(activity, 2) + this.recyclerView?.adapter = this.adapter + + if (this.user != null) { + this.updateAvatar() + } + + } + + override fun setUserVisibleHint(isVisibleToUser: Boolean) { + super.setUserVisibleHint(isVisibleToUser) + if (isVisibleToUser && context != null) { + speechBubbleView?.animateText(context?.getString(R.string.task_setup_description)) + } + } + + fun setUser(user: User?) { + this.user = user + if (avatarView != null) { + updateAvatar() + } + } + + private fun updateAvatar() { + user.notNull { + avatarView?.setAvatar(it) + } + } + + override fun injectFragment(component: AppComponent) { + component.inject(this) + } + + private fun setTasks() { + this.taskGroups = arrayOf(arrayOf(getString(R.string.setup_group_work), "work"), arrayOf(getString(R.string.setup_group_exercise), "exercise"), arrayOf(getString(R.string.setup_group_health), "healthWellness"), arrayOf(getString(R.string.setup_group_school), "school"), arrayOf(getString(R.string.setup_group_teams), "teams"), arrayOf(getString(R.string.setup_group_chores), "chores"), arrayOf(getString(R.string.setup_group_creativity), "creativity"), arrayOf(getString(R.string.setuP_group_other), "other")) + + this.tasks = arrayOf(arrayOf("work", "habit", getString(R.string.setup_task_work_1), true, false), arrayOf("work", "daily", getString(R.string.setup_task_work_2)), arrayOf("work", "todo", getString(R.string.setup_task_work_3)), + arrayOf("exercise", "habit", getString(R.string.setup_task_exercise_1), true, false), arrayOf("exercise", "daily", getString(R.string.setup_task_exercise_2)), arrayOf("exercise", "todo", getString(R.string.setup_task_exercise_3)), + arrayOf("healthWellness", "habit", getString(R.string.setup_task_healthWellness_1), true, true), arrayOf("healthWellness", "daily", getString(R.string.setup_task_healthWellness_2)), arrayOf("healthWellness", "todo", getString(R.string.setup_task_healthWellness_3)), + arrayOf("school", "habit", getString(R.string.setup_task_school_1), true, true), arrayOf("school", "daily", getString(R.string.setup_task_school_2)), arrayOf("school", "todo", getString(R.string.setup_task_school_3)), + arrayOf("teams", "habit", getString(R.string.setup_task_teams_1), true, false), arrayOf("teams", "daily", getString(R.string.setup_task_teams_2)), arrayOf("teams", "todo", getString(R.string.setup_task_teams_3)), + arrayOf("chores", "habit", getString(R.string.setup_task_chores_1), true, false), arrayOf("chores", "daily", getString(R.string.setup_task_chores_2)), arrayOf("chores", "todo", getString(R.string.setup_task_chores_3)), + arrayOf("creativity", "habit", getString(R.string.setup_task_creativity_1), true, false), arrayOf("creativity", "daily", getString(R.string.setup_task_creativity_2)), arrayOf("creativity", "todo", getString(R.string.setup_task_creativity_3))) + } + + fun createSampleTasks(): List { + val groups = ArrayList() + for ((i, checked) in this.adapter.checkedList.withIndex()) { + if (checked) { + groups.add(this.taskGroups[i][1]) + } + } + val tasks = ArrayList() + for (task in this.tasks) { + val taskGroup = task[0] as String + if (groups.contains(taskGroup)) { + val taskObject: Task = if (task.size == 5) { + this.makeTaskObject(task[1] as String, task[2] as String, task[3] as Boolean, task[4] as Boolean) + } else { + this.makeTaskObject(task[1] as String, task[2] as String, null, null) + } + tasks.add(taskObject) + } + } + return tasks + } + + private fun makeTaskObject(type: String, text: String, up: Boolean?, down: Boolean?): Task { + val task = Task() + task.text = text + task.priority = 1.0f + task.type = type + + if (type == "habit") { + task.up = up + task.down = down + } + + if (type == "daily") { + task.frequency = "weekly" + task.startDate = Date() + val days = Days() + days.m = true + days.t = true + days.w = true + days.th = true + days.f = true + days.s = true + days.su = true + task.repeat = days + } + + return task + } + +} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/setup/WelcomeFragment.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/setup/WelcomeFragment.java deleted file mode 100644 index 956b315b7..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/setup/WelcomeFragment.java +++ /dev/null @@ -1,58 +0,0 @@ -package com.habitrpg.android.habitica.ui.fragments.setup; - -import android.os.Bundle; -import android.support.annotation.Nullable; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageView; - -import com.habitrpg.android.habitica.R; -import com.habitrpg.android.habitica.components.AppComponent; -import com.habitrpg.android.habitica.ui.SpeechBubbleView; -import com.habitrpg.android.habitica.ui.fragments.BaseFragment; -import com.habitrpg.android.habitica.ui.views.HabiticaIconsHelper; - -import butterknife.BindView; -import butterknife.ButterKnife; - -public class WelcomeFragment extends BaseFragment { - - @BindView(R.id.speech_bubble) - SpeechBubbleView speechBubbleView; - - @BindView(R.id.heart_icon) - ImageView heartIconView; - @BindView(R.id.exp_icon) - ImageView expIconView; - @BindView(R.id.magic_icon) - ImageView magicIconView; - @BindView(R.id.gold_icon) - ImageView goldIconView; - @BindView(R.id.gem_icon) - ImageView gemIconView; - - @Nullable - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - super.onCreateView(inflater, container, savedInstanceState); - View v = inflater.inflate(R.layout.fragment_welcome, container, false); - - setUnbinder(ButterKnife.bind(this, v)); - - speechBubbleView.animateText(getContext().getString(R.string.welcome_text)); - - heartIconView.setImageBitmap(HabiticaIconsHelper.imageOfHeartLightBg()); - expIconView.setImageBitmap(HabiticaIconsHelper.imageOfExperience()); - magicIconView.setImageBitmap(HabiticaIconsHelper.imageOfMagic()); - goldIconView.setImageBitmap(HabiticaIconsHelper.imageOfGold()); - gemIconView.setImageBitmap(HabiticaIconsHelper.imageOfGem()); - - return v; - } - - @Override - public void injectFragment(AppComponent component) { - component.inject(this); - } -} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/setup/WelcomeFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/setup/WelcomeFragment.kt new file mode 100644 index 000000000..4fb265b25 --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/setup/WelcomeFragment.kt @@ -0,0 +1,49 @@ +package com.habitrpg.android.habitica.ui.fragments.setup + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import com.habitrpg.android.habitica.R +import com.habitrpg.android.habitica.components.AppComponent +import com.habitrpg.android.habitica.extensions.inflate +import com.habitrpg.android.habitica.ui.SpeechBubbleView +import com.habitrpg.android.habitica.ui.fragments.BaseFragment +import com.habitrpg.android.habitica.ui.helpers.bindView +import com.habitrpg.android.habitica.ui.helpers.resetViews +import com.habitrpg.android.habitica.ui.views.HabiticaIconsHelper + +class WelcomeFragment : BaseFragment() { + + private val speechBubbleView: SpeechBubbleView? by bindView(R.id.speech_bubble) + private val heartIconView: ImageView? by bindView(R.id.heart_icon) + private val magicIconView: ImageView? by bindView(R.id.magic_icon) + private val expIconView: ImageView? by bindView(R.id.exp_icon) + private val goldIconView: ImageView? by bindView(R.id.gold_icon) + private val gemIconView: ImageView? by bindView(R.id.gem_icon) + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + super.onCreateView(inflater, container, savedInstanceState) + + return container?.inflate(R.layout.fragment_welcome) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + resetViews() + + speechBubbleView?.animateText(context?.getString(R.string.welcome_text)) + + heartIconView?.setImageBitmap(HabiticaIconsHelper.imageOfHeartLightBg()) + expIconView?.setImageBitmap(HabiticaIconsHelper.imageOfExperience()) + magicIconView?.setImageBitmap(HabiticaIconsHelper.imageOfMagic()) + goldIconView?.setImageBitmap(HabiticaIconsHelper.imageOfGold()) + gemIconView?.setImageBitmap(HabiticaIconsHelper.imageOfGem()) + } + + override fun injectFragment(component: AppComponent) { + component.inject(this) + } +} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/GuildsOverviewFragment.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/GuildsOverviewFragment.java deleted file mode 100644 index 47ab771a9..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/GuildsOverviewFragment.java +++ /dev/null @@ -1,141 +0,0 @@ -package com.habitrpg.android.habitica.ui.fragments.social; - -import android.content.Context; -import android.os.Bundle; -import android.support.v4.widget.SwipeRefreshLayout; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.Button; -import android.widget.LinearLayout; -import android.widget.TextView; - -import com.habitrpg.android.habitica.R; -import com.habitrpg.android.habitica.components.AppComponent; -import com.habitrpg.android.habitica.data.ChallengeRepository; -import com.habitrpg.android.habitica.data.SocialRepository; -import com.habitrpg.android.habitica.helpers.RxErrorHandler; -import com.habitrpg.android.habitica.models.social.Group; -import com.habitrpg.android.habitica.ui.fragments.BaseMainFragment; - -import java.util.ArrayList; -import java.util.List; - -import javax.inject.Inject; - -import butterknife.BindView; -import butterknife.ButterKnife; -import io.realm.RealmResults; - -public class GuildsOverviewFragment extends BaseMainFragment implements View.OnClickListener, SwipeRefreshLayout.OnRefreshListener { - - @Inject - SocialRepository socialRepository; - @Inject - ChallengeRepository challengeRepository; - - @BindView(R.id.my_guilds_listview) - LinearLayout guildsListView; - @BindView(R.id.publicGuildsButton) - Button publicGuildsButton; - @BindView(R.id.chat_refresh_layout) - SwipeRefreshLayout swipeRefreshLayout; - - private List guilds; - private ArrayList guildIDs; - - @Override - public void onCreate(Bundle savedInstance) { - super.onCreate(savedInstance); - this.fetchGuilds(); - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - super.onCreateView(inflater, container, savedInstanceState); - View v = inflater.inflate(R.layout.fragment_guilds_overview, container, false); - setUnbinder(ButterKnife.bind(this, v)); - swipeRefreshLayout.setOnRefreshListener(this); - this.publicGuildsButton.setOnClickListener(this); - getCompositeSubscription().add(socialRepository.getUserGroups().subscribe(this::setGuilds, RxErrorHandler.handleEmptyError())); - return v; - } - - @Override - public void onDestroy() { - socialRepository.close(); - challengeRepository.close(); - super.onDestroy(); - } - - @Override - public void injectFragment(AppComponent component) { - component.inject(this); - } - - @Override - public void onRefresh() { - if (swipeRefreshLayout != null) { - swipeRefreshLayout.setRefreshing(true); - } - fetchGuilds(); - } - - private void fetchGuilds() { - if (this.socialRepository != null) { - this.socialRepository.retrieveGroups("guilds") - .subscribe(groups -> { - if (swipeRefreshLayout != null) { - swipeRefreshLayout.setRefreshing(false); - } - }, RxErrorHandler.handleEmptyError()); - } - } - - private void setGuilds(RealmResults guilds) { - this.guilds = guilds; - if (this.guildsListView == null) { - return; - } - this.guildIDs = new ArrayList<>(); - this.guildsListView.removeAllViewsInLayout(); - LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); - for (Group guild : this.guilds) { - TextView entry = (TextView) inflater.inflate(R.layout.plain_list_item, this.guildsListView, false); - entry.setText(guild.getName()); - entry.setOnClickListener(this); - this.guildsListView.addView(entry); - this.guildIDs.add(guild.getId()); - } - } - - @Override - public void onClick(View v) { - BaseMainFragment fragment; - if (v == this.publicGuildsButton) { - PublicGuildsFragment publicGuildsFragment = new PublicGuildsFragment(); - publicGuildsFragment.memberGuildIDs = this.guildIDs; - fragment = publicGuildsFragment; - } else { - Integer guildIndex = ((ViewGroup) v.getParent()).indexOfChild(v); - GuildFragment guildFragment = new GuildFragment(); - guildFragment.setGuildId(this.guilds.get(guildIndex).getId()); - guildFragment.isMember = true; - fragment = guildFragment; - } - if (this.activity != null) { - this.activity.displayFragment(fragment); - } - } - - - @Override - public String customTitle() { - if (isAdded()) { - return getString(R.string.sidebar_guilds); - } else { - return ""; - } - } -} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/GuildsOverviewFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/GuildsOverviewFragment.kt new file mode 100644 index 000000000..814fd48b8 --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/GuildsOverviewFragment.kt @@ -0,0 +1,126 @@ +package com.habitrpg.android.habitica.ui.fragments.social + +import android.content.Context +import android.os.Bundle +import android.support.v4.widget.SwipeRefreshLayout +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.Button +import android.widget.LinearLayout +import android.widget.TextView +import com.habitrpg.android.habitica.R +import com.habitrpg.android.habitica.components.AppComponent +import com.habitrpg.android.habitica.data.ChallengeRepository +import com.habitrpg.android.habitica.data.SocialRepository +import com.habitrpg.android.habitica.extensions.inflate +import com.habitrpg.android.habitica.helpers.RxErrorHandler +import com.habitrpg.android.habitica.models.social.Group +import com.habitrpg.android.habitica.ui.fragments.BaseMainFragment +import com.habitrpg.android.habitica.ui.helpers.bindView +import com.habitrpg.android.habitica.ui.helpers.resetViews +import io.reactivex.functions.Consumer +import io.realm.RealmResults +import java.util.* +import javax.inject.Inject + +class GuildsOverviewFragment : BaseMainFragment(), View.OnClickListener, SwipeRefreshLayout.OnRefreshListener { + + @Inject + lateinit var socialRepository: SocialRepository + @Inject + lateinit var challengeRepository: ChallengeRepository + + private val guildsListView: LinearLayout? by bindView(R.id.my_guilds_listview) + private val publicGuildsButton: Button? by bindView(R.id.publicGuildsButton) + private val swipeRefreshLayout: SwipeRefreshLayout? by bindView(R.id.chat_refresh_layout) + + private var guilds: List? = null + private var guildIDs: ArrayList? = null + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + this.fetchGuilds() + } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle?): View? { + super.onCreateView(inflater, container, savedInstanceState) + return container?.inflate(R.layout.fragment_guilds_overview) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + resetViews() + + swipeRefreshLayout?.setOnRefreshListener(this) + this.publicGuildsButton?.setOnClickListener(this) + compositeSubscription.add(socialRepository.getUserGroups().subscribe(Consumer { this.setGuilds(it) }, RxErrorHandler.handleEmptyError())) + } + override fun onDestroy() { + socialRepository.close() + challengeRepository.close() + super.onDestroy() + } + + override fun injectFragment(component: AppComponent) { + component.inject(this) + } + + override fun onRefresh() { + if (swipeRefreshLayout != null) { + swipeRefreshLayout?.isRefreshing = true + } + fetchGuilds() + } + + private fun fetchGuilds() { + this.socialRepository.retrieveGroups("guilds") + .subscribe(Consumer { + swipeRefreshLayout?.isRefreshing = false + }, RxErrorHandler.handleEmptyError()) + } + + private fun setGuilds(guilds: RealmResults) { + this.guilds = guilds + if (this.guildsListView == null) { + return + } + this.guildIDs = ArrayList() + this.guildsListView?.removeAllViewsInLayout() + val inflater = context?.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater + for (guild in guilds) { + val entry = inflater.inflate(R.layout.plain_list_item, this.guildsListView, false) as TextView + entry.text = guild.name + entry.setOnClickListener(this) + this.guildsListView?.addView(entry) + this.guildIDs?.add(guild.id) + } + } + + override fun onClick(v: View) { + val fragment: BaseMainFragment + if (v === this.publicGuildsButton) { + val publicGuildsFragment = PublicGuildsFragment() + publicGuildsFragment.memberGuildIDs = this.guildIDs + fragment = publicGuildsFragment + } else { + val guildIndex = (v.parent as ViewGroup).indexOfChild(v) + val guildFragment = GuildFragment() + guildFragment.setGuildId(this.guilds?.get(guildIndex)?.id) + guildFragment.isMember = true + fragment = guildFragment + } + activity?.displayFragment(fragment) + } + + + override fun customTitle(): String { + return if (isAdded) { + getString(R.string.sidebar_guilds) + } else { + "" + } + } +} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/PublicGuildsFragment.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/PublicGuildsFragment.java deleted file mode 100644 index ed347b46e..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/PublicGuildsFragment.java +++ /dev/null @@ -1,127 +0,0 @@ -package com.habitrpg.android.habitica.ui.fragments.social; - -import android.os.Bundle; -import android.support.annotation.Nullable; -import android.support.v4.content.ContextCompat; -import android.support.v7.widget.DividerItemDecoration; -import android.support.v7.widget.LinearLayoutManager; -import android.support.v7.widget.RecyclerView; -import android.support.v7.widget.SearchView; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; - -import com.habitrpg.android.habitica.R; -import com.habitrpg.android.habitica.components.AppComponent; -import com.habitrpg.android.habitica.data.SocialRepository; -import com.habitrpg.android.habitica.helpers.RxErrorHandler; -import com.habitrpg.android.habitica.ui.adapter.social.PublicGuildsRecyclerViewAdapter; -import com.habitrpg.android.habitica.ui.fragments.BaseMainFragment; -import com.habitrpg.android.habitica.ui.helpers.SafeDefaultItemAnimator; -import com.habitrpg.android.habitica.ui.helpers.UiUtils; - -import java.util.List; - -import javax.inject.Inject; - -import butterknife.BindView; -import butterknife.ButterKnife; - -public class PublicGuildsFragment extends BaseMainFragment implements SearchView.OnQueryTextListener { - - @Inject - SocialRepository socialRepository; - - List memberGuildIDs; - - @BindView(R.id.recyclerView) - RecyclerView recyclerView; - - private View view; - private PublicGuildsRecyclerViewAdapter viewAdapter; - - @Nullable - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - super.onCreateView(inflater, container, savedInstanceState); - view = inflater.inflate(R.layout.fragment_recyclerview, container, false); - - setUnbinder(ButterKnife.bind(this, view)); - recyclerView.setLayoutManager(new LinearLayoutManager(this.activity)); - recyclerView.addItemDecoration(new DividerItemDecoration(getActivity(), DividerItemDecoration.VERTICAL)); - viewAdapter = new PublicGuildsRecyclerViewAdapter(null, true); - viewAdapter.setMemberGuildIDs(this.memberGuildIDs); - viewAdapter.apiClient = this.apiClient; - recyclerView.setAdapter(viewAdapter); - recyclerView.setItemAnimator(new SafeDefaultItemAnimator()); - this.fetchGuilds(); - return view; - } - - @Override - public void injectFragment(AppComponent component) { - component.inject(this); - } - - @Override - public void onCreate(Bundle savedInstance) { - super.onCreate(savedInstance); - } - - @Override - public void onDestroy() { - socialRepository.close(); - super.onDestroy(); - } - - private void fetchGuilds() { - if (this.socialRepository != null) { - this.socialRepository.getPublicGuilds() - .firstElement() - .subscribe(groups -> { - if (PublicGuildsFragment.this.viewAdapter != null) { - PublicGuildsFragment.this.viewAdapter.updateData(groups); - } - }, RxErrorHandler.handleEmptyError()); - this.socialRepository.retrieveGroups("publicGuilds").subscribe(groups -> {}, RxErrorHandler.handleEmptyError()); - } - } - - @Override - public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { - inflater.inflate(R.menu.menu_public_guild, menu); - - MenuItem searchItem = menu.findItem(R.id.action_guild_search); - SearchView guildSearchView = (SearchView) searchItem.getActionView(); - SearchView.SearchAutoComplete theTextArea = guildSearchView.findViewById(R.id.search_src_text); - theTextArea.setHintTextColor(ContextCompat.getColor(getContext(), R.color.white)); - guildSearchView.setQueryHint(getString(R.string.guild_search_hint)); - guildSearchView.setOnQueryTextListener(this); - } - - @Override - public boolean onQueryTextSubmit(String s) { - viewAdapter.getFilter().filter(s); - if (this.activity != null) { - UiUtils.dismissKeyboard(this.activity); - } - return true; - } - - @Override - public boolean onQueryTextChange(String s) { - viewAdapter.getFilter().filter(s); - return true; - } - - @Override - public String customTitle() { - if (!isAdded()) { - return ""; - } - return getString(R.string.public_guilds); - } -} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/PublicGuildsFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/PublicGuildsFragment.kt new file mode 100644 index 000000000..a03a6d110 --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/PublicGuildsFragment.kt @@ -0,0 +1,102 @@ +package com.habitrpg.android.habitica.ui.fragments.social + +import android.os.Bundle +import android.support.v4.content.ContextCompat +import android.support.v7.widget.DividerItemDecoration +import android.support.v7.widget.LinearLayoutManager +import android.support.v7.widget.RecyclerView +import android.support.v7.widget.SearchView +import android.view.* +import com.habitrpg.android.habitica.R +import com.habitrpg.android.habitica.components.AppComponent +import com.habitrpg.android.habitica.data.SocialRepository +import com.habitrpg.android.habitica.extensions.inflate +import com.habitrpg.android.habitica.helpers.RxErrorHandler +import com.habitrpg.android.habitica.ui.adapter.social.PublicGuildsRecyclerViewAdapter +import com.habitrpg.android.habitica.ui.fragments.BaseMainFragment +import com.habitrpg.android.habitica.ui.helpers.SafeDefaultItemAnimator +import com.habitrpg.android.habitica.ui.helpers.UiUtils +import com.habitrpg.android.habitica.ui.helpers.bindView +import com.habitrpg.android.habitica.ui.helpers.resetViews +import io.reactivex.functions.Consumer +import javax.inject.Inject + +class PublicGuildsFragment : BaseMainFragment(), SearchView.OnQueryTextListener { + + @Inject + lateinit var socialRepository: SocialRepository + + var memberGuildIDs: List? = null + + private val recyclerView: RecyclerView? by bindView(R.id.recyclerView) + + private var viewAdapter = PublicGuildsRecyclerViewAdapter(null, true) + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + super.onCreateView(inflater, container, savedInstanceState) + return container?.inflate(R.layout.fragment_recyclerview) + } + + override fun injectFragment(component: AppComponent) { + component.inject(this) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + resetViews() + + recyclerView?.layoutManager = LinearLayoutManager(this.activity) + recyclerView?.addItemDecoration(DividerItemDecoration(getActivity()!!, DividerItemDecoration.VERTICAL)) + viewAdapter.setMemberGuildIDs(this.memberGuildIDs) + viewAdapter.apiClient = this.apiClient + viewAdapter = PublicGuildsRecyclerViewAdapter(null, true) + recyclerView?.adapter = viewAdapter + recyclerView?.itemAnimator = SafeDefaultItemAnimator() + this.fetchGuilds() + } + + override fun onDestroy() { + socialRepository.close() + super.onDestroy() + } + + private fun fetchGuilds() { + this.socialRepository.getPublicGuilds() + .firstElement() + .subscribe(Consumer { groups -> + this@PublicGuildsFragment.viewAdapter.updateData(groups) + }, RxErrorHandler.handleEmptyError()) + this.socialRepository.retrieveGroups("publicGuilds").subscribe(Consumer { }, RxErrorHandler.handleEmptyError()) + } + + override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) { + inflater!!.inflate(R.menu.menu_public_guild, menu) + + val searchItem = menu!!.findItem(R.id.action_guild_search) + val guildSearchView = searchItem.actionView as SearchView + val theTextArea = guildSearchView.findViewById(R.id.search_src_text) + theTextArea.setHintTextColor(ContextCompat.getColor(context!!, R.color.white)) + guildSearchView.queryHint = getString(R.string.guild_search_hint) + guildSearchView.setOnQueryTextListener(this) + } + + override fun onQueryTextSubmit(s: String): Boolean { + viewAdapter.filter.filter(s) + if (this.activity != null) { + UiUtils.dismissKeyboard(this.activity!!) + } + return true + } + + override fun onQueryTextChange(s: String): Boolean { + viewAdapter.filter.filter(s) + return true + } + + override fun customTitle(): String { + return if (!isAdded) { + "" + } else getString(R.string.public_guilds) + } +} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/QuestDetailFragment.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/QuestDetailFragment.java index 1908eb463..d25848678 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/QuestDetailFragment.java +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/QuestDetailFragment.java @@ -165,7 +165,8 @@ public class QuestDetailFragment extends BaseMainFragment { return; } questTitleView.setText(questContent.getText()); - questDescriptionView.setText(MarkdownParser.parseMarkdown(questContent.getNotes())); + //TODO: FIX + //questDescriptionView.setText(MarkdownParser.parseMarkdown(questContent.getNotes())); DataBindingUtils.INSTANCE.loadImage(questScrollImageView, "inventory_quest_scroll_"+questContent.getKey()); } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/challenges/ChallengeDetailDialogHolder.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/challenges/ChallengeDetailDialogHolder.java deleted file mode 100644 index f17b687e9..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/challenges/ChallengeDetailDialogHolder.java +++ /dev/null @@ -1,337 +0,0 @@ -package com.habitrpg.android.habitica.ui.fragments.social.challenges; - -import android.app.Activity; -import android.app.AlertDialog; -import android.content.Intent; -import android.os.Bundle; -import android.support.annotation.Nullable; -import android.view.View; -import android.widget.Button; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.TextView; - -import com.habitrpg.android.habitica.R; -import com.habitrpg.android.habitica.data.ChallengeRepository; -import com.habitrpg.android.habitica.helpers.RxErrorHandler; -import com.habitrpg.android.habitica.models.LeaveChallengeBody; -import com.habitrpg.android.habitica.models.social.Challenge; -import com.habitrpg.android.habitica.models.tasks.Task; -import com.habitrpg.android.habitica.ui.activities.ChallengeDetailActivity; -import com.habitrpg.android.habitica.ui.activities.FullProfileActivity; -import com.habitrpg.android.habitica.ui.helpers.MarkdownParser; -import com.habitrpg.android.habitica.ui.views.HabiticaIconsHelper; -import com.habitrpg.android.habitica.utils.Action1; - -import net.pherth.android.emoji_library.EmojiParser; -import net.pherth.android.emoji_library.EmojiTextView; - -import java.util.ArrayList; -import java.util.Map; - -import butterknife.BindView; -import butterknife.ButterKnife; -import butterknife.OnClick; - -public class ChallengeDetailDialogHolder { - - - @BindView(R.id.challenge_not_joined_header) - LinearLayout notJoinedHeader; - - @BindView(R.id.challenge_joined_header) - LinearLayout joinedHeader; - - @BindView(R.id.challenge_join_btn) - Button joinButton; - - @BindView(R.id.challenge_leave_btn) - Button leaveButton; - - @BindView(R.id.challenge_name) - EmojiTextView challengeName; - - @BindView(R.id.challenge_description) - EmojiTextView challengeDescription; - - @BindView(R.id.challenge_leader) - TextView challengeLeader; - - @BindView(R.id.gem_amount) - TextView gem_amount; - - @BindView(R.id.challenge_member_count) - TextView member_count; - - @BindView(R.id.task_group_layout) - LinearLayout task_group_layout; - - private AlertDialog dialog; - private ChallengeRepository challengeRepository; - @Nullable - private Challenge challenge; - private Action1 challengeLeftAction; - private Activity context; - - - private ChallengeDetailDialogHolder(View view, Activity context) { - this.context = context; - ButterKnife.bind(this, view); - } - - public static void showDialog(Activity activity, ChallengeRepository challengeRepository, Challenge challenge, Action1 challengeLeftAction) { - if (activity == null) { - return; - } - View dialogLayout = activity.getLayoutInflater().inflate(R.layout.dialog_challenge_detail, null); - - ChallengeDetailDialogHolder challengeDetailDialogHolder = new ChallengeDetailDialogHolder(dialogLayout, activity); - - AlertDialog.Builder builder = new AlertDialog.Builder(activity) - .setView(dialogLayout); - - challengeDetailDialogHolder.bind(builder.show(), challengeRepository, challenge, challengeLeftAction); - } - - public void bind(AlertDialog dialog, ChallengeRepository challengeRepository, Challenge challenge, - Action1 challengeLeftAction) { - this.dialog = dialog; - this.challengeRepository = challengeRepository; - this.challenge = challenge; - this.challengeLeftAction = challengeLeftAction; - - changeViewsByChallenge(challenge); - } - - private void changeViewsByChallenge(Challenge challenge) { - setJoined(challenge.isParticipating); - - challengeName.setText(EmojiParser.parseEmojis(challenge.name)); - challengeDescription.setText(MarkdownParser.parseMarkdown(challenge.description)); - challengeLeader.setText(challenge.leaderName); - - gem_amount.setText(String.valueOf(challenge.prize)); - member_count.setText(String.valueOf(challenge.memberCount)); - - challengeRepository.getChallengeTasks(challenge.id) - .subscribe(taskList -> { - ArrayList todos = new ArrayList<>(); - ArrayList habits = new ArrayList<>(); - ArrayList dailies = new ArrayList<>(); - ArrayList rewards = new ArrayList<>(); - - for (Map.Entry entry : taskList.tasks.entrySet()) { - switch (entry.getValue().getType()) { - case Task.TYPE_TODO: - todos.add(entry.getValue()); - break; - case Task.TYPE_HABIT: - - habits.add(entry.getValue()); - break; - case Task.TYPE_DAILY: - - dailies.add(entry.getValue()); - break; - case Task.TYPE_REWARD: - - rewards.add(entry.getValue()); - break; - } - } - - if (habits.size() > 0) { - addHabits(habits); - } - - if (dailies.size() > 0) { - addDailys(dailies); - } - - if (todos.size() > 0) { - addTodos(todos); - } - - if (rewards.size() > 0) { - addRewards(rewards); - } - }, RxErrorHandler.handleEmptyError()); - } - - private void addHabits(ArrayList habits) { - LinearLayout taskGroup = (LinearLayout) context.getLayoutInflater().inflate(R.layout.dialog_challenge_detail_task_group, task_group_layout, false); - TextView groupName = (TextView) taskGroup.findViewById(R.id.task_group_name); - - LinearLayout tasks_layout = (LinearLayout) taskGroup.findViewById(R.id.tasks_layout); - - groupName.setText(habits.size() + " " + getLabelByTypeAndCount(Challenge.TASK_ORDER_HABITS, habits.size())); - - int size = habits.size(); - for (int i = 0; i < size; i++) { - Task task = habits.get(i); - - View entry = context.getLayoutInflater().inflate(R.layout.dialog_challenge_detail_habit, tasks_layout, false); - TextView habitTitle = (TextView) entry.findViewById(R.id.habit_title); - ImageView plusImg = (ImageView) entry.findViewById(task.getUp() ? R.id.plus_img_tinted : R.id.plus_img); - ImageView minusImg = (ImageView) entry.findViewById(task.getDown() ? R.id.minus_img_tinted : R.id.minus_img); - - plusImg.setVisibility(View.VISIBLE); - minusImg.setVisibility(View.VISIBLE); - - habitTitle.setText(EmojiParser.parseEmojis(task.getText())); - tasks_layout.addView(entry); - } - task_group_layout.addView(taskGroup); - } - - private void addDailys(ArrayList dailies) { - LinearLayout taskGroup = (LinearLayout) context.getLayoutInflater().inflate(R.layout.dialog_challenge_detail_task_group, task_group_layout, false); - TextView groupName = (TextView) taskGroup.findViewById(R.id.task_group_name); - - LinearLayout tasks_layout = (LinearLayout) taskGroup.findViewById(R.id.tasks_layout); - - int size = dailies.size(); - groupName.setText(dailies.size() + " " + getLabelByTypeAndCount(Challenge.TASK_ORDER_DAILYS, size)); - - for (int i = 0; i < size; i++) { - Task task = dailies.get(i); - - View entry = context.getLayoutInflater().inflate(R.layout.dialog_challenge_detail_daily, tasks_layout, false); - TextView title = (TextView) entry.findViewById(R.id.daily_title); - title.setText(EmojiParser.parseEmojis(task.getText())); - - if (task.getChecklist() != null && !task.getChecklist().isEmpty()) { - View checklistIndicatorWrapper = entry.findViewById(R.id.checklistIndicatorWrapper); - - checklistIndicatorWrapper.setVisibility(View.VISIBLE); - - TextView checkListAllTextView = (TextView) entry.findViewById(R.id.checkListAllTextView); - checkListAllTextView.setText(String.valueOf(task.getChecklist().size())); - } - tasks_layout.addView(entry); - } - task_group_layout.addView(taskGroup); - } - - private void addTodos(ArrayList todos) { - LinearLayout taskGroup = (LinearLayout) context.getLayoutInflater().inflate(R.layout.dialog_challenge_detail_task_group, task_group_layout, false); - TextView groupName = (TextView) taskGroup.findViewById(R.id.task_group_name); - - LinearLayout tasks_layout = (LinearLayout) taskGroup.findViewById(R.id.tasks_layout); - - int size = todos.size(); - groupName.setText(todos.size() + " " + getLabelByTypeAndCount(Challenge.TASK_ORDER_TODOS, size)); - - for (int i = 0; i < size; i++) { - Task task = todos.get(i); - - View entry = context.getLayoutInflater().inflate(R.layout.dialog_challenge_detail_todo, tasks_layout, false); - TextView title = (TextView) entry.findViewById(R.id.todo_title); - title.setText(EmojiParser.parseEmojis(task.getText())); - - if (task.getChecklist() != null && !task.getChecklist().isEmpty()) { - View checklistIndicatorWrapper = entry.findViewById(R.id.checklistIndicatorWrapper); - - checklistIndicatorWrapper.setVisibility(View.VISIBLE); - - TextView checkListAllTextView = (TextView) entry.findViewById(R.id.checkListAllTextView); - checkListAllTextView.setText(String.valueOf(task.getChecklist().size())); - } - tasks_layout.addView(entry); - } - task_group_layout.addView(taskGroup); - } - - private void addRewards(ArrayList rewards) { - LinearLayout taskGroup = (LinearLayout) context.getLayoutInflater().inflate(R.layout.dialog_challenge_detail_task_group, task_group_layout, false); - TextView groupName = (TextView) taskGroup.findViewById(R.id.task_group_name); - - LinearLayout tasks_layout = (LinearLayout) taskGroup.findViewById(R.id.tasks_layout); - - int size = rewards.size(); - groupName.setText(rewards.size() + " " + getLabelByTypeAndCount(Challenge.TASK_ORDER_REWARDS, size)); - - for (int i = 0; i < size; i++) { - Task task = rewards.get(i); - - View entry = context.getLayoutInflater().inflate(R.layout.dialog_challenge_detail_reward, tasks_layout, false); - ((ImageView)entry.findViewById(R.id.gold_icon)).setImageBitmap(HabiticaIconsHelper.imageOfGold()); - TextView title = (TextView) entry.findViewById(R.id.reward_title); - title.setText(EmojiParser.parseEmojis(task.getText())); - tasks_layout.addView(entry); - } - task_group_layout.addView(taskGroup); - } - - private String getLabelByTypeAndCount(String type, int count) { - if (Challenge.TASK_ORDER_DAILYS.equals(type)) { - return context.getString(count == 1 ? R.string.daily : R.string.dailies); - } else if (Challenge.TASK_ORDER_HABITS.equals(type)) { - return context.getString(count == 1 ? R.string.habit : R.string.habits); - } else if (Challenge.TASK_ORDER_REWARDS.equals(type)) { - return context.getString(count == 1 ? R.string.reward : R.string.rewards); - } else { - return context.getString(count == 1 ? R.string.todo : R.string.todos); - } - } - - private void setJoined(boolean joined) { - joinedHeader.setVisibility(joined ? View.VISIBLE : View.GONE); - leaveButton.setVisibility(joined ? View.VISIBLE : View.GONE); - - notJoinedHeader.setVisibility(joined ? View.GONE : View.VISIBLE); - joinButton.setVisibility(joined ? View.GONE : View.VISIBLE); - } - - @OnClick(R.id.challenge_leader) - void openLeaderProfile() { - FullProfileActivity.open(context, challenge.leaderId); - } - - @OnClick(R.id.challenge_go_to_btn) - void openChallengeActivity() { - Bundle bundle = new Bundle(); - bundle.putString(ChallengeDetailActivity.CHALLENGE_ID, challenge.id); - - Intent intent = new Intent(context, ChallengeDetailActivity.class); - intent.putExtras(bundle); - context.startActivity(intent); - this.dialog.dismiss(); - } - - @OnClick(R.id.challenge_join_btn) - void joinChallenge() { - this.challengeRepository.joinChallenge(challenge).subscribe(this::changeViewsByChallenge, RxErrorHandler.handleEmptyError()); - } - - @OnClick(R.id.challenge_leave_btn) - void leaveChallenge() { - new AlertDialog.Builder(context) - .setTitle(context.getString(R.string.challenge_leave_title)) - .setMessage(context.getString(R.string.challenge_leave_text, challenge.name)) - .setPositiveButton(context.getString(R.string.yes), (dialog, which) -> - showRemoveTasksDialog(keepTasks -> this.challengeRepository.leaveChallenge(challenge, new LeaveChallengeBody(keepTasks)) - .subscribe(aVoid -> { - if (challengeLeftAction != null) { - challengeLeftAction.call(challenge); - } - this.dialog.dismiss(); - }, RxErrorHandler.handleEmptyError()))) - .setNegativeButton(context.getString(R.string.no), (dialog, which) -> dialog.dismiss()).show(); - } - - // refactor as an UseCase later - see ChallengeDetailActivity - private void showRemoveTasksDialog(Action1 callback){ - new AlertDialog.Builder(context) - .setTitle(context.getString(R.string.challenge_remove_tasks_title)) - .setMessage(context.getString(R.string.challenge_remove_tasks_text)) - .setPositiveButton(context.getString(R.string.remove_tasks), (dialog, which) -> { - callback.call("remove-all"); - dialog.dismiss(); - }) - .setNegativeButton(context.getString(R.string.keep_tasks), (dialog, which) -> { - callback.call("keep-all"); - dialog.dismiss(); - }).show(); - } -} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/challenges/ChallengeDetailDialogHolder.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/challenges/ChallengeDetailDialogHolder.kt new file mode 100644 index 000000000..42ed3d389 --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/challenges/ChallengeDetailDialogHolder.kt @@ -0,0 +1,307 @@ +package com.habitrpg.android.habitica.ui.fragments.social.challenges + +import android.app.Activity +import android.app.AlertDialog +import android.content.Intent +import android.os.Bundle +import android.view.View +import android.widget.Button +import android.widget.ImageView +import android.widget.LinearLayout +import android.widget.TextView +import com.habitrpg.android.habitica.R +import com.habitrpg.android.habitica.data.ChallengeRepository +import com.habitrpg.android.habitica.extensions.notNull +import com.habitrpg.android.habitica.helpers.RxErrorHandler +import com.habitrpg.android.habitica.models.LeaveChallengeBody +import com.habitrpg.android.habitica.models.social.Challenge +import com.habitrpg.android.habitica.models.tasks.Task +import com.habitrpg.android.habitica.ui.activities.ChallengeDetailActivity +import com.habitrpg.android.habitica.ui.activities.FullProfileActivity +import com.habitrpg.android.habitica.ui.helpers.MarkdownParser +import com.habitrpg.android.habitica.ui.helpers.bindView +import com.habitrpg.android.habitica.ui.views.HabiticaIconsHelper +import com.habitrpg.android.habitica.utils.Action1 +import io.reactivex.functions.Consumer +import net.pherth.android.emoji_library.EmojiParser +import net.pherth.android.emoji_library.EmojiTextView +import java.util.* + +class ChallengeDetailDialogHolder private constructor(view: View, private val context: Activity) { + + private val notJoinedHeader: LinearLayout? by bindView(view, R.id.challenge_not_joined_header) + private val joinedHeader: LinearLayout? by bindView(view, R.id.challenge_joined_header) + private val joinButton: Button? by bindView(view, R.id.challenge_join_btn) + private val leaveButton: Button? by bindView(view, R.id.challenge_leave_btn) + private val challengeName: EmojiTextView? by bindView(view, R.id.challenge_name) + private val challengeDescription: EmojiTextView? by bindView(view, R.id.challenge_description) + private val challengeLeader: TextView? by bindView(view, R.id.challenge_leader) + private val gemAmountView: TextView? by bindView(view, R.id.gem_amount) + private val memberCountView: TextView? by bindView(view, R.id.challenge_member_count) + private val taskGrouplayout: LinearLayout? by bindView(view, R.id.task_group_layout) + private val openChallengeButton: Button? by bindView(view, R.id.challenge_go_to_btn) + + private var dialog: AlertDialog? = null + lateinit var challengeRepository: ChallengeRepository + private var challenge: Challenge? = null + private var challengeLeftAction: Action1? = null + + init { + joinButton?.setOnClickListener { joinChallenge() } + leaveButton?.setOnClickListener { leaveChallenge() } + challengeLeader?.setOnClickListener { openLeaderProfile() } + openChallengeButton?.setOnClickListener { openChallengeActivity() } + } + + fun bind(dialog: AlertDialog, challengeRepository: ChallengeRepository, challenge: Challenge, + challengeLeftAction: Action1) { + this.dialog = dialog + this.challengeRepository = challengeRepository + this.challenge = challenge + this.challengeLeftAction = challengeLeftAction + + changeViewsByChallenge(challenge) + } + + private fun changeViewsByChallenge(challenge: Challenge) { + setJoined(challenge.isParticipating) + + challengeName?.text = EmojiParser.parseEmojis(challenge.name) + challengeDescription?.text = MarkdownParser.parseMarkdown(challenge.description) + challengeLeader?.text = challenge.leaderName + + gemAmountView?.text = challenge.prize.toString() + memberCountView?.text = challenge.memberCount.toString() + + challengeRepository.getChallengeTasks(challenge.id) + .subscribe(Consumer { taskList -> + val todos = ArrayList() + val habits = ArrayList() + val dailies = ArrayList() + val rewards = ArrayList() + + for (entry in taskList.tasks.entries) { + when (entry.value.type) { + Task.TYPE_TODO -> todos.add(entry.value) + Task.TYPE_HABIT -> + + habits.add(entry.value) + Task.TYPE_DAILY -> + + dailies.add(entry.value) + Task.TYPE_REWARD -> + + rewards.add(entry.value) + } + } + + if (habits.size > 0) { + addHabits(habits) + } + + if (dailies.size > 0) { + addDailys(dailies) + } + + if (todos.size > 0) { + addTodos(todos) + } + + if (rewards.size > 0) { + addRewards(rewards) + } + }, RxErrorHandler.handleEmptyError()) + } + + private fun addHabits(habits: ArrayList) { + val taskGroup = context.layoutInflater.inflate(R.layout.dialog_challenge_detail_task_group, taskGrouplayout, false) as LinearLayout + val groupName = taskGroup.findViewById(R.id.task_group_name) as TextView + + val tasksLayout = taskGroup.findViewById(R.id.tasks_layout) as LinearLayout + + groupName.text = habits.size.toString() + " " + getLabelByTypeAndCount(Challenge.TASK_ORDER_HABITS, habits.size) + + val size = habits.size + for (i in 0 until size) { + val task = habits[i] + + val entry = context.layoutInflater.inflate(R.layout.dialog_challenge_detail_habit, tasksLayout, false) + val habitTitle = entry.findViewById(R.id.habit_title) as TextView + val plusImg = entry.findViewById(if (task.up == true) R.id.plus_img_tinted else R.id.plus_img) as ImageView + val minusImg = entry.findViewById(if (task.down == true) R.id.minus_img_tinted else R.id.minus_img) as ImageView + + plusImg.visibility = View.VISIBLE + minusImg.visibility = View.VISIBLE + + habitTitle.text = EmojiParser.parseEmojis(task.text) + tasksLayout.addView(entry) + } + taskGrouplayout?.addView(taskGroup) + } + + private fun addDailys(dailies: ArrayList) { + val taskGroup = context.layoutInflater.inflate(R.layout.dialog_challenge_detail_task_group, taskGrouplayout, false) as LinearLayout + val groupName = taskGroup.findViewById(R.id.task_group_name) as TextView + + val tasksLayout = taskGroup.findViewById(R.id.tasks_layout) as LinearLayout + + val size = dailies.size + groupName.text = dailies.size.toString() + " " + getLabelByTypeAndCount(Challenge.TASK_ORDER_DAILYS, size) + + for (i in 0 until size) { + val task = dailies[i] + + val entry = context.layoutInflater.inflate(R.layout.dialog_challenge_detail_daily, tasksLayout, false) + val title = entry.findViewById(R.id.daily_title) as TextView + title.text = EmojiParser.parseEmojis(task.text) + + if (task.checklist != null && task.checklist?.isEmpty() == false) { + val checklistIndicatorWrapper = entry.findViewById(R.id.checklistIndicatorWrapper) + + checklistIndicatorWrapper.visibility = View.VISIBLE + + val checkListAllTextView = entry.findViewById(R.id.checkListAllTextView) as TextView + checkListAllTextView.text = task.checklist?.size.toString() + } + tasksLayout.addView(entry) + } + taskGrouplayout?.addView(taskGroup) + } + + private fun addTodos(todos: ArrayList) { + val taskGroup = context.layoutInflater.inflate(R.layout.dialog_challenge_detail_task_group, taskGrouplayout, false) as LinearLayout + val groupName = taskGroup.findViewById(R.id.task_group_name) as TextView + + val tasksLayout = taskGroup.findViewById(R.id.tasks_layout) as LinearLayout + + val size = todos.size + groupName.text = todos.size.toString() + " " + getLabelByTypeAndCount(Challenge.TASK_ORDER_TODOS, size) + + for (i in 0 until size) { + val task = todos[i] + + val entry = context.layoutInflater.inflate(R.layout.dialog_challenge_detail_todo, tasksLayout, false) + val title = entry.findViewById(R.id.todo_title) as TextView + title.text = EmojiParser.parseEmojis(task.text) + + if (task.checklist != null && task.checklist?.isEmpty() == false) { + val checklistIndicatorWrapper = entry.findViewById(R.id.checklistIndicatorWrapper) + + checklistIndicatorWrapper.visibility = View.VISIBLE + + val checkListAllTextView = entry.findViewById(R.id.checkListAllTextView) as TextView + checkListAllTextView.text = task.checklist?.size.toString() + } + tasksLayout.addView(entry) + } + taskGrouplayout?.addView(taskGroup) + } + + private fun addRewards(rewards: ArrayList) { + val taskGroup = context.layoutInflater.inflate(R.layout.dialog_challenge_detail_task_group, taskGrouplayout, false) as LinearLayout + val groupName = taskGroup.findViewById(R.id.task_group_name) as TextView + + val tasksLayout = taskGroup.findViewById(R.id.tasks_layout) as LinearLayout + + val size = rewards.size + groupName.text = rewards.size.toString() + " " + getLabelByTypeAndCount(Challenge.TASK_ORDER_REWARDS, size) + + for (i in 0 until size) { + val task = rewards[i] + + val entry = context.layoutInflater.inflate(R.layout.dialog_challenge_detail_reward, tasksLayout, false) + (entry.findViewById(R.id.gold_icon) as ImageView).setImageBitmap(HabiticaIconsHelper.imageOfGold()) + val title = entry.findViewById(R.id.reward_title) as TextView + title.text = EmojiParser.parseEmojis(task.text) + tasksLayout.addView(entry) + } + taskGrouplayout?.addView(taskGroup) + } + + private fun getLabelByTypeAndCount(type: String, count: Int): String { + return when (type) { + Challenge.TASK_ORDER_DAILYS -> context.getString(if (count == 1) R.string.daily else R.string.dailies) + Challenge.TASK_ORDER_HABITS -> context.getString(if (count == 1) R.string.habit else R.string.habits) + Challenge.TASK_ORDER_REWARDS -> context.getString(if (count == 1) R.string.reward else R.string.rewards) + else -> context.getString(if (count == 1) R.string.todo else R.string.todos) + } + } + + private fun setJoined(joined: Boolean) { + joinedHeader?.visibility = if (joined) View.VISIBLE else View.GONE + leaveButton?.visibility = if (joined) View.VISIBLE else View.GONE + + notJoinedHeader?.visibility = if (joined) View.GONE else View.VISIBLE + joinButton?.visibility = if (joined) View.GONE else View.VISIBLE + } + + private fun openLeaderProfile() { + FullProfileActivity.open(context, challenge?.leaderId) + } + + private fun openChallengeActivity() { + val bundle = Bundle() + bundle.putString(ChallengeDetailActivity.CHALLENGE_ID, challenge?.id) + + val intent = Intent(context, ChallengeDetailActivity::class.java) + intent.putExtras(bundle) + context.startActivity(intent) + this.dialog?.dismiss() + } + + private fun joinChallenge() { + this.challengeRepository.joinChallenge(challenge).subscribe(Consumer { this.changeViewsByChallenge(it) }, RxErrorHandler.handleEmptyError()) + } + + private fun leaveChallenge() { + AlertDialog.Builder(context) + .setTitle(context.getString(R.string.challenge_leave_title)) + .setMessage(context.getString(R.string.challenge_leave_text, challenge?.name)) + .setPositiveButton(context.getString(R.string.yes)) { dialog, _ -> + showRemoveTasksDialog(object : Action1 { + override fun call(t: String) { + challengeRepository.leaveChallenge(challenge, LeaveChallengeBody(t)) + .subscribe(Consumer { + challenge.notNull { + challengeLeftAction?.call(it) + } + dialog.dismiss() + }, RxErrorHandler.handleEmptyError()) + } + }) + } + .setNegativeButton(context.getString(R.string.no)) { dialog, _ -> dialog.dismiss() }.show() + } + + // refactor as an UseCase later - see ChallengeDetailActivity + private fun showRemoveTasksDialog(callback: Action1) { + AlertDialog.Builder(context) + .setTitle(context.getString(R.string.challenge_remove_tasks_title)) + .setMessage(context.getString(R.string.challenge_remove_tasks_text)) + .setPositiveButton(context.getString(R.string.remove_tasks)) { dialog, _ -> + callback.call("remove-all") + dialog.dismiss() + } + .setNegativeButton(context.getString(R.string.keep_tasks)) { dialog, _ -> + callback.call("keep-all") + dialog.dismiss() + }.show() + } + + companion object { + + fun showDialog(activity: Activity?, challengeRepository: ChallengeRepository, challenge: Challenge, challengeLeftAction: Action1) { + if (activity == null) { + return + } + val dialogLayout = activity.layoutInflater.inflate(R.layout.dialog_challenge_detail, null) + + val challengeDetailDialogHolder = ChallengeDetailDialogHolder(dialogLayout, activity) + + val builder = AlertDialog.Builder(activity) + .setView(dialogLayout) + + challengeDetailDialogHolder.bind(builder.show(), challengeRepository, challenge, challengeLeftAction) + } + } +} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/challenges/ChallengeFilterDialogHolder.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/challenges/ChallengeFilterDialogHolder.java deleted file mode 100644 index 2733f0794..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/challenges/ChallengeFilterDialogHolder.java +++ /dev/null @@ -1,140 +0,0 @@ -package com.habitrpg.android.habitica.ui.fragments.social.challenges; - -import android.app.Activity; -import android.app.AlertDialog; -import android.support.annotation.Nullable; -import android.support.v7.widget.LinearLayoutManager; -import android.support.v7.widget.RecyclerView; -import android.view.View; -import android.widget.Button; -import android.widget.CheckBox; - -import com.habitrpg.android.habitica.R; -import com.habitrpg.android.habitica.models.social.Challenge; -import com.habitrpg.android.habitica.models.social.Group; -import com.habitrpg.android.habitica.ui.adapter.social.challenges.ChallengesFilterRecyclerViewAdapter; -import com.habitrpg.android.habitica.utils.Action1; - -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import butterknife.BindView; -import butterknife.ButterKnife; -import butterknife.OnClick; - -class ChallengeFilterDialogHolder { - - @BindView(R.id.challenge_filter_recycler_view) - RecyclerView groupRecyclerView; - - @BindView(R.id.challenge_filter_button_all) - Button allButton; - - @BindView(R.id.challenge_filter_button_none) - Button noneButton; - - @BindView(R.id.challenge_filter_owned) - CheckBox checkboxOwned; - - @BindView(R.id.challenge_filter_not_owned) - CheckBox checkboxNotOwned; - - private AlertDialog dialog; - private List challengesViewed; - private ChallengeFilterOptions currentFilter; - private Action1 selectedGroupsCallback; - private Activity context; - private ChallengesFilterRecyclerViewAdapter adapter; - - - private ChallengeFilterDialogHolder(View view, Activity context) { - this.context = context; - ButterKnife.bind(this, view); - } - - static void showDialog(Activity activity, List challengesViewed, - ChallengeFilterOptions currentFilter, - Action1 selectedGroupsCallback) { - View dialogLayout = activity.getLayoutInflater().inflate(R.layout.dialog_challenge_filter, null); - - ChallengeFilterDialogHolder challengeFilterDialogHolder = new ChallengeFilterDialogHolder(dialogLayout, activity); - - AlertDialog.Builder builder = new AlertDialog.Builder(activity) - .setTitle(R.string.filter) - .setView(dialogLayout); - - challengeFilterDialogHolder.bind(builder, challengesViewed, currentFilter, selectedGroupsCallback); - } - - public void bind(AlertDialog.Builder builder, List challengesViewed, - ChallengeFilterOptions currentFilter, - Action1 selectedGroupsCallback) { - builder = builder - .setPositiveButton(context.getString(R.string.done), (dialog1, which) -> doneClicked()); - this.dialog = builder.show(); - this.challengesViewed = challengesViewed; - this.currentFilter = currentFilter; - this.selectedGroupsCallback = selectedGroupsCallback; - fillChallengeGroups(); - - if(currentFilter != null ){ - checkboxOwned.setChecked(currentFilter.showOwned); - checkboxNotOwned.setChecked(currentFilter.notOwned); - } - } - - private void fillChallengeGroups() { - - this.groupRecyclerView.setLayoutManager(new LinearLayoutManager(context)); - adapter = new ChallengesFilterRecyclerViewAdapter(getGroups(challengesViewed)); - if(currentFilter != null && currentFilter.showByGroups != null){ - adapter.selectAll(currentFilter.showByGroups); - } - - this.groupRecyclerView.setAdapter(adapter); - } - - private Collection getGroups(@Nullable List challenges){ - Map groupMap = new HashMap<>(); - - if (challenges != null) { - for (Challenge challenge : challenges) { - if (groupMap.containsKey(challenge.groupName)) { - continue; - } - Group group = new Group(); - group.setId(challenge.groupId); - group.setName(challenge.groupName); - - groupMap.put(challenge.groupName, group); - } - } - - return groupMap.values(); - } - - private void doneClicked() { - ChallengeFilterOptions options = new ChallengeFilterOptions(); - options.showByGroups = this.adapter.getCheckedEntries(); - options.showOwned = checkboxOwned.isChecked(); - options.notOwned = checkboxNotOwned.isChecked(); - - selectedGroupsCallback.call(options); - this.dialog.hide(); - } - - - @OnClick(R.id.challenge_filter_button_all) - void allClicked() { - this.adapter.selectAll(); - } - - @OnClick(R.id.challenge_filter_button_none) - void noneClicked() { - this.adapter.deSelectAll(); - } - -} - diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/challenges/ChallengeFilterDialogHolder.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/challenges/ChallengeFilterDialogHolder.kt new file mode 100644 index 000000000..b83d1895c --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/challenges/ChallengeFilterDialogHolder.kt @@ -0,0 +1,122 @@ +package com.habitrpg.android.habitica.ui.fragments.social.challenges + +import android.app.Activity +import android.app.AlertDialog +import android.support.v7.widget.LinearLayoutManager +import android.support.v7.widget.RecyclerView +import android.view.View +import android.widget.Button +import android.widget.CheckBox +import com.habitrpg.android.habitica.R +import com.habitrpg.android.habitica.models.social.Challenge +import com.habitrpg.android.habitica.models.social.Group +import com.habitrpg.android.habitica.ui.adapter.social.challenges.ChallengesFilterRecyclerViewAdapter +import com.habitrpg.android.habitica.ui.helpers.bindView +import com.habitrpg.android.habitica.utils.Action1 +import java.util.* + +internal class ChallengeFilterDialogHolder private constructor(view: View, private val context: Activity) { + + private val groupRecyclerView: RecyclerView? by bindView(view, R.id.challenge_filter_recycler_view) + private val allButton: Button? by bindView(view, R.id.challenge_filter_button_all) + private val noneButton: Button? by bindView(view, R.id.challenge_filter_button_none) + private val checkboxOwned: CheckBox? by bindView(view, R.id.challenge_filter_owned) + private val checkboxNotOwned: CheckBox? by bindView(view, R.id.challenge_filter_not_owned) + + private var dialog: AlertDialog? = null + private var challengesViewed: List? = null + private var currentFilter: ChallengeFilterOptions? = null + private var selectedGroupsCallback: Action1? = null + private var adapter: ChallengesFilterRecyclerViewAdapter? = null + + init { + allButton?.setOnClickListener { allClicked() } + noneButton?.setOnClickListener { noneClicked() } + } + + fun bind(builder: AlertDialog.Builder, challengesViewed: List, + currentFilter: ChallengeFilterOptions?, + selectedGroupsCallback: Action1) { + var dialogBuilder = builder + dialogBuilder = builder + .setPositiveButton(context.getString(R.string.done)) { _, _ -> doneClicked() } + this.dialog = dialogBuilder.show() + this.challengesViewed = challengesViewed + this.currentFilter = currentFilter + this.selectedGroupsCallback = selectedGroupsCallback + fillChallengeGroups() + + if (currentFilter != null) { + checkboxOwned?.isChecked = currentFilter.showOwned + checkboxNotOwned?.isChecked = currentFilter.notOwned + } + } + + private fun fillChallengeGroups() { + + this.groupRecyclerView?.layoutManager = LinearLayoutManager(context) + adapter = ChallengesFilterRecyclerViewAdapter(getGroups(challengesViewed)) + if (currentFilter != null && currentFilter?.showByGroups != null) { + adapter?.selectAll(currentFilter?.showByGroups) + } + + this.groupRecyclerView?.adapter = adapter + } + + private fun getGroups(challenges: List?): Collection { + val groupMap = HashMap() + + if (challenges != null) { + for (challenge in challenges) { + if (groupMap.containsKey(challenge.groupName)) { + continue + } + val group = Group() + group.id = challenge.groupId + group.name = challenge.groupName + + groupMap[challenge.groupName] = group + } + } + + return groupMap.values + } + + private fun doneClicked() { + val options = ChallengeFilterOptions() + options.showByGroups = this.adapter?.checkedEntries + options.showOwned = checkboxOwned?.isChecked ?: false + options.notOwned = checkboxNotOwned?.isChecked ?: false + + selectedGroupsCallback?.call(options) + this.dialog?.hide() + } + + + fun allClicked() { + this.adapter?.selectAll() + } + + fun noneClicked() { + this.adapter?.deSelectAll() + } + + companion object { + + fun showDialog(activity: Activity, challengesViewed: List, + currentFilter: ChallengeFilterOptions?, + selectedGroupsCallback: Action1) { + val dialogLayout = activity.layoutInflater.inflate(R.layout.dialog_challenge_filter, null) + + val challengeFilterDialogHolder = ChallengeFilterDialogHolder(dialogLayout, activity) + + val builder = AlertDialog.Builder(activity) + .setTitle(R.string.filter) + .setView(dialogLayout) + + challengeFilterDialogHolder.bind(builder, challengesViewed, currentFilter, selectedGroupsCallback) + } + } + +} + diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/challenges/ChallengeListFragment.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/challenges/ChallengeListFragment.java deleted file mode 100644 index 72dbbf379..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/challenges/ChallengeListFragment.java +++ /dev/null @@ -1,191 +0,0 @@ -package com.habitrpg.android.habitica.ui.fragments.social.challenges; - -import android.content.Intent; -import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v4.view.MenuItemCompat; -import android.support.v4.widget.SwipeRefreshLayout; -import android.support.v7.widget.LinearLayoutManager; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; -import android.widget.RelativeLayout; -import android.widget.TextView; - -import com.habitrpg.android.habitica.R; -import com.habitrpg.android.habitica.components.AppComponent; -import com.habitrpg.android.habitica.data.ChallengeRepository; -import com.habitrpg.android.habitica.helpers.RxErrorHandler; -import com.habitrpg.android.habitica.models.social.Challenge; -import com.habitrpg.android.habitica.modules.AppModule; -import com.habitrpg.android.habitica.ui.activities.CreateChallengeActivity; -import com.habitrpg.android.habitica.ui.adapter.social.ChallengesListViewAdapter; -import com.habitrpg.android.habitica.ui.fragments.BaseMainFragment; -import com.habitrpg.android.habitica.ui.helpers.RecyclerViewEmptySupport; -import com.habitrpg.android.habitica.ui.helpers.SafeDefaultItemAnimator; - -import javax.inject.Inject; -import javax.inject.Named; - -import butterknife.BindView; -import butterknife.ButterKnife; -import io.reactivex.Flowable; -import io.realm.RealmResults; - -public class ChallengeListFragment extends BaseMainFragment implements SwipeRefreshLayout.OnRefreshListener { - - @Inject - ChallengeRepository challengeRepository; - @Inject - @Named(AppModule.NAMED_USER_ID) - String userId; - - @BindView(R.id.refreshLayout) - SwipeRefreshLayout swipeRefreshLayout; - @BindView(R.id.recyclerView) - RecyclerViewEmptySupport recyclerView; - @BindView(R.id.emptyView) - public View emptyView; - - private ChallengesListViewAdapter challengeAdapter; - private boolean viewUserChallengesOnly; - - public void setViewUserChallengesOnly(boolean only) { - this.viewUserChallengesOnly = only; - } - - - private RealmResults challenges; - - private ChallengeFilterOptions filterOptions; - - @Override - public void onDestroy() { - challengeRepository.close(); - super.onDestroy(); - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - super.onCreateView(inflater, container, savedInstanceState); - View v = inflater.inflate(R.layout.fragment_challengeslist, container, false); - setUnbinder(ButterKnife.bind(this, v)); - - challengeAdapter = new ChallengesListViewAdapter(null, true, viewUserChallengesOnly, userId); - - swipeRefreshLayout.setOnRefreshListener(this); - - recyclerView.setLayoutManager(new LinearLayoutManager(this.activity)); - recyclerView.setAdapter(challengeAdapter); - if (!viewUserChallengesOnly) { - this.recyclerView.setBackgroundResource(R.color.white); - } - - recyclerView.setEmptyView(emptyView); - recyclerView.setItemAnimator(new SafeDefaultItemAnimator()); - - loadLocalChallenges(); - return v; - } - - @Override - public void injectFragment(@NonNull AppComponent component) { - component.inject(this); - } - - @Override - public void onRefresh() { - fetchOnlineChallenges(); - } - - private void setRefreshing(boolean state) { - if (swipeRefreshLayout != null && swipeRefreshLayout.getVisibility() == View.VISIBLE) { - swipeRefreshLayout.setRefreshing(state); - } - } - - private void loadLocalChallenges() { - Flowable> observable; - - if (viewUserChallengesOnly && user != null) { - observable = challengeRepository.getUserChallenges(user.getId()); - } else { - observable = challengeRepository.getChallenges(); - } - - observable.firstElement().subscribe(challenges -> { - if (challenges.size() == 0) { - fetchOnlineChallenges(); - } - this.challenges = challenges; - challengeAdapter.updateUnfilteredData(challenges); - }, RxErrorHandler.handleEmptyError()); - } - - private void fetchOnlineChallenges() { - setRefreshing(true); - challengeRepository.retrieveChallenges(user).subscribe(challenges -> {}, RxErrorHandler.handleEmptyError(), () -> setRefreshing(false)); - } - - @Override - public String customTitle() { - if (!isAdded()) { - return ""; - } - return getString(R.string.sidebar_challenges); - } - - @Override - public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { - inflater.inflate(R.menu.menu_list_challenges, menu); - - - RelativeLayout badgeLayout = (RelativeLayout) MenuItemCompat.getActionView(menu.findItem(R.id.action_search)); - if (badgeLayout != null) { - TextView filterCountTextView = badgeLayout.findViewById(R.id.badge_textview); - filterCountTextView.setText(null); - filterCountTextView.setVisibility(View.GONE); - badgeLayout.setOnClickListener(view -> showFilterDialog()); - } - } - - private void showFilterDialog() { - ChallengeFilterDialogHolder.showDialog(getActivity(), - challenges, - filterOptions, this::changeFilter); - } - - private void changeFilter(ChallengeFilterOptions challengeFilterOptions) { - filterOptions = challengeFilterOptions; - if (challengeAdapter != null) { - challengeAdapter.filter(filterOptions); - } - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - // Handle action bar item clicks here. The action bar will - // automatically handle clicks on the Home/Up button, so long - // as you specify a parent activity in AndroidManifest.xml. - int id = item.getItemId(); - - switch (id) { - case R.id.action_create_challenge: - Intent intent = new Intent(getActivity(), CreateChallengeActivity.class); - startActivity(intent); - return true; - case R.id.action_reload: - fetchOnlineChallenges(); - return true; - case R.id.action_search: - showFilterDialog(); - return true; - } - - return super.onOptionsItemSelected(item); - } -} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/challenges/ChallengeListFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/challenges/ChallengeListFragment.kt new file mode 100644 index 000000000..96bae48e4 --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/challenges/ChallengeListFragment.kt @@ -0,0 +1,183 @@ +package com.habitrpg.android.habitica.ui.fragments.social.challenges + +import android.content.Intent +import android.os.Bundle +import android.support.v4.view.MenuItemCompat +import android.support.v4.widget.SwipeRefreshLayout +import android.support.v7.widget.LinearLayoutManager +import android.view.* +import android.widget.RelativeLayout +import android.widget.TextView +import butterknife.ButterKnife +import com.habitrpg.android.habitica.R +import com.habitrpg.android.habitica.components.AppComponent +import com.habitrpg.android.habitica.data.ChallengeRepository +import com.habitrpg.android.habitica.extensions.inflate +import com.habitrpg.android.habitica.helpers.RxErrorHandler +import com.habitrpg.android.habitica.models.social.Challenge +import com.habitrpg.android.habitica.modules.AppModule +import com.habitrpg.android.habitica.ui.activities.CreateChallengeActivity +import com.habitrpg.android.habitica.ui.adapter.social.ChallengesListViewAdapter +import com.habitrpg.android.habitica.ui.fragments.BaseMainFragment +import com.habitrpg.android.habitica.ui.helpers.RecyclerViewEmptySupport +import com.habitrpg.android.habitica.ui.helpers.SafeDefaultItemAnimator +import com.habitrpg.android.habitica.ui.helpers.bindView +import com.habitrpg.android.habitica.ui.helpers.resetViews +import com.habitrpg.android.habitica.utils.Action1 +import io.reactivex.Flowable +import io.reactivex.functions.Consumer +import io.realm.RealmResults +import javax.inject.Inject +import javax.inject.Named + +class ChallengeListFragment : BaseMainFragment(), SwipeRefreshLayout.OnRefreshListener { + + @Inject + lateinit var challengeRepository: ChallengeRepository + @field:[Inject Named(AppModule.NAMED_USER_ID)] + lateinit var userId: String + + private val swipeRefreshLayout: SwipeRefreshLayout? by bindView(R.id.refreshLayout) + private val recyclerView: RecyclerViewEmptySupport? by bindView(R.id.recyclerView) + private val emptyView: View? by bindView(R.id.emptyView) + + private var challengeAdapter: ChallengesListViewAdapter? = null + private var viewUserChallengesOnly: Boolean = false + + + private var challenges: RealmResults? = null + + private var filterOptions: ChallengeFilterOptions? = null + + fun setViewUserChallengesOnly(only: Boolean) { + this.viewUserChallengesOnly = only + } + + override fun onDestroy() { + challengeRepository.close() + super.onDestroy() + } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle?): View? { + super.onCreateView(inflater, container, savedInstanceState) + return container?.inflate(R.layout.fragment_challengeslist) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + resetViews() + + challengeAdapter = ChallengesListViewAdapter(null, true, viewUserChallengesOnly, userId) + + swipeRefreshLayout?.setOnRefreshListener(this) + + recyclerView?.layoutManager = LinearLayoutManager(this.activity) + recyclerView?.adapter = challengeAdapter + if (!viewUserChallengesOnly) { + this.recyclerView?.setBackgroundResource(R.color.white) + } + + recyclerView?.setEmptyView(emptyView) + recyclerView?.itemAnimator = SafeDefaultItemAnimator() + + loadLocalChallenges() + } + + override fun injectFragment(component: AppComponent) { + component.inject(this) + } + + override fun onRefresh() { + fetchOnlineChallenges() + } + + private fun setRefreshing(state: Boolean) { + if (swipeRefreshLayout != null && swipeRefreshLayout!!.visibility == View.VISIBLE) { + swipeRefreshLayout!!.isRefreshing = state + } + } + + private fun loadLocalChallenges() { + val observable: Flowable> = if (viewUserChallengesOnly && user != null) { + challengeRepository.getUserChallenges(user?.id) + } else { + challengeRepository.challenges + } + + observable.firstElement().subscribe(Consumer { challenges -> + if (challenges.size == 0) { + fetchOnlineChallenges() + } + this.challenges = challenges + challengeAdapter!!.updateUnfilteredData(challenges) + }, RxErrorHandler.handleEmptyError()) + } + + private fun fetchOnlineChallenges() { + setRefreshing(true) + challengeRepository.retrieveChallenges(user).doOnComplete { + setRefreshing(false) + } .subscribe(Consumer { }, RxErrorHandler.handleEmptyError()) + } + + override fun customTitle(): String { + return if (!isAdded) { + "" + } else getString(R.string.sidebar_challenges) + } + + override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) { + inflater?.inflate(R.menu.menu_list_challenges, menu) + + + val badgeLayout = MenuItemCompat.getActionView(menu!!.findItem(R.id.action_search)) as RelativeLayout? + if (badgeLayout != null) { + val filterCountTextView = badgeLayout.findViewById(R.id.badge_textview) + filterCountTextView.text = null + filterCountTextView.visibility = View.GONE + badgeLayout.setOnClickListener { showFilterDialog() } + } + } + + private fun showFilterDialog() { + ChallengeFilterDialogHolder.showDialog(getActivity()!!, + challenges ?: emptyList(), + filterOptions, object : Action1 { + override fun call(t: ChallengeFilterOptions) { + changeFilter(t) + } + }) + } + + private fun changeFilter(challengeFilterOptions: ChallengeFilterOptions) { + filterOptions = challengeFilterOptions + challengeAdapter?.filter(filterOptions) + } + + override fun onOptionsItemSelected(item: MenuItem?): Boolean { + // Handle action bar item clicks here. The action bar will + // automatically handle clicks on the Home/Up button, so long + // as you specify a parent activity in AndroidManifest.xml. + val id = item!!.itemId + + when (id) { + R.id.action_create_challenge -> { + val intent = Intent(getActivity(), CreateChallengeActivity::class.java) + startActivity(intent) + return true + } + R.id.action_reload -> { + fetchOnlineChallenges() + return true + } + R.id.action_search -> { + showFilterDialog() + return true + } + } + + return super.onOptionsItemSelected(item) + } +} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/challenges/ChallengesOverviewFragment.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/challenges/ChallengesOverviewFragment.java index 54abf0720..29cb1b759 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/challenges/ChallengesOverviewFragment.java +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/challenges/ChallengesOverviewFragment.java @@ -108,7 +108,7 @@ public class ChallengesOverviewFragment extends BaseMainFragment { @Subscribe public void onEvent(ShowChallengeDetailDialogCommand cmd) { - challengeRepository.getChallenge(cmd.challengeId).firstElement().subscribe(challenge -> ChallengeDetailDialogHolder.showDialog(getActivity(), challengeRepository, challenge, + challengeRepository.getChallenge(cmd.challengeId).firstElement().subscribe(challenge -> ChallengeDetailDialogHolder.Companion.showDialog(getActivity(), challengeRepository, challenge, challenge1 -> { // challenge left }), RxErrorHandler.handleEmptyError()); diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/party/PartyDetailFragment.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/party/PartyDetailFragment.java index 8b7b3b586..769a898a9 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/party/PartyDetailFragment.java +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/party/PartyDetailFragment.java @@ -144,7 +144,8 @@ public class PartyDetailFragment extends BaseFragment { return; } titleView.setText(party.getName()); - descriptionView.setText(MarkdownParser.parseMarkdown(party.getDescription())); + //TODO: FIX + //descriptionView.setText(MarkdownParser.parseMarkdown(party.getDescription())); if (quest != null && !quest.getKey().isEmpty()) { newQuestButton.setVisibility(View.GONE); @@ -216,8 +217,8 @@ public class PartyDetailFragment extends BaseFragment { @OnClick(R.id.new_quest_button) public void inviteNewQuest() { ItemRecyclerFragment fragment = new ItemRecyclerFragment(); - fragment.itemType = "quests"; - fragment.itemTypeText = getString(R.string.quest); + fragment.setItemType("quests"); + fragment.setItemTypeText(getString(R.string.quest)); fragment.show(getFragmentManager(), "questDialog"); } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/party/PartyInviteFragment.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/party/PartyInviteFragment.java deleted file mode 100644 index 17c74ab00..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/party/PartyInviteFragment.java +++ /dev/null @@ -1,87 +0,0 @@ -package com.habitrpg.android.habitica.ui.fragments.social.party; - -import android.os.Bundle; -import android.support.annotation.Nullable; -import android.text.InputType; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.EditText; -import android.widget.LinearLayout; -import android.widget.TextView; - -import com.habitrpg.android.habitica.R; -import com.habitrpg.android.habitica.components.AppComponent; -import com.habitrpg.android.habitica.prefs.scanner.IntentIntegrator; -import com.habitrpg.android.habitica.ui.fragments.BaseFragment; - -import java.util.ArrayList; -import java.util.List; - -import butterknife.BindView; -import butterknife.ButterKnife; -import butterknife.OnClick; - -public class PartyInviteFragment extends BaseFragment { - - public boolean isEmailInvite; - - @BindView(R.id.inviteDescription) - TextView inviteDescription; - - @BindView(R.id.invitationWrapper) - LinearLayout invitationWrapper; - - @Nullable - @Override - public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - super.onCreateView(inflater, container, savedInstanceState); - View v = inflater.inflate(R.layout.fragment_party_invite, container, false); - setUnbinder(ButterKnife.bind(this, v)); - - if (isEmailInvite) { - inviteDescription.setText(getString(R.string.invite_email_description)); - } else { - inviteDescription.setText(getString(R.string.invite_id_description)); - } - - addInviteField(); - - return v; - } - - @Override - public void injectFragment(AppComponent component) { - component.inject(this); - } - - @OnClick(R.id.addInviteButton) - public void addInviteField() { - EditText editText = new EditText(getContext()); - - if (isEmailInvite) { - editText.setHint(R.string.email); - editText.setInputType(InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS); - } else { - editText.setHint(R.string.user_id); - } - invitationWrapper.addView(editText); - } - - @OnClick(R.id.InviteByQR) - public void startQRInvite() { - IntentIntegrator scanIntegrator = new IntentIntegrator(getActivity()); - scanIntegrator.initiateScan(); - } - - public String[] getValues() { - List values = new ArrayList<>(); - for (int i = 0; i < invitationWrapper.getChildCount(); i++) { - EditText valueEditText = (EditText) invitationWrapper.getChildAt(i); - if (valueEditText.getText().toString().length() > 0) { - values.add(valueEditText.getText().toString()); - } - } - return values.toArray(new String[values.size()]); - } -} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/party/PartyInviteFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/party/PartyInviteFragment.kt new file mode 100644 index 000000000..57997bba6 --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/party/PartyInviteFragment.kt @@ -0,0 +1,83 @@ +package com.habitrpg.android.habitica.ui.fragments.social.party + +import android.os.Bundle +import android.text.InputType +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.Button +import android.widget.EditText +import android.widget.LinearLayout +import android.widget.TextView +import com.habitrpg.android.habitica.R +import com.habitrpg.android.habitica.components.AppComponent +import com.habitrpg.android.habitica.prefs.scanner.IntentIntegrator +import com.habitrpg.android.habitica.ui.fragments.BaseFragment +import com.habitrpg.android.habitica.ui.helpers.bindView +import com.habitrpg.android.habitica.ui.helpers.resetViews +import java.util.* + +class PartyInviteFragment : BaseFragment() { + + var isEmailInvite: Boolean = false + + private val inviteDescription: TextView? by bindView(R.id.inviteDescription) + private val invitationWrapper: LinearLayout? by bindView(R.id.invitationWrapper) + private val addInviteButton: Button? by bindView(R.id.addInviteButton) + private val inviteQRButton: Button? by bindView(R.id.InviteByQR) + + val values: Array + get() { + val values = ArrayList() + for (i in 0 until (invitationWrapper?.childCount ?: 0)) { + val valueEditText = invitationWrapper?.getChildAt(i) as EditText + if (valueEditText.text.toString().isNotEmpty()) { + values.add(valueEditText.text.toString()) + } + } + return values.toTypedArray() + } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + super.onCreateView(inflater, container, savedInstanceState) + return inflater.inflate(R.layout.fragment_party_invite, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + resetViews() + + if (isEmailInvite) { + inviteDescription?.text = getString(R.string.invite_email_description) + } else { + inviteDescription?.text = getString(R.string.invite_id_description) + } + + addInviteField() + + addInviteButton?.setOnClickListener { addInviteField() } + inviteQRButton?.setOnClickListener { startQRInvite() } + } + + override fun injectFragment(component: AppComponent) { + component.inject(this) + } + + fun addInviteField() { + val editText = EditText(context) + + if (isEmailInvite) { + editText.setHint(R.string.email) + editText.inputType = InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS + } else { + editText.setHint(R.string.user_id) + } + invitationWrapper?.addView(editText) + } + + fun startQRInvite() { + val scanIntegrator = IntentIntegrator(activity) + scanIntegrator.initiateScan() + } +} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/tasks/TasksFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/tasks/TasksFragment.kt index 4647a2e32..751afd62f 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/tasks/TasksFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/tasks/TasksFragment.kt @@ -15,6 +15,7 @@ import com.habitrpg.android.habitica.components.AppComponent import com.habitrpg.android.habitica.data.TagRepository import com.habitrpg.android.habitica.events.TaskTappedEvent import com.habitrpg.android.habitica.events.commands.AddNewTaskCommand +import com.habitrpg.android.habitica.extensions.notNull import com.habitrpg.android.habitica.helpers.RxErrorHandler import com.habitrpg.android.habitica.helpers.TaskFilterHelper import com.habitrpg.android.habitica.models.tasks.Task @@ -133,33 +134,37 @@ class TasksFragment : BaseMainFragment() { } private fun showFilterDialog() { - val dialog = TaskFilterDialog(context, HabiticaBaseApplication.getComponent()) - if (user != null) { - dialog.setTags(user?.tags?.createSnapshot()) - } - dialog.setActiveTags(taskFilterHelper.tags) - if (activeFragment != null) { - val taskType = activeFragment?.classType - if (taskType != null) { - dialog.setTaskType(taskType, taskFilterHelper.getActiveFilter(taskType)) + context.notNull { + val dialog = TaskFilterDialog(it, HabiticaBaseApplication.getComponent()) + if (user != null) { + dialog.setTags(user?.tags?.createSnapshot() ?: emptyList()) } - } - dialog.setListener { activeTaskFilter, activeTags -> - if (viewFragmentsDictionary == null) { - return@setListener + dialog.setActiveTags(taskFilterHelper.tags) + if (activeFragment != null) { + val taskType = activeFragment?.classType + if (taskType != null) { + dialog.setTaskType(taskType, taskFilterHelper.getActiveFilter(taskType)) + } } - val activePos = viewPager?.currentItem ?: 0 - viewFragmentsDictionary?.get(activePos - 1)?.recyclerAdapter?.filter() - viewFragmentsDictionary?.get(activePos + 1)?.recyclerAdapter?.filter() - taskFilterHelper.tags = activeTags - if (activeTaskFilter != null) { - activeFragment?.setActiveFilter(activeTaskFilter) - } - viewFragmentsDictionary?.values?.forEach { it.recyclerAdapter?.filter() } - updateFilterIcon() + dialog.setListener(object : TaskFilterDialog.OnFilterCompletedListener { + override fun onFilterCompleted(activeTaskFilter: String?, activeTags: List?) { + if (viewFragmentsDictionary == null) { + return + } + val activePos = viewPager?.currentItem ?: 0 + viewFragmentsDictionary?.get(activePos - 1)?.recyclerAdapter?.filter() + viewFragmentsDictionary?.get(activePos + 1)?.recyclerAdapter?.filter() + taskFilterHelper.tags = activeTags + if (activeTaskFilter != null) { + activeFragment?.setActiveFilter(activeTaskFilter) + } + viewFragmentsDictionary?.values?.forEach { it.recyclerAdapter?.filter() } + updateFilterIcon() + } + }) + dialog.show() } - dialog.show() } private fun refresh() { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/helpers/Kotterknife.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/helpers/Kotterknife.kt new file mode 100644 index 000000000..5103cbba5 --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/helpers/Kotterknife.kt @@ -0,0 +1,133 @@ +package com.habitrpg.android.habitica.ui.helpers + +import android.app.Activity +import android.app.Dialog +import android.content.Context +import android.support.annotation.ColorRes +import android.support.annotation.IdRes +import android.support.v4.app.Fragment +import android.support.v4.content.ContextCompat +import android.support.v7.widget.RecyclerView.ViewHolder +import android.view.View +import java.util.* +import kotlin.properties.ReadOnlyProperty +import kotlin.reflect.KProperty + +object ButterKnife { + fun reset(target: Any) { + LazyRegistry.reset(target) + } +} + +fun View.bindView(@IdRes id: Int) + : ReadOnlyProperty = required(id, viewFinder) + +fun Activity.bindView(@IdRes id: Int) + : ReadOnlyProperty = required(id, viewFinder) + +fun Dialog.bindView(@IdRes id: Int) + : ReadOnlyProperty = required(id, viewFinder) + +fun Fragment.bindView(@IdRes id: Int) + : ReadOnlyProperty = required(id, viewFinder) + +fun ViewHolder.bindView(@IdRes id: Int) + : ReadOnlyProperty = required(id, viewFinder) + +fun View.bindOptionalView(@IdRes id: Int) + : ReadOnlyProperty = optional(id, viewFinder) + +fun Activity.bindOptionalView(@IdRes id: Int) + : ReadOnlyProperty = optional(id, viewFinder) + +fun Dialog.bindOptionalView(@IdRes id: Int) + : ReadOnlyProperty = optional(id, viewFinder) + +fun Fragment.bindOptionalView(@IdRes id: Int) + : ReadOnlyProperty = optional(id, viewFinder) + +fun ViewHolder.bindOptionalView(@IdRes id: Int) + : ReadOnlyProperty = optional(id, viewFinder) + + +fun bindView(container: View, @IdRes res: Int) : Lazy { + @Suppress("UNCHECKED_CAST") + return lazy(LazyThreadSafetyMode.NONE) { container.findViewById(res) } +} + +fun bindOptionalView(container: View?, @IdRes res: Int) : Lazy { + @Suppress("UNCHECKED_CAST") + return lazy(LazyThreadSafetyMode.NONE) { container?.findViewById(res) } +} + +fun bindColor(context: Context, @ColorRes res: Int) : Lazy { + @Suppress("UNCHECKED_CAST") + return lazy(LazyThreadSafetyMode.NONE) { ContextCompat.getColor(context, res) } +} + +fun Fragment.resetViews() { + LazyRegistry.reset(this) +} + + +private val View.viewFinder: View.(Int) -> View? + get() = { findViewById(it) } +private val Activity.viewFinder: Activity.(Int) -> View? + get() = { findViewById(it) } +private val Dialog.viewFinder: Dialog.(Int) -> View? + get() = { findViewById(it) } +private val Fragment.viewFinder: Fragment.(Int) -> View? + get() = { view?.findViewById(it) } +private val ViewHolder.viewFinder: ViewHolder.(Int) -> View? + get() = { itemView.findViewById(it) } + +private fun viewNotFound(id: Int, desc: KProperty<*>): Nothing = + throw IllegalStateException("View ID $id for '${desc.name}' not found.") + +@Suppress("UNCHECKED_CAST") +private fun required(id: Int, finder: T.(Int) -> View?) + = TargetedLazy { t: T, desc -> t.finder(id) as V? ?: viewNotFound(id, desc) } + +@Suppress("UNCHECKED_CAST") +private fun optional(id: Int, finder: T.(Int) -> View?) + = TargetedLazy { t: T, desc -> t.finder(id) as V? } + +@Suppress("UNCHECKED_CAST") +private fun required(ids: IntArray, finder: T.(Int) -> View?) + = TargetedLazy { t: T, desc -> ids.map { t.finder(it) as V? ?: viewNotFound(it, desc) } } + +@Suppress("UNCHECKED_CAST") +private fun optional(ids: IntArray, finder: T.(Int) -> View?) + = TargetedLazy { t: T, desc -> ids.map { t.finder(it) as V? }.filterNotNull() } + +// Like Kotlin's lazy delegate but the initializer gets the target and metadata passed to it +private class TargetedLazy(private val initializer: (T, KProperty<*>) -> V) : ReadOnlyProperty { + private object EMPTY + + private var value: Any? = EMPTY + + override fun getValue(thisRef: T, property: KProperty<*>): V { + LazyRegistry.register(thisRef!!, this) + if (value == EMPTY) { + value = initializer(thisRef, property) + } + @Suppress("UNCHECKED_CAST") + return value as V + } + + fun reset() { + value = EMPTY + } +} + +private object LazyRegistry { + private val lazyMap = WeakHashMap>>() + + fun register(target: Any, lazy: TargetedLazy<*, *>) { + lazyMap.getOrPut(target) { Collections.newSetFromMap(WeakHashMap()) }.add(lazy) + } + + fun reset(target: Any) { + lazyMap[target]?.forEach { it.reset() } + } +} \ No newline at end of file diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/helpers/MarkdownParser.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/helpers/MarkdownParser.java deleted file mode 100644 index 4c18d6455..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/helpers/MarkdownParser.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.habitrpg.android.habitica.ui.helpers; - -import android.support.annotation.Nullable; -import android.text.Html; - -import com.commonsware.cwac.anddown.AndDown; - -import net.pherth.android.emoji_library.EmojiParser; - -import static android.text.Html.FROM_HTML_MODE_LEGACY; - -/** - * @author data5tream - */ -public class MarkdownParser { - - private static AndDown processor = new AndDown(); - - /** - * Parses formatted markdown and returns it as styled CharSequence - * - * @param input Markdown formatted String - * @return Stylized CharSequence - */ - public static CharSequence parseMarkdown(String input) { - if (input == null) { - return ""; - } - CharSequence output; - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) { - output = Html.fromHtml(processor.markdownToHtml(EmojiParser.parseEmojis(input.trim())), FROM_HTML_MODE_LEGACY); - } else { - output = Html.fromHtml(processor.markdownToHtml(EmojiParser.parseEmojis(input.trim()))); - } - if (output.length() >= 2) output = output.subSequence(0, output.length() - 2); - return output; - } - - /** - * Converts stylized CharSequence into markdown - * - * @param input Stylized CharSequence - * @return Markdown formatted String - */ - @Nullable - public static String parseCompiled(CharSequence input) { - return EmojiParser.convertToCheatCode(input.toString()); - } - -} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/helpers/MarkdownParser.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/helpers/MarkdownParser.kt new file mode 100644 index 000000000..f92221c42 --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/helpers/MarkdownParser.kt @@ -0,0 +1,47 @@ +package com.habitrpg.android.habitica.ui.helpers + +import android.text.Html + +import com.commonsware.cwac.anddown.AndDown + +import net.pherth.android.emoji_library.EmojiParser + +import android.text.Html.FROM_HTML_MODE_LEGACY + +/** + * @author data5tream + */ +object MarkdownParser { + + private val processor = AndDown() + + /** + * Parses formatted markdown and returns it as styled CharSequence + * + * @param input Markdown formatted String + * @return Stylized CharSequence + */ + fun parseMarkdown(input: String?): CharSequence { + if (input == null) { + return "" + } + var output: CharSequence = if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) { + Html.fromHtml(processor.markdownToHtml(EmojiParser.parseEmojis(input.trim { it <= ' ' })), FROM_HTML_MODE_LEGACY) + } else { + Html.fromHtml(processor.markdownToHtml(EmojiParser.parseEmojis(input.trim { it <= ' ' }))) + } + if (output.length >= 2) output = output.subSequence(0, output.length - 2) + return output + } + + /** + * Converts stylized CharSequence into markdown + * + * @param input Stylized CharSequence + * @return Markdown formatted String + */ + fun parseCompiled(input: CharSequence): String? { + return EmojiParser.convertToCheatCode(input.toString()) + } + +} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/SectionViewHolder.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/SectionViewHolder.kt index 3a42813f6..c27b2a87e 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/SectionViewHolder.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/SectionViewHolder.kt @@ -9,7 +9,7 @@ import android.widget.Button import android.widget.Spinner import android.widget.TextView import com.habitrpg.android.habitica.R -import com.habitrpg.android.habitica.extensions.bindView +import com.habitrpg.android.habitica.ui.helpers.bindView class SectionViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/ShopItemViewHolder.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/ShopItemViewHolder.kt index 9ecb1e562..41e12623a 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/ShopItemViewHolder.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/ShopItemViewHolder.kt @@ -9,7 +9,7 @@ import android.widget.TextView import com.facebook.drawee.view.SimpleDraweeView import com.habitrpg.android.habitica.HabiticaBaseApplication import com.habitrpg.android.habitica.R -import com.habitrpg.android.habitica.extensions.bindView +import com.habitrpg.android.habitica.ui.helpers.bindView import com.habitrpg.android.habitica.models.shops.ShopItem import com.habitrpg.android.habitica.ui.helpers.DataBindingUtils import com.habitrpg.android.habitica.ui.views.CurrencyView diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/BaseTaskViewHolder.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/BaseTaskViewHolder.kt index a58637124..eb1fa8930 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/BaseTaskViewHolder.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/BaseTaskViewHolder.kt @@ -8,13 +8,13 @@ import android.widget.LinearLayout import android.widget.TextView import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.events.TaskTappedEvent -import com.habitrpg.android.habitica.extensions.bindColor -import com.habitrpg.android.habitica.extensions.bindOptionalView -import com.habitrpg.android.habitica.extensions.bindView +import com.habitrpg.android.habitica.ui.helpers.bindView import com.habitrpg.android.habitica.extensions.notNull import com.habitrpg.android.habitica.helpers.RxErrorHandler import com.habitrpg.android.habitica.models.tasks.Task import com.habitrpg.android.habitica.ui.helpers.MarkdownParser +import com.habitrpg.android.habitica.ui.helpers.bindColor +import com.habitrpg.android.habitica.ui.helpers.bindOptionalView import io.reactivex.Single import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.functions.Consumer diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/ChecklistedViewHolder.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/ChecklistedViewHolder.kt index 06c77853c..fa381fc87 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/ChecklistedViewHolder.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/ChecklistedViewHolder.kt @@ -27,7 +27,7 @@ import org.greenrobot.eventbus.EventBus import butterknife.BindView import butterknife.OnClick -import com.habitrpg.android.habitica.extensions.bindView +import com.habitrpg.android.habitica.ui.helpers.bindView import io.reactivex.Observable import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.functions.Consumer diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/DailyViewHolder.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/DailyViewHolder.kt index 1fd4ed8f6..578e4ed0a 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/DailyViewHolder.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/DailyViewHolder.kt @@ -3,7 +3,7 @@ package com.habitrpg.android.habitica.ui.viewHolders.tasks import android.view.View import android.widget.TextView import com.habitrpg.android.habitica.R -import com.habitrpg.android.habitica.extensions.bindView +import com.habitrpg.android.habitica.ui.helpers.bindView import com.habitrpg.android.habitica.models.tasks.Task class DailyViewHolder(itemView: View) : ChecklistedViewHolder(itemView) { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/HabitViewHolder.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/HabitViewHolder.kt index d5b5d7668..12ec04be4 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/HabitViewHolder.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/HabitViewHolder.kt @@ -8,7 +8,7 @@ import android.widget.TextView import butterknife.OnClick import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.events.HabitScoreEvent -import com.habitrpg.android.habitica.extensions.bindView +import com.habitrpg.android.habitica.ui.helpers.bindView import com.habitrpg.android.habitica.models.tasks.Task import org.greenrobot.eventbus.EventBus diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/RewardViewHolder.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/RewardViewHolder.kt index 57bb04eeb..7a98159df 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/RewardViewHolder.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/RewardViewHolder.kt @@ -8,7 +8,7 @@ import butterknife.OnClick import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.events.TaskTappedEvent import com.habitrpg.android.habitica.events.commands.BuyRewardCommand -import com.habitrpg.android.habitica.extensions.bindView +import com.habitrpg.android.habitica.ui.helpers.bindView import com.habitrpg.android.habitica.helpers.NumberAbbreviator import com.habitrpg.android.habitica.models.tasks.Task import com.habitrpg.android.habitica.ui.ItemDetailDialog diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/CollapsibleSectionView.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/CollapsibleSectionView.kt index 1a7817dd5..7535fe024 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/CollapsibleSectionView.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/CollapsibleSectionView.kt @@ -10,8 +10,8 @@ import android.widget.ImageView import android.widget.LinearLayout import android.widget.TextView import com.habitrpg.android.habitica.R -import com.habitrpg.android.habitica.extensions.bindView import com.habitrpg.android.habitica.extensions.notNull +import com.habitrpg.android.habitica.ui.helpers.bindView class CollapsibleSectionView(context: Context?, attrs: AttributeSet?) : LinearLayout(context, attrs) { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/HabiticaAlertDialog.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/HabiticaAlertDialog.kt index 04ea7e33d..250221086 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/HabiticaAlertDialog.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/HabiticaAlertDialog.kt @@ -8,15 +8,15 @@ import android.view.View import android.widget.LinearLayout import android.widget.TextView import com.habitrpg.android.habitica.R -import com.habitrpg.android.habitica.extensions.bindView +import com.habitrpg.android.habitica.ui.helpers.bindView import com.habitrpg.android.habitica.extensions.layoutInflater open class HabiticaAlertDialog(context: Context) : AlertDialog(context) { private val view: LinearLayout = LayoutInflater.from(context).inflate(R.layout.dialog_habitica_base, null) as LinearLayout - private val titleTextView: TextView by bindView(view, R.id.titleTextView) - private val subtitleTextView: TextView by bindView(view, R.id.subtitleTextView) - private val messageTextView: TextView by bindView(view, R.id.messageTextView) + private val titleTextView: TextView by bindView(R.id.titleTextView) + private val subtitleTextView: TextView by bindView(R.id.subtitleTextView) + private val messageTextView: TextView by bindView(R.id.messageTextView) private var additionalContentView: View? = null diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/HabiticaProgressBar.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/HabiticaProgressBar.kt index 453ebd063..e3ae19851 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/HabiticaProgressBar.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/HabiticaProgressBar.kt @@ -6,7 +6,7 @@ import android.view.View import android.widget.FrameLayout import android.widget.LinearLayout import com.habitrpg.android.habitica.R -import com.habitrpg.android.habitica.extensions.bindView +import com.habitrpg.android.habitica.ui.helpers.bindView import com.habitrpg.android.habitica.ui.helpers.DataBindingUtils diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/NPCBannerView.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/NPCBannerView.kt index 5f64fd2c9..805cd6d01 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/NPCBannerView.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/NPCBannerView.kt @@ -10,7 +10,7 @@ import android.widget.ImageView import com.facebook.drawee.view.SimpleDraweeView import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.extensions.backgroundCompat -import com.habitrpg.android.habitica.extensions.bindView +import com.habitrpg.android.habitica.ui.helpers.bindView import com.habitrpg.android.habitica.extensions.layoutInflater import com.habitrpg.android.habitica.helpers.RxErrorHandler import com.habitrpg.android.habitica.ui.helpers.DataBindingUtils diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/ValueBar.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/ValueBar.kt index 15c34e4da..ae619741b 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/ValueBar.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/ValueBar.kt @@ -11,7 +11,7 @@ import android.widget.FrameLayout import android.widget.ImageView import android.widget.TextView import com.habitrpg.android.habitica.R -import com.habitrpg.android.habitica.extensions.bindView +import com.habitrpg.android.habitica.ui.helpers.bindView import java.text.NumberFormat class ValueBar(context: Context?, attrs: AttributeSet?) : FrameLayout(context, attrs) { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/insufficientCurrency/InsufficientCurrencyDialog.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/insufficientCurrency/InsufficientCurrencyDialog.java deleted file mode 100644 index 3fea404be..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/insufficientCurrency/InsufficientCurrencyDialog.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.habitrpg.android.habitica.ui.views.insufficientCurrency; - -import android.content.Context; -import android.support.v7.app.AlertDialog; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.ImageView; -import android.widget.TextView; - -import com.habitrpg.android.habitica.R; - -import butterknife.BindView; -import butterknife.ButterKnife; - -/** - * Created by phillip on 27.09.17. - */ - -abstract public class InsufficientCurrencyDialog extends AlertDialog { - - @BindView(R.id.imageView) - ImageView imageView; - @BindView(R.id.textView) - TextView textView; - - public InsufficientCurrencyDialog(Context context) { - super(context); - - LayoutInflater inflater = LayoutInflater.from(context); - View view = inflater.inflate(R.layout.dialog_insufficient_currency, null); - ButterKnife.bind(this, view); - setView(view); - - this.setButton(AlertDialog.BUTTON_NEUTRAL, context.getString(R.string.close), (dialogInterface, i) -> { - this.dismiss(); - }); - } - -} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/insufficientCurrency/InsufficientCurrencyDialog.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/insufficientCurrency/InsufficientCurrencyDialog.kt new file mode 100644 index 000000000..64c81f634 --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/insufficientCurrency/InsufficientCurrencyDialog.kt @@ -0,0 +1,29 @@ +package com.habitrpg.android.habitica.ui.views.insufficientCurrency + +import android.content.Context +import android.support.v7.app.AlertDialog +import android.view.LayoutInflater +import android.widget.ImageView +import android.widget.TextView +import com.habitrpg.android.habitica.R +import com.habitrpg.android.habitica.ui.helpers.bindView + +/** + * Created by phillip on 27.09.17. + */ + +abstract class InsufficientCurrencyDialog(context: Context) : AlertDialog(context) { + + protected val imageView: ImageView by bindView(R.id.imageView) + protected val textView: TextView by bindView(R.id.textView) + + init { + + val inflater = LayoutInflater.from(context) + val view = inflater.inflate(R.layout.dialog_insufficient_currency, null) + setView(view) + + this.setButton(AlertDialog.BUTTON_NEUTRAL, context.getString(R.string.close)) { _, _ -> this.dismiss() } + } + +} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/insufficientCurrency/InsufficientGemsDialog.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/insufficientCurrency/InsufficientGemsDialog.java deleted file mode 100644 index cc114df14..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/insufficientCurrency/InsufficientGemsDialog.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.habitrpg.android.habitica.ui.views.insufficientCurrency; - -import android.app.AlertDialog; -import android.content.Context; - -import com.habitrpg.android.habitica.R; -import com.habitrpg.android.habitica.events.commands.OpenGemPurchaseFragmentCommand; - -import org.greenrobot.eventbus.EventBus; - -/** - * Created by phillip on 27.09.17. - */ - -public class InsufficientGemsDialog extends InsufficientCurrencyDialog { - - public InsufficientGemsDialog(Context context) { - super(context); - - imageView.setImageResource(R.drawable.gems_84); - textView.setText(R.string.insufficientGems); - - setButton(AlertDialog.BUTTON_POSITIVE, context.getString(R.string.purchase_gems), (dialogInterface, i) -> { - EventBus.getDefault().post(new OpenGemPurchaseFragmentCommand()); - }); - } -} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/insufficientCurrency/InsufficientGemsDialog.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/insufficientCurrency/InsufficientGemsDialog.kt new file mode 100644 index 000000000..b67554d02 --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/insufficientCurrency/InsufficientGemsDialog.kt @@ -0,0 +1,24 @@ +package com.habitrpg.android.habitica.ui.views.insufficientCurrency + +import android.app.AlertDialog +import android.content.Context + +import com.habitrpg.android.habitica.R +import com.habitrpg.android.habitica.events.commands.OpenGemPurchaseFragmentCommand + +import org.greenrobot.eventbus.EventBus + +/** + * Created by phillip on 27.09.17. + */ + +class InsufficientGemsDialog(context: Context) : InsufficientCurrencyDialog(context) { + + init { + + imageView.setImageResource(R.drawable.gems_84) + textView.setText(R.string.insufficientGems) + + setButton(AlertDialog.BUTTON_POSITIVE, context.getString(R.string.purchase_gems)) { _, _ -> EventBus.getDefault().post(OpenGemPurchaseFragmentCommand()) } + } +} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/insufficientCurrency/InsufficientGoldDialog.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/insufficientCurrency/InsufficientGoldDialog.java deleted file mode 100644 index 380d9f136..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/insufficientCurrency/InsufficientGoldDialog.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.habitrpg.android.habitica.ui.views.insufficientCurrency; - -import android.content.Context; - -import com.habitrpg.android.habitica.R; -import com.habitrpg.android.habitica.ui.views.HabiticaIconsHelper; - -public class InsufficientGoldDialog extends InsufficientCurrencyDialog { - public InsufficientGoldDialog(Context context) { - super(context); - - imageView.setImageBitmap(HabiticaIconsHelper.imageOfGoldReward()); - textView.setText(context.getString(R.string.insufficientGold)); - setTitle(R.string.insufficientSubscriberGemsTitle); - } -} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/insufficientCurrency/InsufficientGoldDialog.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/insufficientCurrency/InsufficientGoldDialog.kt new file mode 100644 index 000000000..7f833e781 --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/insufficientCurrency/InsufficientGoldDialog.kt @@ -0,0 +1,15 @@ +package com.habitrpg.android.habitica.ui.views.insufficientCurrency + +import android.content.Context + +import com.habitrpg.android.habitica.R +import com.habitrpg.android.habitica.ui.views.HabiticaIconsHelper + +class InsufficientGoldDialog(context: Context) : InsufficientCurrencyDialog(context) { + init { + + imageView.setImageBitmap(HabiticaIconsHelper.imageOfGoldReward()) + textView.text = context.getString(R.string.insufficientGold) + setTitle(R.string.insufficientSubscriberGemsTitle) + } +} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/insufficientCurrency/InsufficientHourglassesDialog.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/insufficientCurrency/InsufficientHourglassesDialog.java deleted file mode 100644 index 88fc07d07..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/insufficientCurrency/InsufficientHourglassesDialog.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.habitrpg.android.habitica.ui.views.insufficientCurrency; - -import android.content.Context; -import android.support.v7.app.AlertDialog; - -import com.habitrpg.android.habitica.R; -import com.habitrpg.android.habitica.events.commands.OpenGemPurchaseFragmentCommand; -import com.habitrpg.android.habitica.ui.views.HabiticaIconsHelper; - -import org.greenrobot.eventbus.EventBus; - -public class InsufficientHourglassesDialog extends InsufficientCurrencyDialog { - public InsufficientHourglassesDialog(Context context) { - super(context); - - imageView.setImageBitmap(HabiticaIconsHelper.imageOfHourglassShop()); - textView.setText(R.string.insufficientHourglasses); - - - setButton(AlertDialog.BUTTON_POSITIVE, context.getString(R.string.get_hourglasses), (dialogInterface, i) -> { - EventBus.getDefault().post(new OpenGemPurchaseFragmentCommand()); - }); - } -} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/insufficientCurrency/InsufficientHourglassesDialog.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/insufficientCurrency/InsufficientHourglassesDialog.kt new file mode 100644 index 000000000..6abcf2535 --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/insufficientCurrency/InsufficientHourglassesDialog.kt @@ -0,0 +1,20 @@ +package com.habitrpg.android.habitica.ui.views.insufficientCurrency + +import android.content.Context +import android.support.v7.app.AlertDialog + +import com.habitrpg.android.habitica.R +import com.habitrpg.android.habitica.events.commands.OpenGemPurchaseFragmentCommand +import com.habitrpg.android.habitica.ui.views.HabiticaIconsHelper + +import org.greenrobot.eventbus.EventBus + +class InsufficientHourglassesDialog(context: Context) : InsufficientCurrencyDialog(context) { + init { + + imageView.setImageBitmap(HabiticaIconsHelper.imageOfHourglassShop()) + textView.setText(R.string.insufficientHourglasses) + + setButton(AlertDialog.BUTTON_POSITIVE, context.getString(R.string.get_hourglasses)) { _, _ -> EventBus.getDefault().post(OpenGemPurchaseFragmentCommand()) } + } +} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/login/LoginBackgroundView.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/login/LoginBackgroundView.java deleted file mode 100644 index a3a4ff288..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/login/LoginBackgroundView.java +++ /dev/null @@ -1,151 +0,0 @@ -package com.habitrpg.android.habitica.ui.views.login; - - -import android.animation.ObjectAnimator; -import android.animation.ValueAnimator; -import android.content.Context; -import android.support.annotation.Nullable; -import android.util.AttributeSet; -import android.util.DisplayMetrics; -import android.view.View; -import android.view.WindowManager; -import android.widget.FrameLayout; -import android.widget.ImageView; -import android.widget.RelativeLayout; - -import com.habitrpg.android.habitica.R; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Random; - -import butterknife.BindView; -import butterknife.ButterKnife; - -public class LoginBackgroundView extends RelativeLayout { - - private static float SIZE_FACTOR = 1.5f; - private static int STAR_SIZE = 30; - private static int STAR_OFFSET = 18; - private final Random random; - - @BindView(R.id.left_cloud_view) - ImageView leftCloudView; - @BindView(R.id.right_cloud_view) - ImageView rightCloudView; - - private List starViews; - private int width; - private int height; - private boolean didLayoutStars = false; - private FrameLayout.LayoutParams params; - - public LoginBackgroundView(Context context, @Nullable AttributeSet attrs) { - super(context, attrs); - this.random = new Random(); - - DisplayMetrics metrics = new DisplayMetrics(); - WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); - windowManager.getDefaultDisplay().getMetrics(metrics); - height = (int) (metrics.heightPixels*SIZE_FACTOR); - } - - @Override - protected void onFinishInflate() { - super.onFinishInflate(); - ButterKnife.bind(this, this); - starViews = new ArrayList<>(); - params = new FrameLayout.LayoutParams(0, 0); - generateStars(); - animateClouds(); - } - - private void animateClouds() { - ValueAnimator leftAnimator = ObjectAnimator.ofFloat(leftCloudView, View.TRANSLATION_Y, 10.0f).setDuration(5000); - leftAnimator.setRepeatCount(ValueAnimator.INFINITE); - leftAnimator.setRepeatMode(ValueAnimator.REVERSE); - leftAnimator.start(); - ValueAnimator rightAnimator = ObjectAnimator.ofFloat(rightCloudView, View.TRANSLATION_Y, -10.0f).setDuration(8000); - rightAnimator.setRepeatCount(ValueAnimator.INFINITE); - rightAnimator.setRepeatMode(ValueAnimator.REVERSE); - rightAnimator.start(); - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){ - this.width = MeasureSpec.getSize(widthMeasureSpec); - this.setMeasuredDimension(width, height); - params.width = width; - params.height = height; - this.setLayoutParams(params); - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - } - - @Override - protected void onLayout(boolean changed, int l, int t, int r, int b) { - super.onLayout(changed, l, t, r, b); - updateStarLayoutParams(); - } - - public void generateStars() { - generateStars(1, 12, 25); - } - - private void generateStars(int largeCount, int mediumCount, int smallCount) { - removeStarViews(); - for (int x = 0; x < largeCount; x++) { - generateStar(2); - } - for (int x = 0; x < mediumCount; x++) { - generateStar(1); - } - for (int x = 0; x < smallCount; x++) { - generateStar(0); - } - requestLayout(); - } - - private void removeStarViews() { - if (starViews.size() > 0) { - starViews.forEach(this::removeView); - starViews.clear(); - } - } - - private void generateStar(int size) { - StarView starView = new StarView(getContext() - ); - starView.setStarSize(size); - if (random.nextInt(10) > 2) { - starView.setBlinkDurations(Arrays.asList(getBlinkDuration(), getBlinkDuration(), getBlinkDuration())); - } - starViews.add(starView); - if (width > 0 && height > 0) { - this.addView(starView, 0, getStarParams()); - } else { - this.addView(starView, 0); - } - } - - private int getBlinkDuration() { - return random.nextInt(30)*800+4; - } - - private void updateStarLayoutParams() { - if (width <= 0 || height <= 0 || didLayoutStars || starViews.size() == 0) { - return; - } - for (StarView view : starViews) { - view.setLayoutParams(getStarParams()); - } - didLayoutStars = true; - } - - private RelativeLayout.LayoutParams getStarParams() { - RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(STAR_SIZE, STAR_SIZE); - params.leftMargin = random.nextInt(width); - params.topMargin = random.nextInt(height); - return params; - } -} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/login/LoginBackgroundView.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/login/LoginBackgroundView.kt new file mode 100644 index 000000000..84e43b5a5 --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/login/LoginBackgroundView.kt @@ -0,0 +1,134 @@ +package com.habitrpg.android.habitica.ui.views.login + + +import android.animation.ObjectAnimator +import android.animation.ValueAnimator +import android.content.Context +import android.util.AttributeSet +import android.util.DisplayMetrics +import android.view.View +import android.view.WindowManager +import android.widget.FrameLayout +import android.widget.ImageView +import android.widget.RelativeLayout +import com.habitrpg.android.habitica.R +import com.habitrpg.android.habitica.ui.helpers.bindView +import java.util.* + +class LoginBackgroundView(context: Context, attrs: AttributeSet?) : RelativeLayout(context, attrs) { + private val random: Random = Random() + + private val leftCloudView: ImageView by bindView(R.id.left_cloud_view) + private val rightCloudView: ImageView by bindView(R.id.right_cloud_view) + + private var starViews: MutableList? = null + private var viewWidth: Int = 0 + private val viewHeight: Int + private var didLayoutStars = false + private var params = FrameLayout.LayoutParams(0, 0) + + private val blinkDuration: Int + get() = random.nextInt(30) * 800 + 4 + + private val starParams: RelativeLayout.LayoutParams + get() { + val params = RelativeLayout.LayoutParams(STAR_SIZE, STAR_SIZE) + params.leftMargin = random.nextInt(viewWidth) + params.topMargin = random.nextInt(viewHeight) + return params + } + + init { + val metrics = DisplayMetrics() + val windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager + windowManager.defaultDisplay.getMetrics(metrics) + viewHeight = (metrics.heightPixels * SIZE_FACTOR).toInt() + } + + override fun onFinishInflate() { + super.onFinishInflate() + starViews = ArrayList() + generateStars() + animateClouds() + } + + private fun animateClouds() { + val leftAnimator = ObjectAnimator.ofFloat(leftCloudView, View.TRANSLATION_Y, 10.0f).setDuration(5000) + leftAnimator.repeatCount = ValueAnimator.INFINITE + leftAnimator.repeatMode = ValueAnimator.REVERSE + leftAnimator.start() + val rightAnimator = ObjectAnimator.ofFloat(rightCloudView, View.TRANSLATION_Y, -10.0f).setDuration(8000) + rightAnimator.repeatCount = ValueAnimator.INFINITE + rightAnimator.repeatMode = ValueAnimator.REVERSE + rightAnimator.start() + } + + override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + this.viewWidth = View.MeasureSpec.getSize(widthMeasureSpec) + this.setMeasuredDimension(viewWidth, viewHeight) + params.width = viewWidth + params.height = viewHeight + this.layoutParams = params + super.onMeasure(widthMeasureSpec, heightMeasureSpec) + } + + override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) { + super.onLayout(changed, l, t, r, b) + updateStarLayoutParams() + } + + private fun generateStars() { + generateStars(1, 12, 25) + } + + private fun generateStars(largeCount: Int, mediumCount: Int, smallCount: Int) { + removeStarViews() + for (x in 0 until largeCount) { + generateStar(2) + } + for (x in 0 until mediumCount) { + generateStar(1) + } + for (x in 0 until smallCount) { + generateStar(0) + } + requestLayout() + } + + private fun removeStarViews() { + if (starViews?.size ?: 0 > 0) { + starViews?.forEach { this.removeView(it) } + starViews?.clear() + } + } + + private fun generateStar(size: Int) { + val starView = StarView(context) + starView.setStarSize(size) + if (random.nextInt(10) > 2) { + starView.setBlinkDurations(Arrays.asList(blinkDuration, blinkDuration, blinkDuration)) + } + starViews?.add(starView) + if (viewWidth > 0 && viewHeight > 0) { + this.addView(starView, 0, starParams) + } else { + this.addView(starView, 0) + } + } + + private fun updateStarLayoutParams() { + if (viewWidth <= 0 ||viewHeight <= 0 || didLayoutStars || starViews?.size == 0) { + return + } + for (view in starViews ?: emptyList()) { + view.layoutParams = starParams + } + didLayoutStars = true + } + + companion object { + + private const val SIZE_FACTOR = 1.5f + private const val STAR_SIZE = 30 + } +} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/settings/FixValuesEditText.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/settings/FixValuesEditText.kt index b6647c041..49848e24e 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/settings/FixValuesEditText.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/settings/FixValuesEditText.kt @@ -8,7 +8,6 @@ import android.support.v4.content.ContextCompat import android.util.AttributeSet import android.view.View import android.widget.FrameLayout -import butterknife.ButterKnife import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.extensions.backgroundCompat import com.habitrpg.android.habitica.ui.views.HabiticaIconsHelper diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/setup/AvatarCategoryView.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/setup/AvatarCategoryView.java deleted file mode 100644 index 869caeb47..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/setup/AvatarCategoryView.java +++ /dev/null @@ -1,58 +0,0 @@ -package com.habitrpg.android.habitica.ui.views.setup; - - -import android.content.Context; -import android.content.res.TypedArray; -import android.graphics.PorterDuff; -import android.graphics.drawable.Drawable; -import android.support.annotation.Nullable; -import android.support.v4.content.ContextCompat; -import android.util.AttributeSet; -import android.widget.LinearLayout; -import android.widget.TextView; - -import com.habitrpg.android.habitica.R; - -import butterknife.BindView; -import butterknife.ButterKnife; - -public class AvatarCategoryView extends LinearLayout { - - private final Drawable icon; - @BindView(R.id.text_view) - TextView textView; - - public AvatarCategoryView(Context context, @Nullable AttributeSet attrs) { - super(context, attrs); - inflate(context, R.layout.avatar_category, this); - - ButterKnife.bind(this); - - TypedArray a = context.getTheme().obtainStyledAttributes( - attrs, - R.styleable.AvatarCategoryView, - 0, 0); - - textView.setText(a.getText(R.styleable.AvatarCategoryView_categoryTitle)); - - icon = a.getDrawable(R.styleable.AvatarCategoryView_iconDrawable); - if (icon != null) { - textView.setCompoundDrawablesWithIntrinsicBounds(null, icon, null, null); - } - setActive(false); - } - - public void setActive(boolean active) { - int color; - if (active) { - color = ContextCompat.getColor(getContext(), R.color.white); - } else { - color = ContextCompat.getColor(getContext(), R.color.white_50_alpha); - } - textView.setTextColor(color); - if (icon != null) { - icon.setColorFilter(color, PorterDuff.Mode.MULTIPLY); - textView.setCompoundDrawablesWithIntrinsicBounds(null, icon, null, null); - } - } -} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/setup/AvatarCategoryView.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/setup/AvatarCategoryView.kt new file mode 100644 index 000000000..8a90d503b --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/setup/AvatarCategoryView.kt @@ -0,0 +1,49 @@ +package com.habitrpg.android.habitica.ui.views.setup + + +import android.content.Context +import android.graphics.PorterDuff +import android.graphics.drawable.Drawable +import android.support.v4.content.ContextCompat +import android.util.AttributeSet +import android.view.View +import android.widget.LinearLayout +import android.widget.TextView +import com.habitrpg.android.habitica.R +import com.habitrpg.android.habitica.ui.helpers.bindView + +class AvatarCategoryView(context: Context, attrs: AttributeSet?) : LinearLayout(context, attrs) { + + private val icon: Drawable? + private val textView: TextView by bindView(R.id.text_view) + + init { + View.inflate(context, R.layout.avatar_category, this) + + val a = context.theme.obtainStyledAttributes( + attrs, + R.styleable.AvatarCategoryView, + 0, 0) + + textView.text = a.getText(R.styleable.AvatarCategoryView_categoryTitle) + + icon = a.getDrawable(R.styleable.AvatarCategoryView_iconDrawable) + if (icon != null) { + textView.setCompoundDrawablesWithIntrinsicBounds(null, icon, null, null) + } + setActive(false) + } + + fun setActive(active: Boolean) { + val color: Int = if (active) { + ContextCompat.getColor(context, R.color.white) + } else { + ContextCompat.getColor(context, R.color.white_50_alpha) + } + textView.setTextColor(color) + if (icon != null) { + icon.setColorFilter(color, PorterDuff.Mode.MULTIPLY) + textView.setCompoundDrawablesWithIntrinsicBounds(null, icon, null, null) + } + } +} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/shops/PurchaseDialog.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/shops/PurchaseDialog.kt index 9a88f7d19..497130e8d 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/shops/PurchaseDialog.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/shops/PurchaseDialog.kt @@ -17,7 +17,7 @@ import com.habitrpg.android.habitica.data.UserRepository import com.habitrpg.android.habitica.events.GearPurchasedEvent import com.habitrpg.android.habitica.events.ShowSnackbarEvent import com.habitrpg.android.habitica.events.commands.OpenGemPurchaseFragmentCommand -import com.habitrpg.android.habitica.extensions.bindView +import com.habitrpg.android.habitica.ui.helpers.bindView import com.habitrpg.android.habitica.helpers.RemoteConfigManager import com.habitrpg.android.habitica.helpers.RxErrorHandler import com.habitrpg.android.habitica.models.inventory.Equipment diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/shops/PurchaseDialogContent.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/shops/PurchaseDialogContent.kt index ecbe4ba93..1d4d9a80c 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/shops/PurchaseDialogContent.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/shops/PurchaseDialogContent.kt @@ -7,7 +7,7 @@ import android.widget.LinearLayout import android.widget.TextView import com.facebook.drawee.view.SimpleDraweeView import com.habitrpg.android.habitica.R -import com.habitrpg.android.habitica.extensions.bindView +import com.habitrpg.android.habitica.ui.helpers.bindView import com.habitrpg.android.habitica.models.shops.ShopItem import com.habitrpg.android.habitica.ui.helpers.DataBindingUtils diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/shops/PurchaseDialogGearContent.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/shops/PurchaseDialogGearContent.kt index 7fe08c3be..31ac97855 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/shops/PurchaseDialogGearContent.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/shops/PurchaseDialogGearContent.kt @@ -5,7 +5,7 @@ import android.support.v4.content.ContextCompat import android.util.AttributeSet import android.widget.TextView import com.habitrpg.android.habitica.R -import com.habitrpg.android.habitica.extensions.bindView +import com.habitrpg.android.habitica.ui.helpers.bindView import com.habitrpg.android.habitica.models.inventory.Equipment import com.habitrpg.android.habitica.models.shops.ShopItem diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/shops/PurchaseDialogGemsContent.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/shops/PurchaseDialogGemsContent.kt index c6948dd5f..9b64ff5fb 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/shops/PurchaseDialogGemsContent.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/shops/PurchaseDialogGemsContent.kt @@ -3,7 +3,7 @@ package com.habitrpg.android.habitica.ui.views.shops import android.content.Context import android.widget.TextView import com.habitrpg.android.habitica.R -import com.habitrpg.android.habitica.extensions.bindView +import com.habitrpg.android.habitica.ui.helpers.bindView import com.habitrpg.android.habitica.models.shops.ShopItem internal class PurchaseDialogGemsContent(context: Context) : PurchaseDialogContent(context) { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/shops/PurchaseDialogItemContent.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/shops/PurchaseDialogItemContent.kt index 108e67100..68d4e599b 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/shops/PurchaseDialogItemContent.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/shops/PurchaseDialogItemContent.kt @@ -4,7 +4,7 @@ import android.content.Context import android.util.AttributeSet import android.widget.TextView import com.habitrpg.android.habitica.R -import com.habitrpg.android.habitica.extensions.bindView +import com.habitrpg.android.habitica.ui.helpers.bindView import com.habitrpg.android.habitica.models.shops.ShopItem class PurchaseDialogItemContent : PurchaseDialogContent { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/shops/PurchaseDialogQuestContent.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/shops/PurchaseDialogQuestContent.kt index 12575724d..214392d04 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/shops/PurchaseDialogQuestContent.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/shops/PurchaseDialogQuestContent.kt @@ -11,7 +11,7 @@ import android.widget.RatingBar import android.widget.TextView import com.facebook.drawee.view.SimpleDraweeView import com.habitrpg.android.habitica.R -import com.habitrpg.android.habitica.extensions.bindView +import com.habitrpg.android.habitica.ui.helpers.bindView import com.habitrpg.android.habitica.models.inventory.QuestContent import com.habitrpg.android.habitica.models.inventory.QuestDropItem import com.habitrpg.android.habitica.ui.helpers.DataBindingUtils diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/social/OldQuestProgressView.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/social/OldQuestProgressView.kt index 042f24f05..380c26412 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/social/OldQuestProgressView.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/social/OldQuestProgressView.kt @@ -8,13 +8,11 @@ import android.util.AttributeSet import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import android.widget.ImageView import android.widget.LinearLayout import android.widget.TextView -import butterknife.ButterKnife import com.facebook.drawee.view.SimpleDraweeView import com.habitrpg.android.habitica.R -import com.habitrpg.android.habitica.extensions.bindView +import com.habitrpg.android.habitica.ui.helpers.bindView import com.habitrpg.android.habitica.extensions.setScaledPadding import com.habitrpg.android.habitica.models.inventory.QuestContent import com.habitrpg.android.habitica.models.inventory.QuestProgress diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/social/QuestMenuView.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/social/QuestMenuView.kt index 1b2212b2e..433b25366 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/social/QuestMenuView.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/social/QuestMenuView.kt @@ -16,7 +16,7 @@ import android.widget.TextView import com.facebook.drawee.view.SimpleDraweeView import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.extensions.backgroundCompat -import com.habitrpg.android.habitica.extensions.bindView +import com.habitrpg.android.habitica.ui.helpers.bindView import com.habitrpg.android.habitica.models.inventory.Quest import com.habitrpg.android.habitica.models.inventory.QuestContent import com.habitrpg.android.habitica.models.user.User diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/social/QuestProgressView.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/social/QuestProgressView.kt index 824289ea6..d83ff597a 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/social/QuestProgressView.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/social/QuestProgressView.kt @@ -19,7 +19,7 @@ import android.widget.TextView import com.facebook.drawee.view.SimpleDraweeView import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.extensions.backgroundCompat -import com.habitrpg.android.habitica.extensions.bindView +import com.habitrpg.android.habitica.ui.helpers.bindView import com.habitrpg.android.habitica.helpers.RxErrorHandler import com.habitrpg.android.habitica.models.inventory.Quest import com.habitrpg.android.habitica.models.inventory.QuestContent diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/subscriptions/SubscriptionDetailsView.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/subscriptions/SubscriptionDetailsView.java deleted file mode 100644 index a711a5ce6..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/subscriptions/SubscriptionDetailsView.java +++ /dev/null @@ -1,133 +0,0 @@ -package com.habitrpg.android.habitica.ui.views.subscriptions; - - -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.net.Uri; -import android.util.AttributeSet; -import android.view.View; -import android.widget.Button; -import android.widget.LinearLayout; -import android.widget.TextView; - -import com.habitrpg.android.habitica.BuildConfig; -import com.habitrpg.android.habitica.R; -import com.habitrpg.android.habitica.models.user.SubscriptionPlan; - -import butterknife.BindView; -import butterknife.ButterKnife; -import butterknife.OnClick; - -public class SubscriptionDetailsView extends LinearLayout { - - @BindView(R.id.subscriptionDurationTextView) - TextView subscriptionDurationTextView; - - @BindView(R.id.subscriptionStatusActive) - TextView subscriptionStatusActive; - @BindView(R.id.subscriptionStatusInactive) - TextView getSubscriptionStatusInactive; - - @BindView(R.id.paymentProcessorTextView) - TextView paymentProcessorTextView; - - @BindView(R.id.monthsSubscribedTextView) - TextView monthsSubscribedTextView; - - @BindView(R.id.gemCapTextView) - TextView gemCapTextView; - - @BindView(R.id.currentHourglassesTextView) - TextView currentHourglassesTextView; - - @BindView(R.id.cancelSubscriptionDescription) - TextView cancelSubscripnDescription; - - @BindView(R.id.visitWebsiteButton) - Button visitWebsiteButton; - - private SubscriptionPlan plan; - - public SubscriptionDetailsView(Context context, AttributeSet attributeSet) { - super(context, attributeSet); - setupView(); - } - - public SubscriptionDetailsView(Context context) { - super(context); - setupView(); - } - - private void setupView() { - inflate(getContext(), R.layout.subscription_details, this); - - ButterKnife.bind(this); - } - - public void setPlan(SubscriptionPlan plan) { - this.plan = plan; - - if (plan.isActive()) { - subscriptionStatusActive.setVisibility(View.VISIBLE); - getSubscriptionStatusInactive.setVisibility(View.GONE); - } else { - subscriptionStatusActive.setVisibility(View.GONE); - getSubscriptionStatusInactive.setVisibility(View.VISIBLE); - } - - String duration = null; - - if (plan.planId != null) { - if (plan.planId.equals(SubscriptionPlan.PLANID_BASIC) || plan.planId.equals(SubscriptionPlan.PLANID_BASICEARNED)) { - duration = getResources().getString(R.string.month); - } else if (plan.planId.equals(SubscriptionPlan.PLANID_BASIC3MONTH)) { - duration = getResources().getString(R.string.three_months); - } else if (plan.planId.equals(SubscriptionPlan.PLANID_BASIC6MONTH) || plan.planId.equals(SubscriptionPlan.PLANID_GOOGLE6MONTH)) { - duration = getResources().getString(R.string.six_months); - } else if (plan.planId.equals(SubscriptionPlan.PLANID_BASIC12MONTH)) { - duration = getResources().getString(R.string.twelve_months); - } - } - - if (duration != null) { - subscriptionDurationTextView.setText(getResources().getString(R.string.subscription_duration, duration)); - } - - paymentProcessorTextView.setText(plan.paymentMethod); - - if (plan.consecutive.getCount() == 1) { - monthsSubscribedTextView.setText(getResources().getString(R.string.one_month)); - } else { - monthsSubscribedTextView.setText(getResources().getString(R.string.months, plan.consecutive.getCount())); - } - gemCapTextView.setText(String.valueOf(plan.consecutive.getGemCapExtra() + 25)); - currentHourglassesTextView.setText(String.valueOf(plan.consecutive.getTrinkets())); - - if (plan.paymentMethod != null) { - if (plan.paymentMethod.equals("Google")) { - cancelSubscripnDescription.setText(R.string.cancel_subscription_google_description); - visitWebsiteButton.setText(R.string.open_in_store); - } else { - cancelSubscripnDescription.setText(R.string.cancel_subscription_notgoogle_description); - visitWebsiteButton.setText(R.string.visit_habitica_website); - } - } - } - - @OnClick(R.id.visitWebsiteButton) - public void openSubscriptionWebsite() { - if (plan.paymentMethod != null) { - Intent intent; - if (plan.paymentMethod.equals("Google")) { - intent = new Intent(Intent.ACTION_VIEW) - .setComponent(new ComponentName("com.android.vending", - "com.google.android.finsky.activities.MainActivity")) - .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - } else { - intent = new Intent(Intent.ACTION_VIEW, Uri.parse(BuildConfig.BASE_URL + "/")); - } - getContext().startActivity(intent); - } - } -} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/subscriptions/SubscriptionDetailsView.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/subscriptions/SubscriptionDetailsView.kt new file mode 100644 index 000000000..494d31eaa --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/subscriptions/SubscriptionDetailsView.kt @@ -0,0 +1,110 @@ +package com.habitrpg.android.habitica.ui.views.subscriptions + + +import android.content.ComponentName +import android.content.Context +import android.content.Intent +import android.net.Uri +import android.util.AttributeSet +import android.view.View +import android.widget.Button +import android.widget.LinearLayout +import android.widget.TextView +import butterknife.OnClick +import com.habitrpg.android.habitica.BuildConfig +import com.habitrpg.android.habitica.R +import com.habitrpg.android.habitica.ui.helpers.bindView +import com.habitrpg.android.habitica.extensions.inflate +import com.habitrpg.android.habitica.models.user.SubscriptionPlan + +class SubscriptionDetailsView : LinearLayout { + + internal val subscriptionDurationTextView: TextView by bindView(R.id.subscriptionDurationTextView) + internal val subscriptionStatusActive: TextView by bindView(R.id.subscriptionStatusActive) + private val getSubscriptionStatusInactive: TextView by bindView(R.id.subscriptionStatusInactive) + internal val paymentProcessorTextView: TextView by bindView(R.id.paymentProcessorTextView) + internal val monthsSubscribedTextView: TextView by bindView(R.id.monthsSubscribedTextView) + internal val gemCapTextView: TextView by bindView(R.id.gemCapTextView) + internal val currentHourglassesTextView: TextView by bindView(R.id.currentHourglassesTextView) + private val cancelSubscripnDescription: TextView by bindView(R.id.cancelSubscriptionDescription) + internal val visitWebsiteButton: Button by bindView(R.id.visitWebsiteButton) + + private var plan: SubscriptionPlan? = null + + constructor(context: Context, attributeSet: AttributeSet) : super(context, attributeSet) { + setupView() + } + + constructor(context: Context) : super(context) { + setupView() + } + + private fun setupView() { + inflate(R.layout.subscription_details) + } + + fun setPlan(plan: SubscriptionPlan) { + this.plan = plan + + if (plan.isActive) { + subscriptionStatusActive.visibility = View.VISIBLE + getSubscriptionStatusInactive.visibility = View.GONE + } else { + subscriptionStatusActive.visibility = View.GONE + getSubscriptionStatusInactive.visibility = View.VISIBLE + } + + var duration: String? = null + + if (plan.planId != null) { + if (plan.planId == SubscriptionPlan.PLANID_BASIC || plan.planId == SubscriptionPlan.PLANID_BASICEARNED) { + duration = resources.getString(R.string.month) + } else if (plan.planId == SubscriptionPlan.PLANID_BASIC3MONTH) { + duration = resources.getString(R.string.three_months) + } else if (plan.planId == SubscriptionPlan.PLANID_BASIC6MONTH || plan.planId == SubscriptionPlan.PLANID_GOOGLE6MONTH) { + duration = resources.getString(R.string.six_months) + } else if (plan.planId == SubscriptionPlan.PLANID_BASIC12MONTH) { + duration = resources.getString(R.string.twelve_months) + } + } + + if (duration != null) { + subscriptionDurationTextView.text = resources.getString(R.string.subscription_duration, duration) + } + + paymentProcessorTextView.text = plan.paymentMethod + + if (plan.consecutive.count == 1) { + monthsSubscribedTextView.text = resources.getString(R.string.one_month) + } else { + monthsSubscribedTextView.text = resources.getString(R.string.months, plan.consecutive.count) + } + gemCapTextView.text = (plan.consecutive.gemCapExtra + 25).toString() + currentHourglassesTextView.text = plan.consecutive.trinkets.toString() + + if (plan.paymentMethod != null) { + if (plan.paymentMethod == "Google") { + cancelSubscripnDescription.setText(R.string.cancel_subscription_google_description) + visitWebsiteButton.setText(R.string.open_in_store) + } else { + cancelSubscripnDescription.setText(R.string.cancel_subscription_notgoogle_description) + visitWebsiteButton.setText(R.string.visit_habitica_website) + } + } + } + + @OnClick(R.id.visitWebsiteButton) + fun openSubscriptionWebsite() { + if (plan?.paymentMethod != null) { + val intent: Intent = if (plan?.paymentMethod == "Google") { + Intent(Intent.ACTION_VIEW) + .setComponent(ComponentName("com.android.vending", + "com.google.android.finsky.activities.MainActivity")) + .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + } else { + Intent(Intent.ACTION_VIEW, Uri.parse(BuildConfig.BASE_URL + "/")) + } + context.startActivity(intent) + } + } +} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/subscriptions/SubscriptionOptionView.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/subscriptions/SubscriptionOptionView.java deleted file mode 100644 index 480684123..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/subscriptions/SubscriptionOptionView.java +++ /dev/null @@ -1,103 +0,0 @@ -package com.habitrpg.android.habitica.ui.views.subscriptions; - -import android.content.Context; -import android.content.res.TypedArray; -import android.util.AttributeSet; -import android.view.View; -import android.widget.Button; -import android.widget.FrameLayout; -import android.widget.TextView; - -import com.habitrpg.android.habitica.R; - -import butterknife.BindView; -import butterknife.ButterKnife; - - -public class SubscriptionOptionView extends FrameLayout { - - @BindView(R.id.priceLabel) - TextView priceTextView; - - @BindView(R.id.descriptionTextView) - TextView descriptionTextView; - - @BindView(R.id.subscriptionSelectedView) - View subscriptionSelectedView; - - @BindView(R.id.subscriptionSelectedFrameView) - View subscriptionSelectedFrameView; - - @BindView(R.id.gemCapTextView) - TextView gemCapTextView; - - @BindView(R.id.hourglassTextView) - TextView hourGlassTextView; - - private String sku; - - public SubscriptionOptionView(Context context, AttributeSet attrs) { - super(context, attrs); - - inflate(context, R.layout.purchase_subscription_view, this); - - ButterKnife.bind(this); - - TypedArray a = context.getTheme().obtainStyledAttributes( - attrs, - R.styleable.SubscriptionOptionView, - 0, 0); - - descriptionTextView.setText(context.getString(R.string.subscription_duration, a.getText(R.styleable.SubscriptionOptionView_recurringText))); - - gemCapTextView.setText(a.getText(R.styleable.SubscriptionOptionView_gemCapText)); - Integer hourGlassCount = a.getInteger(R.styleable.SubscriptionOptionView_hourGlassCount, 0); - if (hourGlassCount != 0) { - hourGlassTextView.setText(context.getString(R.string.subscription_hourglasses, hourGlassCount)); - hourGlassTextView.setVisibility(View.VISIBLE); - } else { - hourGlassTextView.setVisibility(View.GONE); - } - - } - - public void setOnPurchaseClickListener(Button.OnClickListener listener) { - this.setOnClickListener(listener); - } - - public void setPriceText(String text) { - this.priceTextView.setText(text); - } - - public String getSku() { - return sku; - } - - public void setSku(String sku) { - this.sku = sku; - } - - public void setIsPurchased(boolean purchased) { - int horizontalPadding = (int) getResources().getDimension(R.dimen.pill_horizontal_padding); - int verticalPadding = (int) getResources().getDimension(R.dimen.pill_vertical_padding); - if (purchased) { - subscriptionSelectedView.setBackgroundResource(R.drawable.subscription_selected); - subscriptionSelectedFrameView.setBackgroundResource(R.color.brand_300); - gemCapTextView.setBackgroundResource(R.drawable.pill_bg_green); - gemCapTextView.setTextColor(getContext().getResources().getColor(R.color.white)); - gemCapTextView.setPadding(horizontalPadding, verticalPadding, horizontalPadding, verticalPadding); - hourGlassTextView.setBackgroundResource(R.drawable.pill_bg_green); - hourGlassTextView.setTextColor(getContext().getResources().getColor(R.color.white)); - hourGlassTextView.setPadding(horizontalPadding, verticalPadding, horizontalPadding, verticalPadding); - } else { - subscriptionSelectedView.setBackgroundResource(R.drawable.subscription_unselected); - subscriptionSelectedFrameView.setBackgroundResource(R.color.brand_700); - gemCapTextView.setBackgroundResource(R.drawable.pill_bg); - gemCapTextView.setTextColor(getContext().getResources().getColor(R.color.text_light)); - gemCapTextView.setPadding(horizontalPadding, verticalPadding, horizontalPadding, verticalPadding); - hourGlassTextView.setBackgroundResource(R.drawable.pill_bg); - hourGlassTextView.setTextColor(getContext().getResources().getColor(R.color.text_light)); - hourGlassTextView.setPadding(horizontalPadding, verticalPadding, horizontalPadding, verticalPadding); - } - } -} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/subscriptions/SubscriptionOptionView.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/subscriptions/SubscriptionOptionView.kt new file mode 100644 index 000000000..e6bbe622a --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/subscriptions/SubscriptionOptionView.kt @@ -0,0 +1,76 @@ +package com.habitrpg.android.habitica.ui.views.subscriptions + +import android.content.Context +import android.util.AttributeSet +import android.view.View +import android.widget.FrameLayout +import android.widget.TextView +import com.habitrpg.android.habitica.R +import com.habitrpg.android.habitica.ui.helpers.bindView +import com.habitrpg.android.habitica.extensions.inflate + + +class SubscriptionOptionView(context: Context, attrs: AttributeSet) : FrameLayout(context, attrs) { + + private val priceTextView: TextView by bindView(R.id.priceLabel) + internal val descriptionTextView: TextView by bindView(R.id.descriptionTextView) + internal val subscriptionSelectedView: View by bindView(R.id.subscriptionSelectedView) + internal val subscriptionSelectedFrameView: View by bindView(R.id.subscriptionSelectedFrameView) + internal val gemCapTextView: TextView by bindView(R.id.gemCapTextView) + private val hourGlassTextView: TextView by bindView(R.id.hourglassTextView) + + var sku: String? = null + + init { + inflate(R.layout.purchase_subscription_view) + + val a = context.theme.obtainStyledAttributes( + attrs, + R.styleable.SubscriptionOptionView, + 0, 0) + + descriptionTextView.text = context.getString(R.string.subscription_duration, a.getText(R.styleable.SubscriptionOptionView_recurringText)) + + gemCapTextView.text = a.getText(R.styleable.SubscriptionOptionView_gemCapText) + val hourGlassCount = a.getInteger(R.styleable.SubscriptionOptionView_hourGlassCount, 0) + if (hourGlassCount != 0) { + hourGlassTextView.text = context.getString(R.string.subscription_hourglasses, hourGlassCount) + hourGlassTextView.visibility = View.VISIBLE + } else { + hourGlassTextView.visibility = View.GONE + } + + } + + fun setOnPurchaseClickListener(listener: OnClickListener) { + this.setOnClickListener(listener) + } + + fun setPriceText(text: String) { + this.priceTextView.text = text + } + + fun setIsPurchased(purchased: Boolean) { + val horizontalPadding = resources.getDimension(R.dimen.pill_horizontal_padding).toInt() + val verticalPadding = resources.getDimension(R.dimen.pill_vertical_padding).toInt() + if (purchased) { + subscriptionSelectedView.setBackgroundResource(R.drawable.subscription_selected) + subscriptionSelectedFrameView.setBackgroundResource(R.color.brand_300) + gemCapTextView.setBackgroundResource(R.drawable.pill_bg_green) + gemCapTextView.setTextColor(context.resources.getColor(R.color.white)) + gemCapTextView.setPadding(horizontalPadding, verticalPadding, horizontalPadding, verticalPadding) + hourGlassTextView.setBackgroundResource(R.drawable.pill_bg_green) + hourGlassTextView.setTextColor(context.resources.getColor(R.color.white)) + hourGlassTextView.setPadding(horizontalPadding, verticalPadding, horizontalPadding, verticalPadding) + } else { + subscriptionSelectedView.setBackgroundResource(R.drawable.subscription_unselected) + subscriptionSelectedFrameView.setBackgroundResource(R.color.brand_700) + gemCapTextView.setBackgroundResource(R.drawable.pill_bg) + gemCapTextView.setTextColor(context.resources.getColor(R.color.text_light)) + gemCapTextView.setPadding(horizontalPadding, verticalPadding, horizontalPadding, verticalPadding) + hourGlassTextView.setBackgroundResource(R.drawable.pill_bg) + hourGlassTextView.setTextColor(context.resources.getColor(R.color.text_light)) + hourGlassTextView.setPadding(horizontalPadding, verticalPadding, horizontalPadding, verticalPadding) + } + } +} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/tasks/TaskFilterDialog.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/tasks/TaskFilterDialog.java deleted file mode 100644 index ce7ed2d06..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/tasks/TaskFilterDialog.java +++ /dev/null @@ -1,434 +0,0 @@ -package com.habitrpg.android.habitica.ui.views.tasks; - -import android.content.Context; -import android.content.res.ColorStateList; -import android.graphics.Color; -import android.graphics.drawable.Drawable; -import android.os.Bundle; -import android.support.annotation.IdRes; -import android.support.annotation.Nullable; -import android.support.v4.content.ContextCompat; -import android.support.v4.widget.CompoundButtonCompat; -import android.support.v7.app.AlertDialog; -import android.support.v7.widget.AppCompatCheckBox; -import android.text.Editable; -import android.text.TextWatcher; -import android.util.TypedValue; -import android.view.LayoutInflater; -import android.view.View; -import android.view.WindowManager; -import android.widget.Button; -import android.widget.CheckBox; -import android.widget.EditText; -import android.widget.LinearLayout; -import android.widget.RadioButton; -import android.widget.RadioGroup; -import android.widget.TextView; - -import com.habitrpg.android.habitica.R; -import com.habitrpg.android.habitica.components.AppComponent; -import com.habitrpg.android.habitica.data.TagRepository; -import com.habitrpg.android.habitica.helpers.RxErrorHandler; -import com.habitrpg.android.habitica.models.Tag; -import com.habitrpg.android.habitica.models.tasks.Task; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; - -import javax.inject.Inject; - -import butterknife.BindView; -import butterknife.ButterKnife; -import butterknife.OnClick; -import io.reactivex.Observable; -import io.reactivex.functions.Function; - -public class TaskFilterDialog extends AlertDialog implements RadioGroup.OnCheckedChangeListener { - - @Inject - TagRepository repository; - - @BindView(R.id.task_type_title) - TextView taskTypeTitle; - - @BindView(R.id.task_filter_wrapper) - RadioGroup taskFilters; - @BindView(R.id.all_task_filter) - RadioButton allTaskFilter; - @BindView(R.id.second_task_filter) - RadioButton secondTaskFilter; - @BindView(R.id.third_task_filter) - RadioButton thirdTaskFilter; - - @BindView(R.id.tags_title) - TextView tagsTitleView; - @BindView(R.id.tag_edit_button) - Button tagsEditButton; - @BindView(R.id.tags_list) - LinearLayout tagsList; - private String taskType; - private OnFilterCompletedListener listener; - - private String filterType; - private List tags; - private List activeTags; - private Map editedTags = new HashMap<>(); - private Map createdTags = new HashMap<>(); - private List deletedTags = new ArrayList<>(); - - private Drawable addIcon; - private boolean isEditing; - - public TaskFilterDialog(Context context, AppComponent component) { - super(context); - component.inject(this); - addIcon = ContextCompat.getDrawable(context, R.drawable.ic_add_purple_300_36dp); - - LayoutInflater inflater = LayoutInflater.from(context); - View view = inflater.inflate(R.layout.dialog_task_filter, null); - - ButterKnife.bind(this, view); - - taskFilters.setOnCheckedChangeListener(this); - - setTitle(R.string.filters); - setView(view); - this.setButton(AlertDialog.BUTTON_POSITIVE, context.getString(R.string.done), (dialog, which) -> { - if (isEditing) { - stopEditing(); - } - if (listener != null) { - listener.onFilterCompleted(filterType, activeTags); - } - this.dismiss(); - }); - - setButton(AlertDialog.BUTTON_NEUTRAL, getContext().getString(R.string.clear), (dialog, which) -> { - }); - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - Button clearButton = getButton(AlertDialog.BUTTON_NEUTRAL); - if (clearButton != null) { - clearButton.setOnClickListener(view1 -> { - if (isEditing) { - stopEditing(); - } - setActiveFilter(null); - setActiveTags(null); - }); - clearButton.setEnabled(hasActiveFilters()); - } - } - - @Override - public void show() { - super.show(); - if (this.getWindow() != null) { - this.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); - } - } - - public void setTags(List tags) { - this.tags = repository.getUnmanagedCopy(tags); - createTagViews(); - } - - private void createTagViews() { - ColorStateList colorStateList = new ColorStateList( - new int[][]{ - new int[]{-android.R.attr.state_checked}, //disabled - new int[]{android.R.attr.state_checked} //enabled - }, - new int[] { - Color.LTGRAY, //disabled - ContextCompat.getColor(getContext(), R.color.brand_400) //enabled - } - ); - int leftPadding = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 16, getContext().getResources().getDisplayMetrics()); - int verticalPadding = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 12, getContext().getResources().getDisplayMetrics()); - for (Tag tag : tags) { - AppCompatCheckBox tagCheckbox = new AppCompatCheckBox(getContext()); - tagCheckbox.setText(tag.getName()); - tagCheckbox.setTextSize(TypedValue.COMPLEX_UNIT_SP,16); - tagCheckbox.setPadding(tagCheckbox.getPaddingLeft()+ leftPadding, - verticalPadding, - tagCheckbox.getPaddingRight(), - verticalPadding); - tagCheckbox.setTextColor(ContextCompat.getColor(getContext(), R.color.textColorLight)); - CompoundButtonCompat.setButtonTintList(tagCheckbox, colorStateList); - tagCheckbox.setOnCheckedChangeListener((buttonView, isChecked) -> { - if (isChecked) { - if (!activeTags.contains(tag.getId())) { - activeTags.add(tag.getId()); - } - } else { - if (activeTags.contains(tag.getId())) { - activeTags.remove(tag.getId()); - } - } - filtersChanged(); - }); - tagsList.addView(tagCheckbox); - } - createAddTagButton(); - } - - private void createAddTagButton() { - Button button = new Button(getContext()); - button.setText(R.string.add_tag); - button.setOnClickListener(v -> createTag()); - button.setCompoundDrawablesWithIntrinsicBounds(addIcon, null, null, null); - button.setBackgroundResource(R.drawable.layout_rounded_bg_lighter_gray); - button.setTextColor(ContextCompat.getColor(getContext(), R.color.text_light)); - tagsList.addView(button); - } - - private void createTag() { - Tag tag = new Tag(); - tag.id = UUID.randomUUID().toString(); - tags.add(tag); - createdTags.put(tag.getId(), tag); - startEditing(); - } - - private void startEditing() { - isEditing = true; - tagsList.removeAllViews(); - createTagEditViews(); - tagsEditButton.setText(R.string.done); - if (this.getWindow() != null) { - this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE); - } - } - - private void stopEditing() { - isEditing = false; - tagsList.removeAllViews(); - createTagViews(); - tagsEditButton.setText(R.string.edit_tag_btn_edit); - if (this.getWindow() != null) { - this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN); - } - repository.updateTags(editedTags.values()).toObservable() .flatMap(tags -> Observable.fromIterable(tags)).subscribe(tag -> editedTags.remove(tag.id), RxErrorHandler.handleEmptyError()); - repository.createTags(createdTags.values()).toObservable() .flatMap(tags -> Observable.fromIterable(tags)).subscribe(tag -> createdTags.remove(tag.getId()), RxErrorHandler.handleEmptyError()); - repository.deleteTags(deletedTags).subscribe(tags1 -> deletedTags.clear(), RxErrorHandler.handleEmptyError()); - } - - private void createTagEditViews() { - LayoutInflater inflater = LayoutInflater.from(getContext()); - if (tags != null) { - for (int index = 0; index < tags.size(); index++) { - Tag tag = tags.get(index); - createTagEditView(inflater, index, tag); - } - } - createAddTagButton(); - } - - private void createTagEditView(LayoutInflater inflater, int index, Tag tag) { - LinearLayout wrapper = (LinearLayout) inflater.inflate(R.layout.edit_tag_item, tagsList, false); - EditText tagEditText = (EditText) wrapper.findViewById(R.id.edit_text); - tagEditText.setText(tag.getName()); - tagEditText.addTextChangedListener(new TextWatcher() { - @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - - } - - @Override - public void onTextChanged(CharSequence s, int start, int before, int count) { - if (index >= tags.size()) { - return; - } - Tag tag = tags.get(index); - tag.setName(s.toString()); - if (createdTags.containsKey(tag.getId())) { - createdTags.put(tag.getId(), tag); - } else { - editedTags.put(tag.getId(), tag); - } - tags.set(index, tag); - } - - @Override - public void afterTextChanged(Editable s) { - - } - }); - Button deleteButton = (Button) wrapper.findViewById(R.id.delete_button); - deleteButton.setOnClickListener(v -> { - deletedTags.add(tag.getId()); - if (createdTags.containsKey(tag.getId())) { - createdTags.remove(tag.getId()); - } - if (editedTags.containsKey(tag.getId())) { - editedTags.remove(tag.getId()); - } - tags.remove(tag); - tagsList.removeView(wrapper); - }); - tagsList.addView(wrapper); - } - - public void setActiveTags(@Nullable List tagIds) { - if (tagIds == null) { - this.activeTags.clear(); - } else { - this.activeTags = tagIds; - } - for (int index = 0; index < tagsList.getChildCount()-1; index++) { - ((AppCompatCheckBox)tagsList.getChildAt(index)).setChecked(false); - } - for (String tagId : this.activeTags) { - int index = indexForId(tagId); - if (index >= 0) { - ((CheckBox)tagsList.getChildAt(index)).setChecked(true); - } - } - filtersChanged(); - } - - private int indexForId(String tagId) { - for (int index = 0; index < tags.size(); index++) { - if (tagId.equals(tags.get(index).id)) { - return index; - } - } - return -1; - } - - public void setTaskType(String taskType, String activeFilter) { - this.taskType = taskType; - switch (taskType) { - case Task.TYPE_HABIT: { - taskTypeTitle.setText(R.string.habits); - allTaskFilter.setText(R.string.all); - secondTaskFilter.setText(R.string.weak); - thirdTaskFilter.setText(R.string.strong); - break; - } - case Task.TYPE_DAILY: { - taskTypeTitle.setText(R.string.dailies); - allTaskFilter.setText(R.string.all); - secondTaskFilter.setText(R.string.active); - thirdTaskFilter.setText(R.string.gray); - break; - } - case Task.TYPE_TODO: { - taskTypeTitle.setText(R.string.todos); - allTaskFilter.setText(R.string.active); - secondTaskFilter.setText(R.string.dated); - thirdTaskFilter.setText(R.string.completed); - break; - } - } - setActiveFilter(activeFilter); - } - - private void setActiveFilter(@Nullable String activeFilter) { - filterType = activeFilter; - int checkedId = -1; - if (activeFilter == null) { - checkedId = R.id.all_task_filter; - } else { - switch (activeFilter) { - case Task.FILTER_ALL: - checkedId = R.id.all_task_filter; - break; - case Task.FILTER_WEAK: - case Task.FILTER_DATED: - checkedId = R.id.second_task_filter; - break; - case Task.FILTER_STRONG: - case Task.FILTER_GRAY: - case Task.FILTER_COMPLETED: - checkedId = R.id.third_task_filter; - break; - case Task.FILTER_ACTIVE: - if (taskType.equals(Task.TYPE_DAILY)) { - checkedId = R.id.second_task_filter; - } else { - checkedId = R.id.all_task_filter; - } - break; - } - } - taskFilters.check(checkedId); - filtersChanged(); - } - - @Override - public void onCheckedChanged(RadioGroup group, @IdRes int checkedId) { - if (taskType == null) { - return; - } - if (checkedId == R.id.all_task_filter) { - if (!taskType.equals(Task.TYPE_TODO)) { - filterType = Task.FILTER_ALL; - } else { - filterType = Task.FILTER_ACTIVE; - } - } else if (checkedId == R.id.second_task_filter) { - switch (taskType) { - case Task.TYPE_HABIT: - filterType = Task.FILTER_WEAK; - break; - case Task.FREQUENCY_DAILY: - filterType = Task.FILTER_ACTIVE; - break; - case Task.TYPE_TODO: - filterType = Task.FILTER_DATED; - break; - } - } else if (checkedId == R.id.third_task_filter) { - switch (taskType) { - case Task.TYPE_HABIT: - filterType = Task.FILTER_STRONG; - break; - case Task.FREQUENCY_DAILY: - filterType = Task.FILTER_GRAY; - break; - case Task.TYPE_TODO: - filterType = Task.FILTER_COMPLETED; - break; - } - } - filtersChanged(); - } - - @OnClick(R.id.tag_edit_button) - void editButtonClicked() { - isEditing = !isEditing; - if (isEditing) { - startEditing(); - } else { - stopEditing(); - } - } - - private void filtersChanged() { - Button clearButton = getButton(AlertDialog.BUTTON_NEUTRAL); - if (clearButton != null) { - clearButton.setEnabled(hasActiveFilters()); - } - } - - private boolean hasActiveFilters() { - return taskFilters.getCheckedRadioButtonId() != R.id.all_task_filter || activeTags.size() > 0; - } - - public void setListener(OnFilterCompletedListener listener) { - this.listener = listener; - } - - public interface OnFilterCompletedListener { - - void onFilterCompleted(@Nullable String activeTaskFilter, List activeTags); - } -} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/tasks/TaskFilterDialog.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/tasks/TaskFilterDialog.kt new file mode 100644 index 000000000..4f73a42db --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/tasks/TaskFilterDialog.kt @@ -0,0 +1,363 @@ +package com.habitrpg.android.habitica.ui.views.tasks + +import android.content.Context +import android.content.res.ColorStateList +import android.graphics.Color +import android.graphics.drawable.Drawable +import android.os.Bundle +import android.support.annotation.IdRes +import android.support.v4.content.ContextCompat +import android.support.v4.widget.CompoundButtonCompat +import android.support.v7.app.AlertDialog +import android.support.v7.widget.AppCompatCheckBox +import android.text.Editable +import android.text.TextWatcher +import android.util.TypedValue +import android.view.LayoutInflater +import android.view.View +import android.view.WindowManager +import android.widget.* +import com.habitrpg.android.habitica.R +import com.habitrpg.android.habitica.components.AppComponent +import com.habitrpg.android.habitica.data.TagRepository +import com.habitrpg.android.habitica.helpers.RxErrorHandler +import com.habitrpg.android.habitica.models.Tag +import com.habitrpg.android.habitica.models.tasks.Task +import com.habitrpg.android.habitica.ui.helpers.bindView +import io.reactivex.Observable +import io.reactivex.functions.Consumer +import java.util.* +import javax.inject.Inject + +class TaskFilterDialog(context: Context, component: AppComponent) : AlertDialog(context), RadioGroup.OnCheckedChangeListener { + + @Inject + lateinit var repository: TagRepository + + private val taskTypeTitle: TextView by bindView(R.id.task_type_title) + private val taskFilters: RadioGroup by bindView(R.id.task_filter_wrapper) + private val allTaskFilter: RadioButton by bindView(R.id.all_task_filter) + private val secondTaskFilter: RadioButton by bindView(R.id.second_task_filter) + private val thirdTaskFilter: RadioButton by bindView(R.id.third_task_filter) + private val tagsEditButton: Button by bindView(R.id.tag_edit_button) + private val tagsList: LinearLayout by bindView(R.id.tags_list) + private var taskType: String? = null + private var listener: OnFilterCompletedListener? = null + + private var filterType: String? = null + private var tags = mutableListOf() + private var activeTags = mutableListOf() + private val editedTags = HashMap() + private val createdTags = HashMap() + private val deletedTags = ArrayList() + + private val addIcon: Drawable? + private var isEditing: Boolean = false + + init { + component.inject(this) + addIcon = ContextCompat.getDrawable(context, R.drawable.ic_add_purple_300_36dp) + + val inflater = LayoutInflater.from(context) + val view = inflater.inflate(R.layout.dialog_task_filter, null) + + taskFilters.setOnCheckedChangeListener(this) + + setTitle(R.string.filters) + setView(view) + this.setButton(AlertDialog.BUTTON_POSITIVE, context.getString(R.string.done)) { _, _ -> + if (isEditing) { + stopEditing() + } + listener?.onFilterCompleted(filterType, activeTags) + this.dismiss() + } + + setButton(AlertDialog.BUTTON_NEUTRAL, getContext().getString(R.string.clear)) { _, _ -> } + + tagsEditButton.setOnClickListener { editButtonClicked() } + } + + override fun onCreate(savedInstanceState: Bundle) { + super.onCreate(savedInstanceState) + val clearButton = getButton(AlertDialog.BUTTON_NEUTRAL) + if (clearButton != null) { + clearButton.setOnClickListener { + if (isEditing) { + stopEditing() + } + setActiveFilter(null) + setActiveTags(null) + } + clearButton.isEnabled = hasActiveFilters() + } + } + + override fun show() { + super.show() + if (this.window != null) { + this.window.clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM) + } + } + + fun setTags(tags: List) { + this.tags = repository.getUnmanagedCopy(tags).toMutableList() + createTagViews() + } + + private fun createTagViews() { + val colorStateList = ColorStateList( + arrayOf(intArrayOf(-android.R.attr.state_checked), //disabled + intArrayOf(android.R.attr.state_checked) //enabled + ), + intArrayOf(Color.LTGRAY, //disabled + ContextCompat.getColor(context, R.color.brand_400) //enabled + ) + ) + val leftPadding = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 16f, context.resources.displayMetrics).toInt() + val verticalPadding = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 12f, context.resources.displayMetrics).toInt() + for (tag in tags) { + val tagCheckbox = AppCompatCheckBox(context) + tagCheckbox.text = tag.name + tagCheckbox.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16f) + tagCheckbox.setPadding(tagCheckbox.paddingLeft + leftPadding, + verticalPadding, + tagCheckbox.paddingRight, + verticalPadding) + tagCheckbox.setTextColor(ContextCompat.getColor(context, R.color.textColorLight)) + CompoundButtonCompat.setButtonTintList(tagCheckbox, colorStateList) + tagCheckbox.setOnCheckedChangeListener { _, isChecked -> + if (isChecked) { + if (!activeTags.contains(tag.getId())) { + activeTags.add(tag.getId()) + } + } else { + if (activeTags.contains(tag.getId())) { + activeTags.remove(tag.getId()) + } + } + filtersChanged() + } + tagsList.addView(tagCheckbox) + } + createAddTagButton() + } + + private fun createAddTagButton() { + val button = Button(context) + button.setText(R.string.add_tag) + button.setOnClickListener { createTag() } + button.setCompoundDrawablesWithIntrinsicBounds(addIcon, null, null, null) + button.setBackgroundResource(R.drawable.layout_rounded_bg_lighter_gray) + button.setTextColor(ContextCompat.getColor(context, R.color.text_light)) + tagsList.addView(button) + } + + private fun createTag() { + val tag = Tag() + tag.id = UUID.randomUUID().toString() + tags.add(tag) + createdTags[tag.getId()] = tag + startEditing() + } + + private fun startEditing() { + isEditing = true + tagsList.removeAllViews() + createTagEditViews() + tagsEditButton.setText(R.string.done) + if (this.window != null) { + this.window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE) + } + } + + private fun stopEditing() { + isEditing = false + tagsList.removeAllViews() + createTagViews() + tagsEditButton.setText(R.string.edit_tag_btn_edit) + if (this.window != null) { + this.window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN) + } + repository.updateTags(editedTags.values).toObservable().flatMap { tags -> Observable.fromIterable(tags) }.subscribe(Consumer { tag -> editedTags.remove(tag.id) }, RxErrorHandler.handleEmptyError()) + repository.createTags(createdTags.values).toObservable().flatMap { tags -> Observable.fromIterable(tags) }.subscribe(Consumer { tag -> createdTags.remove(tag.getId()) }, RxErrorHandler.handleEmptyError()) + repository.deleteTags(deletedTags).subscribe(Consumer { deletedTags.clear() }, RxErrorHandler.handleEmptyError()) + } + + private fun createTagEditViews() { + val inflater = LayoutInflater.from(context) + for (index in tags.indices) { + val tag = tags[index] + createTagEditView(inflater, index, tag) + } + createAddTagButton() + } + + private fun createTagEditView(inflater: LayoutInflater, index: Int, tag: Tag) { + val wrapper = inflater.inflate(R.layout.edit_tag_item, tagsList, false) as LinearLayout + val tagEditText = wrapper.findViewById(R.id.edit_text) as EditText + tagEditText.setText(tag.name) + tagEditText.addTextChangedListener(object : TextWatcher { + override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) { + + } + + override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) { + if (index >= tags.size) { + return + } + val changedTag = tags[index] + changedTag.name = s.toString() + if (createdTags.containsKey(changedTag.getId())) { + createdTags[changedTag.getId()] = changedTag + } else { + editedTags[changedTag.getId()] = changedTag + } + tags[index] = changedTag + } + + override fun afterTextChanged(s: Editable) { + + } + }) + val deleteButton = wrapper.findViewById(R.id.delete_button) as Button + deleteButton.setOnClickListener { + deletedTags.add(tag.getId()) + if (createdTags.containsKey(tag.getId())) { + createdTags.remove(tag.getId()) + } + if (editedTags.containsKey(tag.getId())) { + editedTags.remove(tag.getId()) + } + tags.remove(tag) + tagsList.removeView(wrapper) + } + tagsList.addView(wrapper) + } + + fun setActiveTags(tagIds: MutableList?) { + if (tagIds == null) { + this.activeTags.clear() + } else { + this.activeTags = tagIds + } + for (index in 0 until tagsList.childCount - 1) { + (tagsList.getChildAt(index) as AppCompatCheckBox).isChecked = false + } + for (tagId in this.activeTags) { + val index = indexForId(tagId) + if (index >= 0) { + (tagsList.getChildAt(index) as CheckBox).isChecked = true + } + } + filtersChanged() + } + + private fun indexForId(tagId: String): Int { + for (index in tags.indices) { + if (tagId == tags[index].id) { + return index + } + } + return -1 + } + + fun setTaskType(taskType: String, activeFilter: String) { + this.taskType = taskType + when (taskType) { + Task.TYPE_HABIT -> { + taskTypeTitle.setText(R.string.habits) + allTaskFilter.setText(R.string.all) + secondTaskFilter.setText(R.string.weak) + thirdTaskFilter.setText(R.string.strong) + } + Task.TYPE_DAILY -> { + taskTypeTitle.setText(R.string.dailies) + allTaskFilter.setText(R.string.all) + secondTaskFilter.setText(R.string.active) + thirdTaskFilter.setText(R.string.gray) + } + Task.TYPE_TODO -> { + taskTypeTitle.setText(R.string.todos) + allTaskFilter.setText(R.string.active) + secondTaskFilter.setText(R.string.dated) + thirdTaskFilter.setText(R.string.completed) + } + } + setActiveFilter(activeFilter) + } + + private fun setActiveFilter(activeFilter: String?) { + filterType = activeFilter + var checkedId = -1 + if (activeFilter == null) { + checkedId = R.id.all_task_filter + } else { + when (activeFilter) { + Task.FILTER_ALL -> checkedId = R.id.all_task_filter + Task.FILTER_WEAK, Task.FILTER_DATED -> checkedId = R.id.second_task_filter + Task.FILTER_STRONG, Task.FILTER_GRAY, Task.FILTER_COMPLETED -> checkedId = R.id.third_task_filter + Task.FILTER_ACTIVE -> checkedId = if (taskType == Task.TYPE_DAILY) { + R.id.second_task_filter + } else { + R.id.all_task_filter + } + } + } + taskFilters.check(checkedId) + filtersChanged() + } + + override fun onCheckedChanged(group: RadioGroup, @IdRes checkedId: Int) { + if (taskType == null) { + return + } + when (checkedId) { + R.id.all_task_filter -> filterType = if (taskType != Task.TYPE_TODO) { + Task.FILTER_ALL + } else { + Task.FILTER_ACTIVE + } + R.id.second_task_filter -> when (taskType) { + Task.TYPE_HABIT -> filterType = Task.FILTER_WEAK + Task.FREQUENCY_DAILY -> filterType = Task.FILTER_ACTIVE + Task.TYPE_TODO -> filterType = Task.FILTER_DATED + } + R.id.third_task_filter -> when (taskType) { + Task.TYPE_HABIT -> filterType = Task.FILTER_STRONG + Task.FREQUENCY_DAILY -> filterType = Task.FILTER_GRAY + Task.TYPE_TODO -> filterType = Task.FILTER_COMPLETED + } + } + filtersChanged() + } + + private fun editButtonClicked() { + isEditing = !isEditing + if (isEditing) { + startEditing() + } else { + stopEditing() + } + } + + private fun filtersChanged() { + val clearButton = getButton(AlertDialog.BUTTON_NEUTRAL) + if (clearButton != null) { + clearButton.isEnabled = hasActiveFilters() + } + } + + private fun hasActiveFilters(): Boolean { + return taskFilters.checkedRadioButtonId != R.id.all_task_filter || activeTags.size > 0 + } + + fun setListener(listener: OnFilterCompletedListener) { + this.listener = listener + } + + interface OnFilterCompletedListener { + + fun onFilterCompleted(activeTaskFilter: String?, activeTags: List?) + } +} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/utils/MountMapDeserializer.java b/Habitica/src/main/java/com/habitrpg/android/habitica/utils/MountMapDeserializer.java index 964178761..527321e93 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/utils/MountMapDeserializer.java +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/utils/MountMapDeserializer.java @@ -14,9 +14,9 @@ import java.util.Map; import io.realm.Realm; -public class MountMapDeserializer implements JsonDeserializer> { +public class MountMapDeserializer implements JsonDeserializer> { @Override - public HashMap deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + public Map deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { HashMap vals = new HashMap<>(); if (json.isJsonObject()) { JsonObject object = json.getAsJsonObject(); diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/utils/PetMapDeserializer.java b/Habitica/src/main/java/com/habitrpg/android/habitica/utils/PetMapDeserializer.java index 10e3453c1..0191797ea 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/utils/PetMapDeserializer.java +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/utils/PetMapDeserializer.java @@ -14,9 +14,9 @@ import java.util.Map; import io.realm.Realm; -public class PetMapDeserializer implements JsonDeserializer> { +public class PetMapDeserializer implements JsonDeserializer> { @Override - public HashMap deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + public Map deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { HashMap vals = new HashMap<>(); if (json.isJsonObject()) { JsonObject object = json.getAsJsonObject(); diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/widget/HabitButtonWidgetService.java b/Habitica/src/main/java/com/habitrpg/android/habitica/widget/HabitButtonWidgetService.java index 0a1caeb44..ab3db0b3c 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/widget/HabitButtonWidgetService.java +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/widget/HabitButtonWidgetService.java @@ -69,7 +69,7 @@ public class HabitButtonWidgetService extends Service { private void updateData(Task task) { RemoteViews remoteViews = new RemoteViews(this.getPackageName(), R.layout.widget_habit_button); if (task != null && task.isValid()) { - CharSequence parsedText = MarkdownParser.parseMarkdown(task.getText()); + CharSequence parsedText = MarkdownParser.INSTANCE.parseMarkdown(task.getText()); SpannableStringBuilder builder = new SpannableStringBuilder(parsedText); EmojiHandler.addEmojis(this.context, builder, 16, DynamicDrawableSpan.ALIGN_BASELINE, 16, 0, -1, false); diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/widget/TaskListFactory.java b/Habitica/src/main/java/com/habitrpg/android/habitica/widget/TaskListFactory.java index 83c6bf26b..0fd16a7e0 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/widget/TaskListFactory.java +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/widget/TaskListFactory.java @@ -106,7 +106,7 @@ public abstract class TaskListFactory implements RemoteViewsService.RemoteViewsF if (taskList.size() > position) { Task task = taskList.get(position); - CharSequence parsedText = MarkdownParser.parseMarkdown(task.getText()); + CharSequence parsedText = MarkdownParser.INSTANCE.parseMarkdown(task.getText()); SpannableStringBuilder builder = new SpannableStringBuilder(parsedText); EmojiHandler.addEmojis(this.context, builder, 16, DynamicDrawableSpan.ALIGN_BASELINE, 16, 0, -1, false);