diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/SocialRepository.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/data/SocialRepository.kt index cd0454985..916bd4686 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/SocialRepository.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/SocialRepository.kt @@ -58,14 +58,14 @@ interface SocialRepository : BaseRepository { fun markPrivateMessagesRead(user: User?): Flowable - fun acceptQuest(user: User, partyId: String): Flowable - fun rejectQuest(user: User, partyId: String): Flowable + fun acceptQuest(user: User?, partyId: String): Flowable + fun rejectQuest(user: User?, partyId: String): Flowable - fun leaveQuest(partyId: String?): Flowable + fun leaveQuest(partyId: String): Flowable - fun cancelQuest(partyId: String?): Flowable + fun cancelQuest(partyId: String): Flowable - fun abortQuest(partyId: String?): Flowable + fun abortQuest(partyId: String): Flowable fun rejectGroupInvite(groupId: String): Flowable diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/SocialRepositoryImpl.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/SocialRepositoryImpl.kt index 0e77abf91..ef2dd0258 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/SocialRepositoryImpl.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/SocialRepositoryImpl.kt @@ -3,6 +3,7 @@ package com.habitrpg.android.habitica.data.implementation import com.habitrpg.android.habitica.data.ApiClient import com.habitrpg.android.habitica.data.SocialRepository import com.habitrpg.android.habitica.data.local.SocialLocalRepository +import com.habitrpg.android.habitica.extensions.notNull import com.habitrpg.android.habitica.helpers.RxErrorHandler import com.habitrpg.android.habitica.models.AchievementResult import com.habitrpg.android.habitica.models.inventory.Quest @@ -196,34 +197,34 @@ class SocialRepositoryImpl(localRepository: SocialLocalRepository, apiClient: Ap override fun getUserGroups(): Flowable> = localRepository.getUserGroups() - override fun acceptQuest(user: User, partyId: String): Flowable { + override fun acceptQuest(user: User?, partyId: String): Flowable { return apiClient.acceptQuest(partyId) - .doOnNext { localRepository.updateRSVPNeeded(user, false) } + .doOnNext { + user.notNull { + localRepository.updateRSVPNeeded(it, false) + } + } } - override fun rejectQuest(user: User, partyId: String): Flowable { + override fun rejectQuest(user: User?, partyId: String): Flowable { return apiClient.rejectQuest(partyId) - .doOnNext { localRepository.updateRSVPNeeded(user, false) } + .doOnNext { + user.notNull { + localRepository.updateRSVPNeeded(it, false) + } + } } - override fun leaveQuest(partyId: String?): Flowable { - return if (partyId == null) { - Flowable.empty() - } else apiClient.leaveQuest(partyId) + override fun leaveQuest(partyId: String): Flowable { + return apiClient.leaveQuest(partyId) } - override fun cancelQuest(partyId: String?): Flowable { - if (partyId == null) { - return Flowable.empty() - } + override fun cancelQuest(partyId: String): Flowable { return apiClient.cancelQuest(partyId) .doOnNext { localRepository.removeQuest(partyId) } } - override fun abortQuest(partyId: String?): Flowable { - if (partyId == null) { - return Flowable.empty() - } + override fun abortQuest(partyId: String): Flowable { return apiClient.abortQuest(partyId) .doOnNext { localRepository.removeQuest(partyId) } } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/AboutActivity.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/AboutActivity.java deleted file mode 100644 index cc2601417..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/AboutActivity.java +++ /dev/null @@ -1,145 +0,0 @@ -package com.habitrpg.android.habitica.ui.activities; - -import android.os.Bundle; -import android.support.design.widget.TabLayout; -import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentManager; -import android.support.v4.app.FragmentStatePagerAdapter; -import android.support.v4.view.ViewPager; -import android.support.v7.app.ActionBar; -import android.view.MenuItem; - -import com.habitrpg.android.habitica.R; -import com.habitrpg.android.habitica.components.AppComponent; -import com.habitrpg.android.habitica.ui.fragments.AboutFragment; -import com.mikepenz.aboutlibraries.Libs; -import com.mikepenz.aboutlibraries.LibsBuilder; - -import butterknife.BindView; - -public class AboutActivity extends BaseActivity { - - @BindView(R.id.pager) - ViewPager pager; - - @BindView(R.id.tab_layout) - TabLayout tabLayout; - - @Override - protected int getLayoutResId() { - return R.layout.activity_about; - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - ActionBar actionBar = getSupportActionBar(); - if (actionBar != null) { - actionBar.setTitle(R.string.about_title); - actionBar.setDisplayHomeAsUpEnabled(true); - actionBar.setDisplayShowHomeEnabled(false); - actionBar.setDisplayShowTitleEnabled(true); - actionBar.setDisplayUseLogoEnabled(false); - actionBar.setHomeButtonEnabled(false); - actionBar.setElevation(0); - } - - tabLayout.setTabGravity(TabLayout.GRAVITY_FILL); - - final PagerAdapter adapter = new PagerAdapter(getSupportFragmentManager(), 2); - pager.setAdapter(adapter); - pager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout)); - pager.setOffscreenPageLimit(1); - - tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() { - @Override - public void onTabSelected(TabLayout.Tab tab) { - pager.setCurrentItem(tab.getPosition()); - } - - @Override - public void onTabUnselected(TabLayout.Tab tab) { - - } - - @Override - public void onTabReselected(TabLayout.Tab tab) { - - } - }); - - tabLayout.setupWithViewPager(pager); - } - - @Override - protected void injectActivity(AppComponent component) { - component.inject(this); - } - - @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(); - - //noinspection SimplifiableIfStatement - if (id == android.R.id.home) { - finish(); - return true; - } - - return super.onOptionsItemSelected(item); - } - - private class PagerAdapter extends FragmentStatePagerAdapter { - int mNumOfTabs; - - public PagerAdapter(FragmentManager fm, int NumOfTabs) { - super(fm); - this.mNumOfTabs = NumOfTabs; - } - - @Override - public Fragment getItem(int position) { - - switch (position) { - case 0: - - return new AboutFragment(); - case 1: - return new LibsBuilder() - //Pass the fields of your application to the lib so it can find all external lib information - .withFields(R.string.class.getFields()) - .withActivityStyle(Libs.ActivityStyle.LIGHT_DARK_TOOLBAR) - .withAboutAppName(getString(R.string.app_name)) - .withAboutDescription("

Used Libraries

") - .withAboutIconShown(true) - .withAboutVersionShown(true) - .withAboutVersionShownCode(true) - .withAboutVersionShownName(true) - .supportFragment(); - default: - return null; - } - } - - @Override - public CharSequence getPageTitle(int position) { - if (position == 0) { - return getString(R.string.about_title); - } else if (position == 1) { - return getString(R.string.about_libraries); - } - - - return getString(R.string.about_versionhistory); - } - - @Override - public int getCount() { - return mNumOfTabs; - } - } -} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/AboutActivity.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/AboutActivity.kt new file mode 100644 index 000000000..26316ccc8 --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/AboutActivity.kt @@ -0,0 +1,121 @@ +package com.habitrpg.android.habitica.ui.activities + +import android.os.Bundle +import android.support.design.widget.TabLayout +import android.support.v4.app.Fragment +import android.support.v4.app.FragmentManager +import android.support.v4.app.FragmentStatePagerAdapter +import android.support.v4.view.ViewPager +import android.view.MenuItem +import com.habitrpg.android.habitica.R +import com.habitrpg.android.habitica.components.AppComponent +import com.habitrpg.android.habitica.ui.fragments.AboutFragment +import com.habitrpg.android.habitica.ui.helpers.bindView +import com.mikepenz.aboutlibraries.Libs +import com.mikepenz.aboutlibraries.LibsBuilder + +class AboutActivity : BaseActivity() { + + private val pager: ViewPager by bindView(R.id.pager) + private val tabLayout: TabLayout by bindView(R.id.tab_layout) + + override fun getLayoutResId(): Int { + return R.layout.activity_about + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + val actionBar = supportActionBar + if (actionBar != null) { + actionBar.setTitle(R.string.about_title) + actionBar.setDisplayHomeAsUpEnabled(true) + actionBar.setDisplayShowHomeEnabled(false) + actionBar.setDisplayShowTitleEnabled(true) + actionBar.setDisplayUseLogoEnabled(false) + actionBar.setHomeButtonEnabled(false) + actionBar.elevation = 0f + } + + tabLayout.tabGravity = TabLayout.GRAVITY_FILL + + val adapter = PagerAdapter(supportFragmentManager, 2) + pager.adapter = adapter + pager.addOnPageChangeListener(TabLayout.TabLayoutOnPageChangeListener(tabLayout)) + pager.offscreenPageLimit = 1 + + tabLayout.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener { + override fun onTabSelected(tab: TabLayout.Tab) { + pager.currentItem = tab.position + } + + override fun onTabUnselected(tab: TabLayout.Tab) { + + } + + override fun onTabReselected(tab: TabLayout.Tab) { + + } + }) + + tabLayout.setupWithViewPager(pager) + } + + override fun injectActivity(component: AppComponent) { + component.inject(this) + } + + 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 + + + if (id == android.R.id.home) { + finish() + return true + } + + return super.onOptionsItemSelected(item) + } + + private inner class PagerAdapter(fm: FragmentManager, internal var mNumOfTabs: Int) : FragmentStatePagerAdapter(fm) { + + override fun getItem(position: Int): Fragment? { + + when (position) { + 0 -> + + return AboutFragment() + 1 -> return LibsBuilder() + //Pass the fields of your application to the lib so it can find all external lib information + .withFields(R.string::class.java.fields) + .withActivityStyle(Libs.ActivityStyle.LIGHT_DARK_TOOLBAR) + .withAboutAppName(getString(R.string.app_name)) + .withAboutDescription("

Used Libraries

") + .withAboutIconShown(true) + .withAboutVersionShown(true) + .withAboutVersionShownCode(true) + .withAboutVersionShownName(true) + .supportFragment() + else -> return null + } + } + + override fun getPageTitle(position: Int): CharSequence? { + if (position == 0) { + return getString(R.string.about_title) + } else if (position == 1) { + return getString(R.string.about_libraries) + } + + + return getString(R.string.about_versionhistory) + } + + override fun getCount(): Int { + return mNumOfTabs + } + } +} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/SkillMemberActivity.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/SkillMemberActivity.java deleted file mode 100644 index 9152a1c56..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/SkillMemberActivity.java +++ /dev/null @@ -1,61 +0,0 @@ -package com.habitrpg.android.habitica.ui.activities; - -import android.app.Activity; -import android.content.Intent; -import android.os.Bundle; -import android.support.v7.widget.LinearLayoutManager; -import android.support.v7.widget.RecyclerView; - -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.data.UserRepository; -import com.habitrpg.android.habitica.helpers.RxErrorHandler; -import com.habitrpg.android.habitica.ui.adapter.social.PartyMemberRecyclerViewAdapter; - -import javax.inject.Inject; - -import butterknife.BindView; - -public class SkillMemberActivity extends BaseActivity { - @BindView(R.id.recyclerView) - RecyclerView recyclerView; - private PartyMemberRecyclerViewAdapter viewAdapter; - - @Inject - public SocialRepository socialRepository; - @Inject - public UserRepository userRepository; - - @Override - protected int getLayoutResId() { - return R.layout.activity_skill_members; - } - - @Override - protected void injectActivity(AppComponent component) { - component.inject(this); - } - - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - loadMemberList(); - } - - private void loadMemberList() { - recyclerView.setLayoutManager(new LinearLayoutManager(this)); - viewAdapter = new PartyMemberRecyclerViewAdapter(null, true, this); - viewAdapter.getUserClickedEvents().subscribe(userId -> { - Intent resultIntent = new Intent(); - resultIntent.putExtra("member_id", userId); - setResult(Activity.RESULT_OK, resultIntent); - finish(); - }, RxErrorHandler.handleEmptyError()); - recyclerView.setAdapter(viewAdapter); - - userRepository.getUser() - .firstElement() - .flatMap(user -> socialRepository.getGroupMembers(user.getParty().id).firstElement()) - .subscribe(viewAdapter::updateData, RxErrorHandler.handleEmptyError()); - } -} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/SkillMemberActivity.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/SkillMemberActivity.kt new file mode 100644 index 000000000..34bd81a19 --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/SkillMemberActivity.kt @@ -0,0 +1,57 @@ +package com.habitrpg.android.habitica.ui.activities + +import android.app.Activity +import android.content.Intent +import android.os.Bundle +import android.support.v7.widget.LinearLayoutManager +import android.support.v7.widget.RecyclerView +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.data.UserRepository +import com.habitrpg.android.habitica.helpers.RxErrorHandler +import com.habitrpg.android.habitica.ui.adapter.social.PartyMemberRecyclerViewAdapter +import com.habitrpg.android.habitica.ui.helpers.bindView +import io.reactivex.functions.Consumer +import javax.inject.Inject + +class SkillMemberActivity : BaseActivity() { + private val recyclerView: RecyclerView by bindView(R.id.recyclerView) + + private var viewAdapter: PartyMemberRecyclerViewAdapter? = null + + @Inject + lateinit var socialRepository: SocialRepository + @Inject + lateinit var userRepository: UserRepository + + override fun getLayoutResId(): Int { + return R.layout.activity_skill_members + } + + override fun injectActivity(component: AppComponent) { + component.inject(this) + } + + public override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + loadMemberList() + } + + private fun loadMemberList() { + recyclerView.layoutManager = LinearLayoutManager(this) + viewAdapter = PartyMemberRecyclerViewAdapter(null, true) + viewAdapter?.getUserClickedEvents()?.subscribe(Consumer { userId -> + val resultIntent = Intent() + resultIntent.putExtra("member_id", userId) + setResult(Activity.RESULT_OK, resultIntent) + finish() + }, RxErrorHandler.handleEmptyError()) + recyclerView.adapter = viewAdapter + + userRepository.getUser() + .firstElement() + .flatMap { user -> socialRepository.getGroupMembers(user.party.id).firstElement() } + .subscribe(Consumer { viewAdapter?.updateData(it) }, RxErrorHandler.handleEmptyError()) + } +} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/SkillTasksActivity.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/SkillTasksActivity.java index 96feed551..bb31e75bb 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/SkillTasksActivity.java +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/SkillTasksActivity.java @@ -62,13 +62,13 @@ public class SkillTasksActivity extends BaseActivity { SkillTasksRecyclerViewFragment fragment = new SkillTasksRecyclerViewFragment(); switch (position) { case 0: - fragment.taskType = Task.TYPE_HABIT; + fragment.setTaskType(Task.TYPE_HABIT); break; case 1: - fragment.taskType = Task.TYPE_DAILY; + fragment.setTaskType(Task.TYPE_DAILY); break; default: - fragment.taskType = Task.TYPE_TODO; + fragment.setTaskType(Task.TYPE_TODO); } compositeSubscription.add(fragment.getTaskSelectionEvents().subscribe(task -> taskSelected(task), RxErrorHandler.handleEmptyError())); diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/social/PartyMemberRecyclerViewAdapter.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/social/PartyMemberRecyclerViewAdapter.kt index 7425e9ab5..909db0991 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/social/PartyMemberRecyclerViewAdapter.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/social/PartyMemberRecyclerViewAdapter.kt @@ -23,7 +23,7 @@ import io.reactivex.subjects.PublishSubject import io.realm.OrderedRealmCollection import io.realm.RealmRecyclerViewAdapter -class PartyMemberRecyclerViewAdapter(data: OrderedRealmCollection?, autoUpdate: Boolean, private val context: Context) : RealmRecyclerViewAdapter(data, autoUpdate) { +class PartyMemberRecyclerViewAdapter(data: OrderedRealmCollection?, autoUpdate: Boolean) : RealmRecyclerViewAdapter(data, autoUpdate) { private val userClickedEvents = PublishSubject.create() @@ -60,9 +60,9 @@ class PartyMemberRecyclerViewAdapter(data: OrderedRealmCollection?, auto AvatarWithBarsViewModel.setHpBarData(hpBar, user.stats) - lvl.text = context.getString(R.string.user_level, user.stats.getLvl()) + lvl.text = itemView.context.getString(R.string.user_level, user.stats.getLvl()) - classLabel.text = user.stats.getTranslatedClassName(context) + classLabel.text = user.stats.getTranslatedClassName(itemView.context) val colorResourceID: Int = when (user.stats.habitClass) { Stats.HEALER -> { @@ -79,7 +79,7 @@ class PartyMemberRecyclerViewAdapter(data: OrderedRealmCollection?, auto } else -> R.color.task_gray } - ViewHelper.SetBackgroundTint(classBackground, ContextCompat.getColor(context, colorResourceID)) + ViewHelper.SetBackgroundTint(classBackground, ContextCompat.getColor(itemView.context, colorResourceID)) userName.text = user.profile.name itemView.isClickable = true diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/GemsPurchaseFragment.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/GemsPurchaseFragment.java deleted file mode 100644 index 7a2fe2a70..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/GemsPurchaseFragment.java +++ /dev/null @@ -1,136 +0,0 @@ -package com.habitrpg.android.habitica.ui.fragments; - -import android.graphics.drawable.BitmapDrawable; -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.TextView; - -import com.habitrpg.android.habitica.R; -import com.habitrpg.android.habitica.components.AppComponent; -import com.habitrpg.android.habitica.helpers.PurchaseTypes; -import com.habitrpg.android.habitica.proxy.CrashlyticsProxy; -import com.habitrpg.android.habitica.ui.GemPurchaseOptionsView; -import com.habitrpg.android.habitica.ui.activities.GemPurchaseActivity; -import com.habitrpg.android.habitica.ui.views.HabiticaIconsHelper; - -import org.solovyev.android.checkout.ActivityCheckout; -import org.solovyev.android.checkout.BillingRequests; -import org.solovyev.android.checkout.Inventory; -import org.solovyev.android.checkout.ProductTypes; -import org.solovyev.android.checkout.Sku; - -import javax.inject.Inject; - -import butterknife.BindView; - -public class GemsPurchaseFragment extends BaseFragment implements GemPurchaseActivity.CheckoutFragment { - - @BindView(R.id.gems_4_view) - GemPurchaseOptionsView gems4View; - @BindView(R.id.gems_21_view) - GemPurchaseOptionsView gems21View; - @BindView(R.id.gems_42_view) - GemPurchaseOptionsView gems42View; - @BindView(R.id.gems_84_view) - GemPurchaseOptionsView gems84View; - - @BindView(R.id.supportTextView) - TextView supportTextView; - - @Inject - CrashlyticsProxy crashlyticsProxy; - - private GemPurchaseActivity listener; - private BillingRequests billingRequests; - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - - super.onCreateView(inflater, container, savedInstanceState); - - return inflater.inflate(R.layout.fragment_gem_purchase, container, false); - } - - @Override - public void injectFragment(AppComponent component) { - component.inject(this); - } - - @Override - public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - - gems4View.setOnPurchaseClickListener(v -> purchaseGems(PurchaseTypes.Purchase4Gems)); - gems21View.setOnPurchaseClickListener(v -> purchaseGems(PurchaseTypes.Purchase21Gems)); - gems42View.setOnPurchaseClickListener(v -> purchaseGems(PurchaseTypes.Purchase42Gems)); - gems84View.setOnPurchaseClickListener(v -> purchaseGems(PurchaseTypes.Purchase84Gems)); - - Drawable heartDrawable = new BitmapDrawable(getResources(), HabiticaIconsHelper.imageOfHeartLarge()); - supportTextView.setCompoundDrawables(null, heartDrawable, null, null); - - gems84View.getSeedsImageButton().setOnClickListener(v -> ((GemPurchaseActivity) this.getActivity()).showSeedsPromo(getString(R.string.seeds_interstitial_gems), "store")); - } - - @Override - public void setupCheckout() { - final ActivityCheckout checkout = listener.getActivityCheckout(); - if (checkout != null) { - Inventory inventory = checkout.makeInventory(); - - inventory.load(Inventory.Request.create() - .loadAllPurchases().loadSkus(ProductTypes.IN_APP, PurchaseTypes.allGemTypes), - products -> { - Inventory.Product gems = products.get(ProductTypes.IN_APP); - if (!gems.supported) { - // billing is not supported, user can't purchase anything - return; - } - java.util.List skus = gems.getSkus(); - for (Sku sku : skus) { - updateButtonLabel(sku.id.code, sku.price); - } - }); - } - } - - @Override - public void setListener(GemPurchaseActivity listener) { - this.listener = listener; - } - - @Override - public void setBillingRequests(BillingRequests billingRequests) { - this.billingRequests = billingRequests; - } - - private void updateButtonLabel(String sku, String price) { - GemPurchaseOptionsView matchingView; - if (sku.equals(PurchaseTypes.Purchase4Gems)) { - matchingView = gems4View; - } else if (sku.equals(PurchaseTypes.Purchase21Gems)) { - matchingView = gems21View; - } else if (sku.equals(PurchaseTypes.Purchase42Gems)) { - matchingView = gems42View; - } else if (sku.equals(PurchaseTypes.Purchase84Gems)) { - matchingView = gems84View; - } else { - return; - } - if (matchingView != null) { - matchingView.setPurchaseButtonText(price); - matchingView.setSku(sku); - } - } - - public void purchaseGems(String sku) { - if (listener != null) { - final ActivityCheckout checkout = listener.getActivityCheckout(); - billingRequests.purchase(ProductTypes.IN_APP, sku, null, checkout.getPurchaseFlow()); - } - } -} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/GemsPurchaseFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/GemsPurchaseFragment.kt new file mode 100644 index 000000000..61700ed13 --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/GemsPurchaseFragment.kt @@ -0,0 +1,112 @@ +package com.habitrpg.android.habitica.ui.fragments + +import android.graphics.drawable.BitmapDrawable +import android.os.Bundle +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.extensions.notNull +import com.habitrpg.android.habitica.helpers.PurchaseTypes +import com.habitrpg.android.habitica.proxy.CrashlyticsProxy +import com.habitrpg.android.habitica.ui.GemPurchaseOptionsView +import com.habitrpg.android.habitica.ui.activities.GemPurchaseActivity +import com.habitrpg.android.habitica.ui.helpers.bindView +import com.habitrpg.android.habitica.ui.views.HabiticaIconsHelper +import org.solovyev.android.checkout.BillingRequests +import org.solovyev.android.checkout.Inventory +import org.solovyev.android.checkout.ProductTypes +import javax.inject.Inject + +class GemsPurchaseFragment : BaseFragment(), GemPurchaseActivity.CheckoutFragment { + + private val gems4View: GemPurchaseOptionsView? by bindView(R.id.gems_4_view) + private val gems21View: GemPurchaseOptionsView? by bindView(R.id.gems_21_view) + private val gems42View: GemPurchaseOptionsView? by bindView(R.id.gems_42_view) + private val gems84View: GemPurchaseOptionsView? by bindView(R.id.gems_84_view) + + private val supportTextView: TextView? by bindView(R.id.supportTextView) + + @Inject + lateinit var crashlyticsProxy: CrashlyticsProxy + + private var listener: GemPurchaseActivity? = null + private var billingRequests: BillingRequests? = null + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle?): View? { + + super.onCreateView(inflater, container, savedInstanceState) + return container?.inflate(R.layout.fragment_gem_purchase) + } + + override fun injectFragment(component: AppComponent) { + component.inject(this) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + gems4View?.setOnPurchaseClickListener(View.OnClickListener { purchaseGems(PurchaseTypes.Purchase4Gems) }) + gems21View?.setOnPurchaseClickListener(View.OnClickListener { purchaseGems(PurchaseTypes.Purchase21Gems) }) + gems42View?.setOnPurchaseClickListener(View.OnClickListener { purchaseGems(PurchaseTypes.Purchase42Gems) }) + gems84View?.setOnPurchaseClickListener(View.OnClickListener { purchaseGems(PurchaseTypes.Purchase84Gems) }) + + val heartDrawable = BitmapDrawable(resources, HabiticaIconsHelper.imageOfHeartLarge()) + supportTextView?.setCompoundDrawables(null, heartDrawable, null, null) + + gems84View?.seedsImageButton?.setOnClickListener { (this.activity as GemPurchaseActivity).showSeedsPromo(getString(R.string.seeds_interstitial_gems), "store") } + } + + override fun setupCheckout() { + val checkout = listener?.activityCheckout + if (checkout != null) { + val inventory = checkout.makeInventory() + + inventory.load(Inventory.Request.create() + .loadAllPurchases().loadSkus(ProductTypes.IN_APP, PurchaseTypes.allGemTypes) + ) { products -> + val gems = products.get(ProductTypes.IN_APP) + if (!gems.supported) { + // billing is not supported, user can't purchase anything + return@load + } + val skus = gems.skus + for (sku in skus) { + updateButtonLabel(sku.id.code, sku.price) + } + } + } + } + + override fun setListener(listener: GemPurchaseActivity) { + this.listener = listener + } + + override fun setBillingRequests(billingRequests: BillingRequests) { + this.billingRequests = billingRequests + } + + private fun updateButtonLabel(sku: String, price: String) { + val matchingView: GemPurchaseOptionsView? = when (sku) { + PurchaseTypes.Purchase4Gems -> gems4View + PurchaseTypes.Purchase21Gems -> gems21View + PurchaseTypes.Purchase42Gems -> gems42View + PurchaseTypes.Purchase84Gems -> gems84View + else -> return + } + if (matchingView != null) { + matchingView.setPurchaseButtonText(price) + matchingView.sku = sku + } + } + + fun purchaseGems(sku: String) { + listener?.activityCheckout.notNull { + billingRequests?.purchase(ProductTypes.IN_APP, sku, null, it.purchaseFlow) + } + } +} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/SubscriptionFragment.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/SubscriptionFragment.java deleted file mode 100644 index 5fd81338b..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/SubscriptionFragment.java +++ /dev/null @@ -1,321 +0,0 @@ -package com.habitrpg.android.habitica.ui.fragments; - -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.Drawable; -import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.Button; -import android.widget.ImageView; -import android.widget.ProgressBar; -import android.widget.TextView; - -import com.habitrpg.android.habitica.R; -import com.habitrpg.android.habitica.components.AppComponent; -import com.habitrpg.android.habitica.data.UserRepository; -import com.habitrpg.android.habitica.events.UserSubscribedEvent; -import com.habitrpg.android.habitica.helpers.PurchaseTypes; -import com.habitrpg.android.habitica.helpers.RxErrorHandler; -import com.habitrpg.android.habitica.models.user.SubscriptionPlan; -import com.habitrpg.android.habitica.models.user.User; -import com.habitrpg.android.habitica.proxy.CrashlyticsProxy; -import com.habitrpg.android.habitica.ui.activities.GemPurchaseActivity; -import com.habitrpg.android.habitica.ui.views.HabiticaIconsHelper; -import com.habitrpg.android.habitica.ui.views.subscriptions.SubscriptionDetailsView; -import com.habitrpg.android.habitica.ui.views.subscriptions.SubscriptionOptionView; - -import org.greenrobot.eventbus.Subscribe; -import org.solovyev.android.checkout.ActivityCheckout; -import org.solovyev.android.checkout.BillingRequests; -import org.solovyev.android.checkout.Inventory; -import org.solovyev.android.checkout.ProductTypes; -import org.solovyev.android.checkout.RequestListener; -import org.solovyev.android.checkout.Sku; - -import java.util.List; - -import javax.inject.Inject; - -import butterknife.BindView; -import butterknife.OnClick; - -public class SubscriptionFragment extends BaseFragment implements GemPurchaseActivity.CheckoutFragment { - - @Inject - CrashlyticsProxy crashlyticsProxy; - - @Inject - UserRepository userRepository; - - @BindView(R.id.subscribe_listitem1_box) - View subscribeListitem1Box; - @BindView(R.id.subscribe_listitem2_box) - View subscribeListitem2Box; - @BindView(R.id.subscribe_listitem3_box) - View subscribeListitem3Box; - @BindView(R.id.subscribe_listitem4_box) - View subscribeListitem4Box; - - @BindView(R.id.subscribe_listitem1_expand) - ImageView subscribeListitem1Button; - @BindView(R.id.subscribe_listitem2_expand) - ImageView subscribeListitem2Button; - @BindView(R.id.subscribe_listitem3_expand) - ImageView subscribeListitem3Button; - @BindView(R.id.subscribe_listitem4_expand) - ImageView subscribeListitem4Button; - - @BindView(R.id.subscribe_listitem1_description) - TextView subscribeListItem1Description; - @BindView(R.id.subscribe_listitem2_description) - TextView subscribeListItem2Description; - @BindView(R.id.subscribe_listitem3_description) - TextView subscribeListItem3Description; - @BindView(R.id.subscribe_listitem4_description) - TextView subscribeListItem4Description; - - @BindView(R.id.loadingIndicator) - ProgressBar loadingIndicator; - - @BindView(R.id.subscriptionOptions) - View subscriptionOptions; - - @BindView(R.id.subscription1month) - SubscriptionOptionView subscription1MonthView; - @BindView(R.id.subscription3month) - SubscriptionOptionView subscription3MonthView; - @BindView(R.id.subscription6month) - SubscriptionOptionView subscription6MonthView; - @BindView(R.id.subscription12month) - SubscriptionOptionView subscription12MonthView; - - @BindView(R.id.subscribeButton) - Button subscriptionButton; - - @BindView(R.id.subscriptionDetails) - SubscriptionDetailsView subscriptionDetailsView; - - @BindView(R.id.subscribeBenefitsTitle) - TextView subscribeBenefitsTitle; - - @BindView(R.id.supportTextView) - TextView supportTextView; - - @Nullable - Sku selectedSubscriptionSku; - List skus; - - private GemPurchaseActivity listener; - private BillingRequests billingRequests; - - private User user; - private boolean hasLoadedSubscriptionOptions; - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - - super.onCreateView(inflater, container, savedInstanceState); - - fetchUser(null); - - return inflater.inflate(R.layout.fragment_subscription, container, false); - } - - @Override - public void onDestroyView() { - super.onDestroyView(); - } - - @Subscribe - public void fetchUser(@Nullable UserSubscribedEvent event) { - userRepository.retrieveUser(false).subscribe(this::setUser, RxErrorHandler.handleEmptyError()); - } - - @Override - public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - - subscriptionOptions.setVisibility(View.GONE); - subscriptionDetailsView.setVisibility(View.GONE); - - this.subscription1MonthView.setOnPurchaseClickListener(view1 -> selectSubscription(PurchaseTypes.Subscription1Month)); - this.subscription3MonthView.setOnPurchaseClickListener(view1 -> selectSubscription(PurchaseTypes.Subscription3Month)); - this.subscription6MonthView.setOnPurchaseClickListener(view1 -> selectSubscription(PurchaseTypes.Subscription6Month)); - this.subscription12MonthView.setOnPurchaseClickListener(view1 -> selectSubscription(PurchaseTypes.Subscription12Month)); - - this.subscribeListitem1Box.setOnClickListener(view1 -> toggleDescriptionView(this.subscribeListitem1Button, this.subscribeListItem1Description)); - this.subscribeListitem2Box.setOnClickListener(view1 -> toggleDescriptionView(this.subscribeListitem2Button, this.subscribeListItem2Description)); - this.subscribeListitem3Box.setOnClickListener(view1 -> toggleDescriptionView(this.subscribeListitem3Button, this.subscribeListItem3Description)); - this.subscribeListitem4Box.setOnClickListener(view1 -> toggleDescriptionView(this.subscribeListitem4Button, this.subscribeListItem4Description)); - - Drawable heartDrawable = new BitmapDrawable(getResources(), HabiticaIconsHelper.imageOfHeartLarge()); - supportTextView.setCompoundDrawables(null, heartDrawable, null, null); - } - - private void toggleDescriptionView(ImageView button, TextView descriptionView) { - if (descriptionView.getVisibility() == View.VISIBLE) { - descriptionView.setVisibility(View.GONE); - button.setImageResource(R.drawable.ic_keyboard_arrow_down_black_24dp); - } else { - descriptionView.setVisibility(View.VISIBLE); - button.setImageResource(R.drawable.ic_keyboard_arrow_up_black_24dp); - } - } - - @Override - public void injectFragment(AppComponent component) { - component.inject(this); - } - - @Override - public void setupCheckout() { - final ActivityCheckout checkout = listener.getActivityCheckout(); - if (checkout != null) { - Inventory inventory = checkout.makeInventory(); - - inventory.load(Inventory.Request.create() - .loadAllPurchases().loadSkus(ProductTypes.SUBSCRIPTION, PurchaseTypes.allSubscriptionTypes), - products -> { - Inventory.Product subscriptions = products.get(ProductTypes.SUBSCRIPTION); - - skus = subscriptions.getSkus(); - - for (Sku sku : skus) { - updateButtonLabel(sku, sku.price, subscriptions); - } - selectSubscription(PurchaseTypes.Subscription1Month); - hasLoadedSubscriptionOptions = true; - updateSubscriptionInfo(); - }); - } - } - - private void updateButtonLabel(Sku sku, String price, Inventory.Product subscriptions) { - SubscriptionOptionView matchingView = buttonForSku(sku); - if (matchingView != null) { - matchingView.setPriceText(price); - matchingView.setSku(sku.id.code); - matchingView.setIsPurchased(subscriptions.isPurchased(sku)); - } - } - - private void selectSubscription(String sku) { - for (Sku thisSku : skus) { - if (thisSku.id.code.equals(sku)) { - selectSubscription(thisSku); - return; - } - } - } - - private void selectSubscription(Sku sku) { - if (this.selectedSubscriptionSku != null) { - SubscriptionOptionView oldButton = buttonForSku(this.selectedSubscriptionSku); - if (oldButton != null) { - oldButton.setIsPurchased(false); - } - } - this.selectedSubscriptionSku = sku; - SubscriptionOptionView subscriptionOptionButton = buttonForSku(this.selectedSubscriptionSku); - if (subscriptionOptionButton != null) { - subscriptionOptionButton.setIsPurchased(true); - } - if (this.subscriptionButton != null) { - this.subscriptionButton.setEnabled(true); - } - } - - @Nullable - private SubscriptionOptionView buttonForSku(Sku sku) { - return buttonForSku(sku.id.code); - } - - @Nullable - private SubscriptionOptionView buttonForSku(String sku) { - if (sku.equals(PurchaseTypes.Subscription1Month)) { - return subscription1MonthView; - } else if (sku.equals(PurchaseTypes.Subscription3Month)) { - return subscription3MonthView; - } else if (sku.equals(PurchaseTypes.Subscription6Month)) { - return subscription6MonthView; - } else if (sku.equals(PurchaseTypes.Subscription12Month)) { - return subscription12MonthView; - } else { - return null; - } - } - - @Override - public void setListener(GemPurchaseActivity listener) { - this.listener = listener; - } - - @Override - public void setBillingRequests(BillingRequests billingRequests) { - this.billingRequests = billingRequests; - } - - private void purchaseSubscription() { - if (selectedSubscriptionSku != null) { - billingRequests.isPurchased(ProductTypes.SUBSCRIPTION, this.selectedSubscriptionSku.id.code, new RequestListener() { - @Override - public void onSuccess(@NonNull Boolean aBoolean) { - if (!aBoolean) { - // no current product exist - final ActivityCheckout checkout = listener.getActivityCheckout(); - billingRequests.purchase(ProductTypes.SUBSCRIPTION, selectedSubscriptionSku.id.code, null, checkout.getPurchaseFlow()); - } - } - - @Override - public void onError(int i, @NonNull Exception e) { - crashlyticsProxy.fabricLogE("Purchase", "Error", e); - } - }); - } - } - - public void setUser(User newUser) { - user = newUser; - this.updateSubscriptionInfo(); - } - - private void updateSubscriptionInfo() { - if (user != null) { - SubscriptionPlan plan = user.getPurchased().getPlan(); - boolean isSubscribed = false; - if (plan != null) { - if (plan.isActive()) { - isSubscribed = true; - } - } - - if (this.subscriptionDetailsView == null) { - return; - } - - if (isSubscribed) { - this.subscriptionDetailsView.setVisibility(View.VISIBLE); - this.subscriptionDetailsView.setPlan(plan); - this.subscribeBenefitsTitle.setText(R.string.subscribe_prompt_thanks); - this.subscriptionOptions.setVisibility(View.GONE); - } else { - if (!hasLoadedSubscriptionOptions) { - return; - } - this.subscriptionOptions.setVisibility(View.VISIBLE); - this.subscriptionDetailsView.setVisibility(View.GONE); - } - this.loadingIndicator.setVisibility(View.GONE); - } - } - - @OnClick(R.id.subscribeButton) - public void subscribeUser() { - purchaseSubscription(); - } -} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/SubscriptionFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/SubscriptionFragment.kt new file mode 100644 index 000000000..b315c497d --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/SubscriptionFragment.kt @@ -0,0 +1,261 @@ +package com.habitrpg.android.habitica.ui.fragments + +import android.graphics.drawable.BitmapDrawable +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.Button +import android.widget.ImageView +import android.widget.ProgressBar +import android.widget.TextView +import com.habitrpg.android.habitica.R +import com.habitrpg.android.habitica.components.AppComponent +import com.habitrpg.android.habitica.data.UserRepository +import com.habitrpg.android.habitica.events.UserSubscribedEvent +import com.habitrpg.android.habitica.extensions.notNull +import com.habitrpg.android.habitica.helpers.PurchaseTypes +import com.habitrpg.android.habitica.helpers.RxErrorHandler +import com.habitrpg.android.habitica.models.user.User +import com.habitrpg.android.habitica.proxy.CrashlyticsProxy +import com.habitrpg.android.habitica.ui.activities.GemPurchaseActivity +import com.habitrpg.android.habitica.ui.helpers.bindView +import com.habitrpg.android.habitica.ui.views.HabiticaIconsHelper +import com.habitrpg.android.habitica.ui.views.subscriptions.SubscriptionDetailsView +import com.habitrpg.android.habitica.ui.views.subscriptions.SubscriptionOptionView +import io.reactivex.functions.Consumer +import kotlinx.android.synthetic.main.fragment_subscription.* +import org.greenrobot.eventbus.Subscribe +import org.solovyev.android.checkout.* +import javax.inject.Inject + +class SubscriptionFragment : BaseFragment(), GemPurchaseActivity.CheckoutFragment { + + @Inject + lateinit var crashlyticsProxy: CrashlyticsProxy + + @Inject + lateinit var userRepository: UserRepository + + private val subscribeListitem1Box: View? by bindView(R.id.subscribe_listitem1_box) + private val subscribeListitem2Box: View? by bindView(R.id.subscribe_listitem2_box) + private val subscribeListitem3Box: View? by bindView(R.id.subscribe_listitem3_box) + private val subscribeListitem4Box: View? by bindView(R.id.subscribe_listitem4_box) + + private val subscribeListitem1Button: ImageView? by bindView(R.id.subscribe_listitem1_expand) + private val subscribeListitem2Button: ImageView? by bindView(R.id.subscribe_listitem2_expand) + private val subscribeListitem3Button: ImageView? by bindView(R.id.subscribe_listitem3_expand) + private val subscribeListitem4Button: ImageView? by bindView(R.id.subscribe_listitem4_expand) + + private val subscribeListItem1Description: TextView? by bindView(R.id.subscribe_listitem1_description) + private val subscribeListItem2Description: TextView? by bindView(R.id.subscribe_listitem2_description) + private val subscribeListItem3Description: TextView? by bindView(R.id.subscribe_listitem3_description) + private val subscribeListItem4Description: TextView? by bindView(R.id.subscribe_listitem4_description) + + private val loadingIndicator: ProgressBar? by bindView(R.id.loadingIndicator) + private val subscriptionOptions: View? by bindView(R.id.subscriptionOptions) + + private val subscription1MonthView: SubscriptionOptionView? by bindView(R.id.subscription1month) + private val subscription3MonthView: SubscriptionOptionView? by bindView(R.id.subscription3month) + private val subscription6MonthView: SubscriptionOptionView? by bindView(R.id.subscription6month) + private val subscription12MonthView: SubscriptionOptionView? by bindView(R.id.subscription12month) + + private val subscriptionButton: Button? by bindView(R.id.subscribeButton) + private val subscriptionDetailsView: SubscriptionDetailsView? by bindView(R.id.subscriptionDetails) + private val subscribeBenefitsTitle: TextView? by bindView(R.id.subscribeBenefitsTitle) + private val supportTextView: TextView? by bindView(R.id.supportTextView) + + private var selectedSubscriptionSku: Sku? = null + private var skus: List = emptyList() + + private var listener: GemPurchaseActivity? = null + private var billingRequests: BillingRequests? = null + + private var user: User? = null + private var hasLoadedSubscriptionOptions: Boolean = false + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle?): View? { + + super.onCreateView(inflater, container, savedInstanceState) + + fetchUser(null) + + return inflater.inflate(R.layout.fragment_subscription, container, false) + } + + @Subscribe + fun fetchUser(event: UserSubscribedEvent?) { + userRepository.retrieveUser(false).subscribe(Consumer { this.setUser(it) }, RxErrorHandler.handleEmptyError()) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + subscriptionOptions?.visibility = View.GONE + subscriptionDetailsView?.visibility = View.GONE + + this.subscription1MonthView?.setOnPurchaseClickListener(View.OnClickListener { selectSubscription(PurchaseTypes.Subscription1Month) }) + this.subscription3MonthView?.setOnPurchaseClickListener(View.OnClickListener { selectSubscription(PurchaseTypes.Subscription3Month) }) + this.subscription6MonthView?.setOnPurchaseClickListener(View.OnClickListener { selectSubscription(PurchaseTypes.Subscription6Month) }) + this.subscription12MonthView?.setOnPurchaseClickListener(View.OnClickListener { selectSubscription(PurchaseTypes.Subscription12Month) }) + + this.subscribeListitem1Box?.setOnClickListener { toggleDescriptionView(this.subscribeListitem1Button, this.subscribeListItem1Description) } + this.subscribeListitem2Box?.setOnClickListener { toggleDescriptionView(this.subscribeListitem2Button, this.subscribeListItem2Description) } + this.subscribeListitem3Box?.setOnClickListener { toggleDescriptionView(this.subscribeListitem3Button, this.subscribeListItem3Description) } + this.subscribeListitem4Box?.setOnClickListener { toggleDescriptionView(this.subscribeListitem4Button, this.subscribeListItem4Description) } + + val heartDrawable = BitmapDrawable(resources, HabiticaIconsHelper.imageOfHeartLarge()) + supportTextView?.setCompoundDrawables(null, heartDrawable, null, null) + + subscribeButton.setOnClickListener { subscribeUser() } + } + + private fun toggleDescriptionView(button: ImageView?, descriptionView: TextView?) { + if (descriptionView?.visibility == View.VISIBLE) { + descriptionView.visibility = View.GONE + button?.setImageResource(R.drawable.ic_keyboard_arrow_down_black_24dp) + } else { + descriptionView?.visibility = View.VISIBLE + button?.setImageResource(R.drawable.ic_keyboard_arrow_up_black_24dp) + } + } + + override fun injectFragment(component: AppComponent) { + component.inject(this) + } + + override fun setupCheckout() { + val checkout = listener?.activityCheckout + if (checkout != null) { + val inventory = checkout.makeInventory() + + inventory.load(Inventory.Request.create() + .loadAllPurchases().loadSkus(ProductTypes.SUBSCRIPTION, PurchaseTypes.allSubscriptionTypes) + ) { products -> + val subscriptions = products.get(ProductTypes.SUBSCRIPTION) + + skus = subscriptions.skus + + for (sku in skus) { + updateButtonLabel(sku, sku.price, subscriptions) + } + selectSubscription(PurchaseTypes.Subscription1Month) + hasLoadedSubscriptionOptions = true + updateSubscriptionInfo() + } + } + } + + private fun updateButtonLabel(sku: Sku, price: String, subscriptions: Inventory.Product) { + val matchingView = buttonForSku(sku) + if (matchingView != null) { + matchingView.setPriceText(price) + matchingView.sku = sku.id.code + matchingView.setIsPurchased(subscriptions.isPurchased(sku)) + } + } + + private fun selectSubscription(sku: String) { + for (thisSku in skus) { + if (thisSku.id.code == sku) { + selectSubscription(thisSku) + return + } + } + } + + private fun selectSubscription(sku: Sku) { + if (this.selectedSubscriptionSku != null) { + val oldButton = buttonForSku(this.selectedSubscriptionSku) + oldButton?.setIsPurchased(false) + } + this.selectedSubscriptionSku = sku + val subscriptionOptionButton = buttonForSku(this.selectedSubscriptionSku) + subscriptionOptionButton?.setIsPurchased(true) + if (this.subscriptionButton != null) { + this.subscriptionButton?.isEnabled = true + } + } + + private fun buttonForSku(sku: Sku?): SubscriptionOptionView? { + return buttonForSku(sku?.id?.code) + } + + private fun buttonForSku(sku: String?): SubscriptionOptionView? { + return when (sku) { + PurchaseTypes.Subscription1Month -> subscription1MonthView + PurchaseTypes.Subscription3Month -> subscription3MonthView + PurchaseTypes.Subscription6Month -> subscription6MonthView + PurchaseTypes.Subscription12Month -> subscription12MonthView + else -> null + } + } + + override fun setListener(listener: GemPurchaseActivity) { + this.listener = listener + } + + override fun setBillingRequests(billingRequests: BillingRequests) { + this.billingRequests = billingRequests + } + + private fun purchaseSubscription() { + selectedSubscriptionSku?.id?.code.notNull { code -> + billingRequests?.isPurchased(ProductTypes.SUBSCRIPTION, code, object : RequestListener { + override fun onSuccess(aBoolean: Boolean) { + if (!aBoolean) { + // no current product exist + val checkout = listener?.activityCheckout + checkout.notNull { + billingRequests?.purchase(ProductTypes.SUBSCRIPTION, code, null, it.purchaseFlow) + } + } + } + + override fun onError(i: Int, e: Exception) { + crashlyticsProxy.fabricLogE("Purchase", "Error", e) + } + }) + } + } + + fun setUser(newUser: User) { + user = newUser + this.updateSubscriptionInfo() + } + + private fun updateSubscriptionInfo() { + if (user != null) { + val plan = user?.purchased?.plan + var isSubscribed = false + if (plan != null) { + if (plan.isActive) { + isSubscribed = true + } + } + + if (this.subscriptionDetailsView == null) { + return + } + + if (isSubscribed) { + this.subscriptionDetailsView?.visibility = View.VISIBLE + plan.notNull { this.subscriptionDetailsView?.setPlan(it) } + this.subscribeBenefitsTitle?.setText(R.string.subscribe_prompt_thanks) + this.subscriptionOptions?.visibility = View.GONE + } else { + if (!hasLoadedSubscriptionOptions) { + return + } + this.subscriptionOptions?.visibility = View.VISIBLE + this.subscriptionDetailsView?.visibility = View.GONE + } + this.loadingIndicator?.visibility = View.GONE + } + } + + fun subscribeUser() { + purchaseSubscription() + } +} 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 index da5f0b3d4..cf9241a8c 100644 --- 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 @@ -12,7 +12,6 @@ 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 diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/skills/SkillTasksRecyclerViewFragment.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/skills/SkillTasksRecyclerViewFragment.java deleted file mode 100644 index 6607c5758..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/skills/SkillTasksRecyclerViewFragment.java +++ /dev/null @@ -1,76 +0,0 @@ -package com.habitrpg.android.habitica.ui.fragments.skills; - -import android.os.Bundle; -import android.support.annotation.Nullable; -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.TaskRepository; -import com.habitrpg.android.habitica.helpers.RxErrorHandler; -import com.habitrpg.android.habitica.models.tasks.Task; -import com.habitrpg.android.habitica.modules.AppModule; -import com.habitrpg.android.habitica.ui.adapter.SkillTasksRecyclerViewAdapter; -import com.habitrpg.android.habitica.ui.fragments.BaseFragment; -import com.habitrpg.android.habitica.ui.helpers.SafeDefaultItemAnimator; - -import javax.inject.Inject; -import javax.inject.Named; - -import butterknife.BindView; -import io.reactivex.Flowable; - -public class SkillTasksRecyclerViewFragment extends BaseFragment { - @Inject - TaskRepository taskRepository; - @Inject - @Named(AppModule.NAMED_USER_ID) - String userId; - - @BindView(R.id.recyclerView) - public RecyclerView recyclerView; - public SkillTasksRecyclerViewAdapter adapter; - LinearLayoutManager layoutManager = null; - public String taskType; - private View view; - - public SkillTasksRecyclerViewFragment() { - super(); - adapter = new SkillTasksRecyclerViewAdapter(null, true); - } - - @Override - public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - return inflater.inflate(R.layout.fragment_recyclerview, container, false); - } - - @Override - public void injectFragment(AppComponent component) { - component.inject(this); - } - - @Override - public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - - taskRepository.getTasks(taskType, userId).firstElement().subscribe(tasks -> adapter.updateData(tasks), RxErrorHandler.handleEmptyError()); - recyclerView.setAdapter(adapter); - - layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager(); - - if (layoutManager == null) { - layoutManager = new LinearLayoutManager(getContext()); - - recyclerView.setLayoutManager(layoutManager); - } - recyclerView.setItemAnimator(new SafeDefaultItemAnimator()); - } - - public Flowable getTaskSelectionEvents() { - return adapter.getTaskSelectionEvents(); - } -} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/skills/SkillTasksRecyclerViewFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/skills/SkillTasksRecyclerViewFragment.kt new file mode 100644 index 000000000..2b695d098 --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/skills/SkillTasksRecyclerViewFragment.kt @@ -0,0 +1,67 @@ +package com.habitrpg.android.habitica.ui.fragments.skills + +import android.os.Bundle +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.TaskRepository +import com.habitrpg.android.habitica.helpers.RxErrorHandler +import com.habitrpg.android.habitica.models.tasks.Task +import com.habitrpg.android.habitica.modules.AppModule +import com.habitrpg.android.habitica.ui.adapter.SkillTasksRecyclerViewAdapter +import com.habitrpg.android.habitica.ui.fragments.BaseFragment +import com.habitrpg.android.habitica.ui.helpers.SafeDefaultItemAnimator + +import javax.inject.Inject +import javax.inject.Named + +import com.habitrpg.android.habitica.extensions.inflate +import com.habitrpg.android.habitica.ui.helpers.bindView +import io.reactivex.Flowable +import io.reactivex.functions.Consumer + +class SkillTasksRecyclerViewFragment : BaseFragment() { + @Inject + lateinit var taskRepository: TaskRepository + @field:[Inject Named(AppModule.NAMED_USER_ID)] + lateinit var userId: String + + private val recyclerView: RecyclerView? by bindView(R.id.recyclerView) + + var adapter: SkillTasksRecyclerViewAdapter = SkillTasksRecyclerViewAdapter(null, true) + internal var layoutManager: LinearLayoutManager? = null + var taskType: String? = null + + val taskSelectionEvents: Flowable + get() = adapter.getTaskSelectionEvents() + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + super.onCreateView(inflater, container, savedInstanceState) + return container?.inflate(R.id.recyclerView) + } + + override fun injectFragment(component: AppComponent) { + component.inject(this) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + taskRepository.getTasks(taskType ?: "", userId).firstElement().subscribe(Consumer { tasks -> adapter.updateData(tasks) }, RxErrorHandler.handleEmptyError()) + recyclerView?.adapter = adapter + + layoutManager = recyclerView?.layoutManager as LinearLayoutManager? + + if (layoutManager == null) { + layoutManager = LinearLayoutManager(context) + + recyclerView?.layoutManager = layoutManager + } + recyclerView?.itemAnimator = SafeDefaultItemAnimator() + } +} 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 deleted file mode 100644 index d25848678..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/QuestDetailFragment.java +++ /dev/null @@ -1,268 +0,0 @@ -package com.habitrpg.android.habitica.ui.fragments.social; - -import android.app.AlertDialog; -import android.content.Context; -import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.v4.content.ContextCompat; -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.facebook.drawee.view.SimpleDraweeView; -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.data.SocialRepository; -import com.habitrpg.android.habitica.data.UserRepository; -import com.habitrpg.android.habitica.helpers.RxErrorHandler; -import com.habitrpg.android.habitica.models.inventory.Quest; -import com.habitrpg.android.habitica.models.inventory.QuestContent; -import com.habitrpg.android.habitica.models.members.Member; -import com.habitrpg.android.habitica.models.social.Group; -import com.habitrpg.android.habitica.modules.AppModule; -import com.habitrpg.android.habitica.ui.fragments.BaseMainFragment; -import com.habitrpg.android.habitica.ui.helpers.DataBindingUtils; -import com.habitrpg.android.habitica.ui.helpers.MarkdownParser; - -import java.util.List; - -import javax.inject.Inject; -import javax.inject.Named; - -import butterknife.BindView; -import butterknife.OnClick; - -public class QuestDetailFragment extends BaseMainFragment { - - @Inject - SocialRepository socialRepository; - @Inject - UserRepository userRepository; - @Inject - InventoryRepository inventoryRepository; - @Inject - @Named(AppModule.NAMED_USER_ID) - String userId; - - @BindView(R.id.quest_title_view) - TextView questTitleView; - @BindView(R.id.quest_scroll_image_view) - SimpleDraweeView questScrollImageView; - @BindView(R.id.quest_leader_view) - TextView questLeaderView; - @BindView(R.id.description_view) - TextView questDescriptionView; - @BindView(R.id.quest_participant_list) - LinearLayout questParticipantList; - @BindView(R.id.participants_header) - TextView participantHeader; - @BindView(R.id.participants_header_count) - TextView participantHeaderCount; - @BindView(R.id.quest_participant_response_wrapper) - ViewGroup questParticipantResponseWrapper; - @BindView(R.id.quest_leader_response_wrapper) - ViewGroup questLeaderResponseWrapper; - @BindView(R.id.quest_accept_button) - Button questAcceptButton; - @BindView(R.id.quest_reject_button) - Button questRejectButton; - @BindView(R.id.quest_begin_button) - Button questBeginButton; - @BindView(R.id.quest_cancel_button) - Button questCancelButton; - @BindView(R.id.quest_abort_button) - Button questAbortButton; - - public String partyId; - public String questKey; - private Group party; - private Quest quest; - private String begin_quest_message; - - - @Nullable - @Override - public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - super.onCreateView(inflater, container, savedInstanceState); - return inflater.inflate(R.layout.fragment_quest_detail, container, false); - } - - - @Override - public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - } - - @Override - public void onResume() { - super.onResume(); - getCompositeSubscription().add(socialRepository.getGroup(partyId).subscribe(this::updateParty, RxErrorHandler.handleEmptyError())); - if (questKey != null) { - getCompositeSubscription().add(inventoryRepository.getQuestContent(questKey).subscribe(this::updateQuestContent, RxErrorHandler.handleEmptyError())); - } - } - - - private void updateParty(Group group) { - if (questTitleView == null || group == null|| group.getQuest() == null) { - return; - } - party = group; - quest = group.getQuest(); - setQuestParticipants(group.getQuest().getParticipants()); - socialRepository.getMember(quest.getLeader()).firstElement().subscribe(member -> { - if (getContext() != null && questLeaderView != null && member != null) { - questLeaderView.setText(getContext().getString(R.string.quest_leader_header, member.getDisplayName())); - } - }, RxErrorHandler.handleEmptyError()); - - if (questLeaderResponseWrapper != null) { - if (showParticipatantButtons()) { - questLeaderResponseWrapper.setVisibility(View.GONE); - questParticipantResponseWrapper.setVisibility(View.VISIBLE); - } else if (showLeaderButtons()) { - questParticipantResponseWrapper.setVisibility(View.GONE); - questLeaderResponseWrapper.setVisibility(View.VISIBLE); - if (isQuestActive()) { - questBeginButton.setVisibility(View.GONE); - questCancelButton.setVisibility(View.GONE); - questAbortButton.setVisibility(View.VISIBLE); - } else { - questBeginButton.setVisibility(View.VISIBLE); - questCancelButton.setVisibility(View.VISIBLE); - questAbortButton.setVisibility(View.GONE); - } - } else { - questLeaderResponseWrapper.setVisibility(View.GONE); - questParticipantResponseWrapper.setVisibility(View.GONE); - } - } - } - - private boolean showLeaderButtons() { - return party != null && party.getQuest() != null && userId != null && userId.equals(party.getQuest().getLeader()); - } - - private boolean showParticipatantButtons() { - if (user == null || user.getParty() == null || user.getParty().getQuest() == null) { - return false; - } - return !isQuestActive() && user.getParty().getQuest().getRSVPNeeded(); - } - - private boolean isQuestActive() { - return quest != null && quest.getActive(); - } - - - private void updateQuestContent(QuestContent questContent) { - if (questTitleView == null || !questContent.isManaged()) { - return; - } - questTitleView.setText(questContent.getText()); - //TODO: FIX - //questDescriptionView.setText(MarkdownParser.parseMarkdown(questContent.getNotes())); - DataBindingUtils.INSTANCE.loadImage(questScrollImageView, "inventory_quest_scroll_"+questContent.getKey()); - } - - private void setQuestParticipants(List participants) { - if (questParticipantList == null) { - return; - } - questParticipantList.removeAllViews(); - LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); - int participantCount = 0; - for (Member participant : participants) { - if (quest.getActive() && (participant.getParticipatesInQuest() == null || !participant.getParticipatesInQuest())) { - continue; - } - View participantView = inflater.inflate(R.layout.quest_participant, questParticipantList, false); - TextView textView = (TextView) participantView.findViewById(R.id.participant_name); - textView.setText(participant.getDisplayName()); - TextView statusTextView = (TextView) participantView.findViewById(R.id.status_view); - if (!quest.getActive()) { - if (participant.getParticipatesInQuest() == null) { - statusTextView.setText(R.string.pending); - statusTextView.setTextColor(ContextCompat.getColor(getContext(), R.color.gray_200)); - } else if (participant.getParticipatesInQuest()) { - statusTextView.setText(R.string.accepted); - statusTextView.setTextColor(ContextCompat.getColor(getContext(), R.color.green_100)); - } else { - statusTextView.setText(R.string.declined); - statusTextView.setTextColor(ContextCompat.getColor(getContext(), R.color.red_100)); - } - } else { - statusTextView.setVisibility(View.GONE); - } - questParticipantList.addView(participantView); - if (quest.getActive() || (participant.getParticipatesInQuest() != null && participant.getParticipatesInQuest())) { - participantCount += 1; - } - } - if (quest.getActive()) { - participantHeader.setText(R.string.participants); - participantHeaderCount.setText(String.valueOf(participantCount)); - } else { - participantHeader.setText(R.string.invitations); - participantHeaderCount.setText(participantCount + "/" + quest.getParticipants().size()); - begin_quest_message = getString(R.string.quest_begin_message, participantCount, quest.getParticipants().size()); - } - } - - @Override - public void onDestroyView() { - socialRepository.close(); - userRepository.close(); - inventoryRepository.close(); - super.onDestroyView(); - } - - @OnClick(R.id.quest_accept_button) - public void onQuestAccept() { - socialRepository.acceptQuest(user, partyId).subscribe(aVoid -> {}, RxErrorHandler.handleEmptyError()); - } - - - @OnClick(R.id.quest_reject_button) - public void onQuestReject() { - socialRepository.rejectQuest(user, partyId).subscribe(aVoid -> {}, RxErrorHandler.handleEmptyError()); - } - - @OnClick(R.id.quest_begin_button) - public void onQuestBegin() { - AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()) - .setMessage(begin_quest_message) - .setPositiveButton(R.string.yes, (dialog, which) -> socialRepository.forceStartQuest(party) - .subscribe(quest -> {}, RxErrorHandler.handleEmptyError())) - .setNegativeButton(R.string.no, (dialog, which) -> {}); - builder.show(); - } - - @OnClick(R.id.quest_cancel_button) - public void onQuestCancel() { - AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()) - .setMessage(R.string.quest_cancel_message) - .setPositiveButton(R.string.yes, (dialog, which) -> socialRepository.cancelQuest(partyId) - .subscribe(aVoid -> getActivity().getFragmentManager().popBackStack(), RxErrorHandler.handleEmptyError())).setNegativeButton(R.string.no, (dialog, which) -> {}); - builder.show(); - } - - @OnClick(R.id.quest_abort_button) - public void onQuestAbort() { - AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()) - .setMessage(R.string.quest_abort_message) - .setPositiveButton(R.string.yes, (dialog, which) -> socialRepository.abortQuest(partyId) - .subscribe(aVoid -> getActivity().getFragmentManager().popBackStack(), RxErrorHandler.handleEmptyError())).setNegativeButton(R.string.no, (dialog, which) -> {}); - builder.show(); - } - - @Override - public void injectFragment(AppComponent component) { - component.inject(this); - } -} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/QuestDetailFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/QuestDetailFragment.kt new file mode 100644 index 000000000..7008d517c --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/QuestDetailFragment.kt @@ -0,0 +1,263 @@ +package com.habitrpg.android.habitica.ui.fragments.social + +import android.app.AlertDialog +import android.content.Context +import android.os.Bundle +import android.support.v4.content.ContextCompat +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.facebook.drawee.view.SimpleDraweeView +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.data.SocialRepository +import com.habitrpg.android.habitica.extensions.notNull +import com.habitrpg.android.habitica.helpers.RxErrorHandler +import com.habitrpg.android.habitica.models.inventory.Quest +import com.habitrpg.android.habitica.models.inventory.QuestContent +import com.habitrpg.android.habitica.models.members.Member +import com.habitrpg.android.habitica.models.social.Group +import com.habitrpg.android.habitica.modules.AppModule +import com.habitrpg.android.habitica.ui.fragments.BaseMainFragment +import com.habitrpg.android.habitica.ui.helpers.DataBindingUtils +import com.habitrpg.android.habitica.ui.helpers.MarkdownParser +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 +import javax.inject.Named + +class QuestDetailFragment : BaseMainFragment() { + + @Inject + lateinit var socialRepository: SocialRepository + @Inject + lateinit var inventoryRepository: InventoryRepository + @field:[Inject Named(AppModule.NAMED_USER_ID)] + lateinit var userId: String + + private val questTitleView: TextView? by bindView(R.id.title_view) + private val questScrollImageView: SimpleDraweeView? by bindView(R.id.quest_scroll_image_view) + private val questLeaderView: TextView? by bindView(R.id.quest_leader_view) + private val questDescriptionView: TextView? by bindView(R.id.description_view) + private val questParticipantList: LinearLayout? by bindView(R.id.quest_participant_list) + private val participantHeader: TextView? by bindView(R.id.participants_header) + private val participantHeaderCount: TextView? by bindView(R.id.participants_header_count) + private val questParticipantResponseWrapper: ViewGroup? by bindView(R.id.quest_participant_response_wrapper) + private val questLeaderResponseWrapper: ViewGroup? by bindView(R.id.quest_leader_response_wrapper) + private val questAcceptButton: Button? by bindView(R.id.quest_accept_button) + private val questRejectButton: Button? by bindView(R.id.quest_reject_button) + private val questBeginButton: Button? by bindView(R.id.quest_begin_button) + private val questCancelButton: Button? by bindView(R.id.quest_cancel_button) + private val questAbortButton: Button? by bindView(R.id.quest_abort_button) + + var partyId: String? = null + var questKey: String? = null + private var party: Group? = null + private var quest: Quest? = null + private var beginQuestMessage: String? = null + + private val isQuestActive: Boolean + get() = quest?.active == true + + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + super.onCreateView(inflater, container, savedInstanceState) + return inflater.inflate(R.layout.fragment_quest_detail, container, false) + } + + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + resetViews() + + questAcceptButton?.setOnClickListener { onQuestAccept() } + questRejectButton?.setOnClickListener { onQuestReject() } + questBeginButton?.setOnClickListener { onQuestBegin() } + questCancelButton?.setOnClickListener { onQuestCancel() } + questAbortButton?.setOnClickListener { onQuestAbort() } + } + + override fun onResume() { + super.onResume() + compositeSubscription.add(socialRepository.getGroup(partyId).subscribe(Consumer { this.updateParty(it) }, RxErrorHandler.handleEmptyError())) + if (questKey != null) { + compositeSubscription.add(inventoryRepository.getQuestContent(questKey).subscribe(Consumer { this.updateQuestContent(it) }, RxErrorHandler.handleEmptyError())) + } + } + + + private fun updateParty(group: Group?) { + if (questTitleView == null || group == null || group.quest == null) { + return + } + party = group + quest = group.quest + setQuestParticipants(group.quest?.participants) + socialRepository.getMember(quest?.leader).firstElement().subscribe(Consumer { member -> + if (context != null && questLeaderView != null && member != null) { + questLeaderView?.text = context?.getString(R.string.quest_leader_header, member.displayName) + } + }, RxErrorHandler.handleEmptyError()) + + if (questLeaderResponseWrapper != null) { + if (showParticipatantButtons()) { + questLeaderResponseWrapper?.visibility = View.GONE + questParticipantResponseWrapper?.visibility = View.VISIBLE + } else if (showLeaderButtons()) { + questParticipantResponseWrapper?.visibility = View.GONE + questLeaderResponseWrapper?.visibility = View.VISIBLE + if (isQuestActive) { + questBeginButton?.visibility = View.GONE + questCancelButton?.visibility = View.GONE + questAbortButton?.visibility = View.VISIBLE + } else { + questBeginButton?.visibility = View.VISIBLE + questCancelButton?.visibility = View.VISIBLE + questAbortButton?.visibility = View.GONE + } + } else { + questLeaderResponseWrapper?.visibility = View.GONE + questParticipantResponseWrapper?.visibility = View.GONE + } + } + } + + private fun showLeaderButtons(): Boolean { + return userId == party?.quest?.leader + } + + private fun showParticipatantButtons(): Boolean { + return if (user == null || user?.party == null || user?.party?.quest == null) { + false + } else !isQuestActive && user?.party?.quest?.RSVPNeeded == true + } + + + private fun updateQuestContent(questContent: QuestContent) { + if (questTitleView == null || !questContent.isManaged) { + return + } + questTitleView?.text = questContent.text + //TODO: FIX + questDescriptionView?.text = MarkdownParser.parseMarkdown(questContent.notes) + DataBindingUtils.loadImage(questScrollImageView, "inventory_quest_scroll_" + questContent.key) + } + + private fun setQuestParticipants(participants: List?) { + if (questParticipantList == null) { + return + } + questParticipantList?.removeAllViews() + val inflater = context?.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater + var participantCount = 0 + for (participant in participants ?: emptyList()) { + if (quest?.active == true && (participant.participatesInQuest == null || !participant.participatesInQuest)) { + continue + } + val participantView = inflater.inflate(R.layout.quest_participant, questParticipantList, false) + val textView = participantView.findViewById(R.id.participant_name) as TextView + textView.text = participant.displayName + val statusTextView = participantView.findViewById(R.id.status_view) as TextView + if (quest?.active == false) { + context.notNull { + when { + participant.participatesInQuest == null -> { + statusTextView.setText(R.string.pending) + statusTextView.setTextColor(ContextCompat.getColor(it, R.color.gray_200)) + } + participant.participatesInQuest -> { + statusTextView.setText(R.string.accepted) + statusTextView.setTextColor(ContextCompat.getColor(it, R.color.green_100)) + } + else -> { + statusTextView.setText(R.string.declined) + statusTextView.setTextColor(ContextCompat.getColor(it, R.color.red_100)) + } + } + } + + } else { + statusTextView.visibility = View.GONE + } + questParticipantList?.addView(participantView) + if (quest?.active == true || participant.participatesInQuest != null && participant.participatesInQuest) { + participantCount += 1 + } + } + if (quest?.active == true) { + participantHeader?.setText(R.string.participants) + participantHeaderCount?.text = participantCount.toString() + } else { + participantHeader?.setText(R.string.invitations) + participantHeaderCount?.text = participantCount.toString() + "/" + quest?.participants?.size + beginQuestMessage = getString(R.string.quest_begin_message, participantCount, quest?.participants?.size) + } + } + + override fun onDestroyView() { + socialRepository.close() + userRepository.close() + inventoryRepository.close() + super.onDestroyView() + } + + fun onQuestAccept() { + partyId.notNull { + socialRepository.acceptQuest(user, it).subscribe(Consumer { }, RxErrorHandler.handleEmptyError()) + } + } + + + fun onQuestReject() { + partyId.notNull { + socialRepository.rejectQuest(user, it).subscribe(Consumer { }, RxErrorHandler.handleEmptyError()) + } + } + + fun onQuestBegin() { + val builder = AlertDialog.Builder(getActivity()) + .setMessage(beginQuestMessage) + .setPositiveButton(R.string.yes) { _, _ -> + party.notNull { + socialRepository.forceStartQuest(it) + .subscribe(Consumer { }, RxErrorHandler.handleEmptyError()) + } + } + .setNegativeButton(R.string.no) { _, _ -> } + builder.show() + } + + fun onQuestCancel() { + val builder = AlertDialog.Builder(getActivity()) + .setMessage(R.string.quest_cancel_message) + .setPositiveButton(R.string.yes) { _, _ -> + partyId.notNull { + socialRepository.cancelQuest(it) + .subscribe(Consumer { getActivity()?.fragmentManager?.popBackStack() }, RxErrorHandler.handleEmptyError()) + } + }.setNegativeButton(R.string.no) { _, _ -> } + builder.show() + } + + fun onQuestAbort() { + val builder = AlertDialog.Builder(getActivity()) + .setMessage(R.string.quest_abort_message) + .setPositiveButton(R.string.yes) { _, _ -> + partyId.notNull { + socialRepository.abortQuest(it) + .subscribe(Consumer { getActivity()?.fragmentManager?.popBackStack() }, RxErrorHandler.handleEmptyError()) + } + }.setNegativeButton(R.string.no) { _, _ -> } + builder.show() + } + + override fun injectFragment(component: AppComponent) { + component.inject(this) + } +} 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 deleted file mode 100644 index 769a898a9..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/party/PartyDetailFragment.java +++ /dev/null @@ -1,272 +0,0 @@ -package com.habitrpg.android.habitica.ui.fragments.social.party; - -import android.app.AlertDialog; -import android.os.Bundle; -import android.os.Handler; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -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.facebook.drawee.view.SimpleDraweeView; -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.data.SocialRepository; -import com.habitrpg.android.habitica.data.UserRepository; -import com.habitrpg.android.habitica.helpers.RxErrorHandler; -import com.habitrpg.android.habitica.models.inventory.Quest; -import com.habitrpg.android.habitica.models.inventory.QuestContent; -import com.habitrpg.android.habitica.models.social.Group; -import com.habitrpg.android.habitica.models.user.User; -import com.habitrpg.android.habitica.modules.AppModule; -import com.habitrpg.android.habitica.ui.activities.MainActivity; -import com.habitrpg.android.habitica.ui.fragments.BaseFragment; -import com.habitrpg.android.habitica.ui.fragments.inventory.items.ItemRecyclerFragment; -import com.habitrpg.android.habitica.ui.fragments.social.QuestDetailFragment; -import com.habitrpg.android.habitica.ui.helpers.DataBindingUtils; -import com.habitrpg.android.habitica.ui.helpers.MarkdownParser; -import com.habitrpg.android.habitica.ui.views.social.OldQuestProgressView; - -import javax.inject.Inject; -import javax.inject.Named; - -import butterknife.BindView; -import butterknife.OnClick; - - -public class PartyDetailFragment extends BaseFragment { - - @Inject - SocialRepository socialRepository; - @Inject - UserRepository userRepository; - @Inject - InventoryRepository inventoryRepository; - @Inject - @Named(AppModule.NAMED_USER_ID) - String userId; - - @BindView(R.id.refreshLayout) - SwipeRefreshLayout refreshLayout; - - @BindView(R.id.party_invitation_wrapper) - ViewGroup partyInvitationWrapper; - - @BindView(R.id.title_view) - TextView titleView; - @BindView(R.id.description_view) - TextView descriptionView; - - @BindView(R.id.new_quest_button) - Button newQuestButton; - @BindView(R.id.quest_detail_button) - ViewGroup questDetailButton; - @BindView(R.id.quest_scroll_image_view) - SimpleDraweeView questScrollImageView; - @BindView(R.id.quest_title_view) - TextView questTitleView; - @BindView(R.id.quest_participation_view) - TextView questParticipationView; - @BindView(R.id.quest_image_wrapper) - ViewGroup questImageWrapper; - @BindView(R.id.quest_image_view) - SimpleDraweeView questImageView; - @BindView(R.id.quest_participant_response_wrapper) - ViewGroup questParticipantResponseWrapper; - @BindView(R.id.quest_accept_button) - Button questAcceptButton; - @BindView(R.id.quest_reject_button) - Button questRejectButton; - @BindView(R.id.quest_progress_view) - OldQuestProgressView questProgressView; - @BindView(R.id.quest_participant_list) - LinearLayout questParticipantList; - - - public String partyId; - private Group party; - private Quest quest; - private User user; - - @Override - public void injectFragment(@NonNull AppComponent component) { - component.inject(this); - } - - @Nullable - @Override - public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - super.onCreateView(inflater, container, savedInstanceState); - return inflater.inflate(R.layout.fragment_party_detail, container, false); - } - - @Override - public void onDestroyView() { - socialRepository.close(); - userRepository.close(); - inventoryRepository.close(); - super.onDestroyView(); - } - - @Override - public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - - refreshLayout.setOnRefreshListener(this::refreshParty); - - getCompositeSubscription().add(socialRepository.getGroup(partyId).subscribe(this::updateParty, RxErrorHandler.handleEmptyError())); - getCompositeSubscription().add(userRepository.getUser(userId).subscribe(this::updateUser, RxErrorHandler.handleEmptyError())); - } - - private void refreshParty() { - socialRepository.retrieveGroup("party") - .flatMap(group1 -> socialRepository.retrieveGroupMembers(group1.getId(), true)) - .subscribe(members -> {}, RxErrorHandler.handleEmptyError(), () -> { - if (refreshLayout != null) { - refreshLayout.setRefreshing(false); - } - }); - } - - private void updateParty(Group party) { - if (party == null) { - return; - } - this.party = party; - this.quest = party.getQuest(); - if (titleView == null) { - return; - } - titleView.setText(party.getName()); - //TODO: FIX - //descriptionView.setText(MarkdownParser.parseMarkdown(party.getDescription())); - - if (quest != null && !quest.getKey().isEmpty()) { - newQuestButton.setVisibility(View.GONE); - questDetailButton.setVisibility(View.VISIBLE); - questImageWrapper.setVisibility(View.VISIBLE); - Handler mainHandler = new Handler(getContext().getMainLooper()); - mainHandler.postDelayed(() -> inventoryRepository.getQuestContent(quest.getKey()) - .firstElement() - .subscribe(PartyDetailFragment.this::updateQuestContent, RxErrorHandler.handleEmptyError()), 500); - } else { - newQuestButton.setVisibility(View.VISIBLE); - questDetailButton.setVisibility(View.GONE); - questImageWrapper.setVisibility(View.GONE); - questProgressView.setVisibility(View.GONE); - } - } - - private void updateUser(User user) { - if (user == null || user.getParty() == null || user.getParty().getQuest() == null) { - return; - } - this.user = user; - - int invitationVisibility = View.GONE; - if (user.getInvitations() != null && user.getInvitations().getParty() != null && user.getInvitations().getParty().getId() != null) { - invitationVisibility = View.VISIBLE; - } - - if (partyInvitationWrapper != null) { - partyInvitationWrapper.setVisibility(invitationVisibility); - } - - if (questParticipantResponseWrapper != null) { - if (showParticipantButtons()) { - questParticipantResponseWrapper.setVisibility(View.VISIBLE); - } else { - questParticipantResponseWrapper.setVisibility(View.GONE); - } - } - - questProgressView.configure(user); - } - - private boolean showParticipantButtons() { - return !(user == null || user.getParty() == null || user.getParty().getQuest() == null) && !isQuestActive() && user.getParty().getQuest().getRSVPNeeded(); - } - - private void updateQuestContent(QuestContent questContent) { - if (questTitleView == null || !questContent.isValid()) { - return; - } - questTitleView.setText(questContent.getText()); - DataBindingUtils.INSTANCE.loadImage(questScrollImageView, "inventory_quest_scroll_"+questContent.getKey()); - DataBindingUtils.INSTANCE.loadImage(questImageView, "quest_"+questContent.getKey()); - if (isQuestActive()) { - questProgressView.setVisibility(View.VISIBLE); - questProgressView.setData(questContent, quest.getProgress()); - - questParticipationView.setText(getString(R.string.number_participants, quest.getMembers().size())); - } else { - questProgressView.setVisibility(View.GONE); - } - } - - private boolean isQuestActive() { - return quest != null && quest.getActive(); - } - - @OnClick(R.id.new_quest_button) - public void inviteNewQuest() { - ItemRecyclerFragment fragment = new ItemRecyclerFragment(); - fragment.setItemType("quests"); - fragment.setItemTypeText(getString(R.string.quest)); - fragment.show(getFragmentManager(), "questDialog"); - } - - @OnClick(R.id.leave_button) - public void leaveParty() { - AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()) - .setMessage(R.string.leave_party_confirmation) - .setPositiveButton(R.string.yes, (dialog, which) -> socialRepository.leaveGroup(partyId) - .subscribe(aVoid -> {}, RxErrorHandler.handleEmptyError())).setNegativeButton(R.string.no, (dialog, which) -> {}); - builder.show(); } - - @OnClick(R.id.quest_accept_button) - public void onQuestAccept() { - socialRepository.acceptQuest(user, partyId).subscribe(aVoid -> {}, RxErrorHandler.handleEmptyError()); - } - - - @OnClick(R.id.quest_reject_button) - public void onQuestReject() { - socialRepository.rejectQuest(user, partyId).subscribe(aVoid -> {}, RxErrorHandler.handleEmptyError()); - } - - @OnClick(R.id.party_invite_accept_button) - public void onPartyInviteAccepted() { - if (user != null) { - socialRepository.joinGroup(user.getInvitations().getParty().getId()) - .subscribe(group -> {}, RxErrorHandler.handleEmptyError()); - } - } - - @OnClick(R.id.party_invite_reject_button) - public void onPartyInviteRejected() { - if (user != null) { - socialRepository.rejectGroupInvite(user.getInvitations().getParty().getId()) - .subscribe(aVoid -> {}, RxErrorHandler.handleEmptyError()); - } - } - - @OnClick(R.id.quest_detail_button) - public void questDetailButtonClicked() { - QuestDetailFragment fragment = new QuestDetailFragment(); - fragment.partyId = partyId; - if (party != null && party.getQuest() != null) { - fragment.questKey = party.getQuest().getKey(); - } - if (getActivity() != null) { - MainActivity activity = (MainActivity) getActivity(); - activity.displayFragment(fragment); - } - } -} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/party/PartyDetailFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/party/PartyDetailFragment.kt new file mode 100644 index 000000000..c2954eb77 --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/party/PartyDetailFragment.kt @@ -0,0 +1,247 @@ +package com.habitrpg.android.habitica.ui.fragments.social.party + +import android.app.AlertDialog +import android.os.Bundle +import android.os.Handler +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.facebook.drawee.view.SimpleDraweeView +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.data.SocialRepository +import com.habitrpg.android.habitica.data.UserRepository +import com.habitrpg.android.habitica.extensions.notNull +import com.habitrpg.android.habitica.helpers.RxErrorHandler +import com.habitrpg.android.habitica.models.inventory.Quest +import com.habitrpg.android.habitica.models.inventory.QuestContent +import com.habitrpg.android.habitica.models.social.Group +import com.habitrpg.android.habitica.models.user.User +import com.habitrpg.android.habitica.modules.AppModule +import com.habitrpg.android.habitica.ui.activities.MainActivity +import com.habitrpg.android.habitica.ui.fragments.BaseFragment +import com.habitrpg.android.habitica.ui.fragments.inventory.items.ItemRecyclerFragment +import com.habitrpg.android.habitica.ui.fragments.social.QuestDetailFragment +import com.habitrpg.android.habitica.ui.helpers.DataBindingUtils +import com.habitrpg.android.habitica.ui.helpers.MarkdownParser +import com.habitrpg.android.habitica.ui.helpers.bindView +import com.habitrpg.android.habitica.ui.views.social.OldQuestProgressView +import io.reactivex.functions.Consumer +import javax.inject.Inject +import javax.inject.Named + + +class PartyDetailFragment : BaseFragment() { + + @Inject + lateinit var socialRepository: SocialRepository + @Inject + lateinit var userRepository: UserRepository + @Inject + lateinit var inventoryRepository: InventoryRepository + @field:[Inject Named(AppModule.NAMED_USER_ID)] + lateinit var userId: String + + private val refreshLayout: SwipeRefreshLayout? by bindView(R.id.refreshLayout) + private val partyInvitationWrapper: ViewGroup? by bindView(R.id.party_invitation_wrapper) + private val titleView: TextView? by bindView(R.id.title_view) + private val descriptionView: TextView? by bindView(R.id.description_view) + private val newQuestButton: Button? by bindView(R.id.new_quest_button) + private val questDetailButton: ViewGroup? by bindView(R.id.quest_detail_button) + private val questScrollImageView: SimpleDraweeView? by bindView(R.id.quest_scroll_image_view) + private val questTitleView: TextView? by bindView(R.id.quest_title_view) + private val questParticipationView: TextView? by bindView(R.id.quest_participation_view) + private val questImageWrapper: ViewGroup? by bindView(R.id.quest_image_wrapper) + private val questImageView: SimpleDraweeView? by bindView(R.id.quest_image_view) + private val questParticipantResponseWrapper: ViewGroup? by bindView(R.id.quest_participant_response_wrapper) + private val questAcceptButton: Button? by bindView(R.id.quest_accept_button) + private val questRejectButton: Button? by bindView(R.id.quest_reject_button) + private val questProgressView: OldQuestProgressView? by bindView(R.id.quest_progress_view) + private val questParticipantList: LinearLayout? by bindView(R.id.quest_participant_list) + private val leaveButton: Button? by bindView(R.id.leave_button) + + + var partyId: String? = null + private var party: Group? = null + private var quest: Quest? = null + private var user: User? = null + + private val isQuestActive: Boolean + get() = quest?.active == true + + override fun injectFragment(component: AppComponent) { + component.inject(this) + } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + super.onCreateView(inflater, container, savedInstanceState) + return inflater.inflate(R.layout.fragment_party_detail, container, false) + } + + override fun onDestroyView() { + socialRepository.close() + userRepository.close() + inventoryRepository.close() + super.onDestroyView() + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + refreshLayout?.setOnRefreshListener { this.refreshParty() } + + compositeSubscription.add(socialRepository.getGroup(partyId).subscribe(Consumer { this.updateParty(it) }, RxErrorHandler.handleEmptyError())) + compositeSubscription.add(userRepository.getUser(userId).subscribe(Consumer { this.updateUser(it) }, RxErrorHandler.handleEmptyError())) + + questAcceptButton?.setOnClickListener { onQuestAccept() } + questRejectButton?.setOnClickListener { onQuestReject() } + newQuestButton?.setOnClickListener { inviteNewQuest() } + questDetailButton?.setOnClickListener { questDetailButtonClicked() } + leaveButton?.setOnClickListener { leaveParty() } + } + + private fun refreshParty() { + socialRepository.retrieveGroup("party") + .flatMap { group1 -> socialRepository.retrieveGroupMembers(group1.id, true) } + .doOnComplete { refreshLayout?.isRefreshing = false } + .subscribe(Consumer { }, RxErrorHandler.handleEmptyError()) + } + + private fun updateParty(party: Group?) { + if (party == null) { + return + } + this.party = party + this.quest = party.quest + if (titleView == null) { + return + } + titleView?.text = party.name + descriptionView?.text = MarkdownParser.parseMarkdown(party.description) + + if (quest?.key?.isEmpty() == false) { + newQuestButton?.visibility = View.GONE + questDetailButton?.visibility = View.VISIBLE + questImageWrapper?.visibility = View.VISIBLE + val mainHandler = Handler(context?.mainLooper) + mainHandler.postDelayed({ + inventoryRepository.getQuestContent(quest?.key) + .firstElement() + .subscribe(Consumer { this@PartyDetailFragment.updateQuestContent(it) }, RxErrorHandler.handleEmptyError()) + }, 500) + } else { + newQuestButton?.visibility = View.VISIBLE + questDetailButton?.visibility = View.GONE + questImageWrapper?.visibility = View.GONE + questProgressView?.visibility = View.GONE + } + } + + private fun updateUser(user: User?) { + if (user == null || user.party == null || user.party.quest == null) { + return + } + this.user = user + + var invitationVisibility = View.GONE + if (user.invitations != null && user.invitations.party != null && user.invitations.party.id != null) { + invitationVisibility = View.VISIBLE + } + + if (partyInvitationWrapper != null) { + partyInvitationWrapper?.visibility = invitationVisibility + } + + if (questParticipantResponseWrapper != null) { + if (showParticipantButtons()) { + questParticipantResponseWrapper?.visibility = View.VISIBLE + } else { + questParticipantResponseWrapper?.visibility = View.GONE + } + } + + questProgressView?.configure(user) + } + + private fun showParticipantButtons(): Boolean { + return !(user == null || user?.party == null || user?.party?.quest == null) && !isQuestActive && user?.party?.quest?.RSVPNeeded == true + } + + private fun updateQuestContent(questContent: QuestContent) { + if (questTitleView == null || !questContent.isValid) { + return + } + questTitleView?.text = questContent.text + DataBindingUtils.loadImage(questScrollImageView, "inventory_quest_scroll_" + questContent.key) + DataBindingUtils.loadImage(questImageView, "quest_" + questContent.key) + if (isQuestActive) { + questProgressView?.visibility = View.VISIBLE + questProgressView?.setData(questContent, quest?.progress) + + questParticipationView?.text = getString(R.string.number_participants, quest?.members?.size) + } else { + questProgressView?.visibility = View.GONE + } + } + + fun inviteNewQuest() { + val fragment = ItemRecyclerFragment() + fragment.itemType = "quests" + fragment.itemTypeText = getString(R.string.quest) + fragment.show(fragmentManager, "questDialog") + } + + fun leaveParty() { + val builder = AlertDialog.Builder(activity) + .setMessage(R.string.leave_party_confirmation) + .setPositiveButton(R.string.yes) { _, _ -> + socialRepository.leaveGroup(partyId) + .subscribe(Consumer { }, RxErrorHandler.handleEmptyError()) + }.setNegativeButton(R.string.no) { _, _ -> } + builder.show() + } + + fun onQuestAccept() { + partyId.notNull { + socialRepository.acceptQuest(user, it).subscribe(Consumer { }, RxErrorHandler.handleEmptyError()) + } + } + + + fun onQuestReject() { + partyId.notNull { + socialRepository.rejectQuest(user, it).subscribe(Consumer { }, RxErrorHandler.handleEmptyError()) + } + } + + fun onPartyInviteAccepted() { + user?.invitations?.party?.id.notNull { + socialRepository.joinGroup(it) + .subscribe(Consumer { }, RxErrorHandler.handleEmptyError()) + } + } + + fun onPartyInviteRejected() { + user?.invitations?.party?.id.notNull { + socialRepository.rejectGroupInvite(it) + .subscribe(Consumer { }, RxErrorHandler.handleEmptyError()) + } + } + + fun questDetailButtonClicked() { + val fragment = QuestDetailFragment() + fragment.partyId = partyId + if (party != null && party?.quest != null) { + fragment.questKey = party?.quest?.key + } + if (activity != null) { + val activity = activity as MainActivity? + activity?.displayFragment(fragment) + } + } +} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/party/PartyFragment.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/party/PartyFragment.java index 3e9d5492f..35983f1a6 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/party/PartyFragment.java +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/party/PartyFragment.java @@ -262,7 +262,7 @@ public class PartyFragment extends BaseMainFragment { case 0: { if (user.hasParty()) { PartyDetailFragment detailFragment = new PartyDetailFragment(); - detailFragment.partyId = user.getParty().id; + detailFragment.setPartyId(user.getParty().id); fragment = detailFragment; } else { fragment = GroupInformationFragment.Companion.newInstance(null, user); diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/party/PartyMemberListFragment.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/party/PartyMemberListFragment.java deleted file mode 100644 index 85ea0da6a..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/party/PartyMemberListFragment.java +++ /dev/null @@ -1,94 +0,0 @@ -package com.habitrpg.android.habitica.ui.fragments.social.party; - -import android.os.Bundle; -import android.support.annotation.Nullable; -import android.support.v4.widget.SwipeRefreshLayout; -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.SocialRepository; -import com.habitrpg.android.habitica.helpers.RxErrorHandler; -import com.habitrpg.android.habitica.ui.activities.FullProfileActivity; -import com.habitrpg.android.habitica.ui.adapter.social.PartyMemberRecyclerViewAdapter; -import com.habitrpg.android.habitica.ui.fragments.BaseFragment; -import com.habitrpg.android.habitica.ui.helpers.SafeDefaultItemAnimator; - -import javax.inject.Inject; - -import butterknife.BindView; - -/** - * Created by Negue on 15.09.2015. - */ -public class PartyMemberListFragment extends BaseFragment { - - @Inject - SocialRepository socialRepository; - - @BindView(R.id.recyclerView) - RecyclerView recyclerView; - @BindView(R.id.refreshLayout) - SwipeRefreshLayout refreshLayout; - private PartyMemberRecyclerViewAdapter adapter; - private View view; - private String partyId; - - @Nullable - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - super.onCreateView(inflater, container, savedInstanceState); - view = inflater.inflate(R.layout.fragment_refresh_recyclerview, container, false); - return view; - } - - @Override - public void injectFragment(AppComponent component) { - component.inject(this); - } - - @Override - public void onViewCreated(View view, Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - - recyclerView.setLayoutManager(new LinearLayoutManager(getContext())); - adapter = new PartyMemberRecyclerViewAdapter(null, true, getContext()); - getCompositeSubscription().add(adapter.getUserClickedEvents().subscribe(userId -> FullProfileActivity.open(getContext(), userId), RxErrorHandler.handleEmptyError())); - recyclerView.setAdapter(adapter); - recyclerView.setItemAnimator(new SafeDefaultItemAnimator()); - - refreshLayout.setOnRefreshListener(this::refreshMembers); - - getUsers(); - } - - private void refreshMembers() { - setRefreshing(true); - socialRepository.retrieveGroupMembers(partyId, true).subscribe(users -> {}, RxErrorHandler.handleEmptyError(), () -> setRefreshing(false)); - } - - private void setRefreshing(boolean isRefreshing) { - if (refreshLayout != null) { - refreshLayout.setRefreshing(isRefreshing); - } - } - - public void setPartyId(String id) { - this.partyId = id; - } - - private void getUsers() { - if (partyId == null) { - return; - } - socialRepository.getGroupMembers(partyId).firstElement().subscribe(users -> { - if (adapter != null) { - adapter.updateData(users); - } - }, RxErrorHandler.handleEmptyError()); - } -} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/party/PartyMemberListFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/party/PartyMemberListFragment.kt new file mode 100644 index 000000000..cca6d4d42 --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/party/PartyMemberListFragment.kt @@ -0,0 +1,81 @@ +package com.habitrpg.android.habitica.ui.fragments.social.party + +import android.os.Bundle +import android.support.v4.widget.SwipeRefreshLayout +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.SocialRepository +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.ui.activities.FullProfileActivity +import com.habitrpg.android.habitica.ui.adapter.social.PartyMemberRecyclerViewAdapter +import com.habitrpg.android.habitica.ui.fragments.BaseFragment +import com.habitrpg.android.habitica.ui.helpers.SafeDefaultItemAnimator +import com.habitrpg.android.habitica.ui.helpers.bindView +import io.reactivex.functions.Consumer +import javax.inject.Inject + +/** + * Created by Negue on 15.09.2015. + */ +class PartyMemberListFragment : BaseFragment() { + + @Inject + lateinit var socialRepository: SocialRepository + + private val recyclerView: RecyclerView? by bindView(R.id.recyclerView) + private val refreshLayout: SwipeRefreshLayout? by bindView(R.id.refreshLayout) + private var adapter: PartyMemberRecyclerViewAdapter? = null + private var partyId: String? = null + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + super.onCreateView(inflater, container, savedInstanceState) + return container?.inflate(R.layout.fragment_refresh_recyclerview) + } + + override fun injectFragment(component: AppComponent) { + component.inject(this) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + recyclerView?.layoutManager = LinearLayoutManager(context) + adapter = PartyMemberRecyclerViewAdapter(null, true) + adapter?.getUserClickedEvents()?.subscribe(Consumer { userId -> FullProfileActivity.open(context, userId) }, RxErrorHandler.handleEmptyError()).notNull { compositeSubscription.add(it) } + recyclerView?.adapter = adapter + recyclerView?.itemAnimator = SafeDefaultItemAnimator() + + refreshLayout?.setOnRefreshListener { this.refreshMembers() } + + getUsers() + } + + private fun refreshMembers() { + setRefreshing(true) + socialRepository.retrieveGroupMembers(partyId!!, true).doOnComplete { setRefreshing(false) }.subscribe(Consumer { users -> }, RxErrorHandler.handleEmptyError()) + } + + private fun setRefreshing(isRefreshing: Boolean) { + refreshLayout?.isRefreshing = isRefreshing + } + + fun setPartyId(id: String) { + this.partyId = id + } + + private fun getUsers() { + if (partyId == null) { + return + } + socialRepository.getGroupMembers(partyId!!).firstElement().subscribe(Consumer { users -> + adapter?.updateData(users) + }, RxErrorHandler.handleEmptyError()) + } +} 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 fa381fc87..eb52598a0 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 @@ -12,7 +12,6 @@ import android.widget.CheckBox import android.widget.CompoundButton import android.widget.LinearLayout import android.widget.TextView - import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.events.commands.ChecklistCheckedCommand import com.habitrpg.android.habitica.events.commands.TaskCheckedCommand @@ -20,18 +19,13 @@ import com.habitrpg.android.habitica.helpers.RxErrorHandler import com.habitrpg.android.habitica.models.tasks.ChecklistItem import com.habitrpg.android.habitica.models.tasks.Task import com.habitrpg.android.habitica.ui.helpers.MarkdownParser - -import net.pherth.android.emoji_library.EmojiTextView - -import org.greenrobot.eventbus.EventBus - -import butterknife.BindView -import butterknife.OnClick import com.habitrpg.android.habitica.ui.helpers.bindView import io.reactivex.Observable import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.functions.Consumer import io.reactivex.schedulers.Schedulers +import net.pherth.android.emoji_library.EmojiTextView +import org.greenrobot.eventbus.EventBus abstract class ChecklistedViewHolder(itemView: View) : BaseTaskViewHolder(itemView), CompoundButton.OnCheckedChangeListener { @@ -45,6 +39,7 @@ abstract class ChecklistedViewHolder(itemView: View) : BaseTaskViewHolder(itemVi init { checklistIndicatorWrapper.isClickable = true + checklistIndicatorWrapper.setOnClickListener { onChecklistIndicatorClicked() } checkbox.setOnCheckedChangeListener(this) expandCheckboxTouchArea(checkboxHolder, checkbox) } @@ -116,7 +111,6 @@ abstract class ChecklistedViewHolder(itemView: View) : BaseTaskViewHolder(itemVi } } - @OnClick(R.id.checklistIndicatorWrapper) fun onChecklistIndicatorClicked() { expandedChecklistRow = if (this.shouldDisplayExpandedChecklist()) null else adapterPosition if (this.shouldDisplayExpandedChecklist()) { 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 12ec04be4..ba6613efa 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 @@ -5,7 +5,6 @@ import android.widget.Button import android.widget.FrameLayout import android.widget.ImageView 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.ui.helpers.bindView @@ -31,6 +30,11 @@ class HabitViewHolder(itemView: View) : BaseTaskViewHolder(itemView) { return isVisible } + init { + btnPlus.setOnClickListener { onPlusButtonClicked() } + btnMinus.setOnClickListener { onMinusButtonClicked() } + } + override fun bindHolder(newTask: Task, position: Int) { this.task = newTask if (newTask.up == true) { @@ -82,7 +86,6 @@ class HabitViewHolder(itemView: View) : BaseTaskViewHolder(itemView) { super.bindHolder(newTask, position) } - @OnClick(R.id.btnPlus) fun onPlusButtonClicked() { val event = HabitScoreEvent() event.Up = true @@ -90,7 +93,6 @@ class HabitViewHolder(itemView: View) : BaseTaskViewHolder(itemView) { EventBus.getDefault().post(event) } - @OnClick(R.id.btnMinus) fun onMinusButtonClicked() { val event = HabitScoreEvent() event.Up = false 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 7a98159df..3c4f7381f 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 @@ -4,14 +4,13 @@ import android.support.v4.content.ContextCompat import android.view.View import android.widget.ImageView import android.widget.TextView -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.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 +import com.habitrpg.android.habitica.ui.helpers.bindView import com.habitrpg.android.habitica.ui.views.HabiticaIconsHelper import org.greenrobot.eventbus.EventBus 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 index 494d31eaa..c13a7a23a 100644 --- 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 @@ -10,12 +10,11 @@ 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 +import com.habitrpg.android.habitica.ui.helpers.bindView class SubscriptionDetailsView : LinearLayout { @@ -41,6 +40,8 @@ class SubscriptionDetailsView : LinearLayout { private fun setupView() { inflate(R.layout.subscription_details) + + visitWebsiteButton.setOnClickListener { openSubscriptionWebsite() } } fun setPlan(plan: SubscriptionPlan) { @@ -93,7 +94,6 @@ class SubscriptionDetailsView : LinearLayout { } } - @OnClick(R.id.visitWebsiteButton) fun openSubscriptionWebsite() { if (plan?.paymentMethod != null) { val intent: Intent = if (plan?.paymentMethod == "Google") {