mirror of
https://github.com/pezkuwichain/pezkuwi-wallet-android.git
synced 2026-04-22 02:07:58 +00:00
Initial commit: Pezkuwi Wallet Android
Security hardened release: - Code obfuscation enabled (minifyEnabled=true, shrinkResources=true) - Sensitive files excluded (google-services.json, keystores) - Branch.io key moved to BuildConfig placeholder - Updated dependencies: OkHttp 4.12.0, Gson 2.10.1, BouncyCastle 1.77 - Comprehensive ProGuard rules for crypto wallet - Navigation 2.7.7, Lifecycle 2.7.0, ConstraintLayout 2.1.4
This commit is contained in:
@@ -0,0 +1 @@
|
||||
/build
|
||||
@@ -0,0 +1,50 @@
|
||||
apply plugin: 'kotlin-parcelize'
|
||||
apply from: '../tests.gradle'
|
||||
apply from: '../scripts/secrets.gradle'
|
||||
|
||||
android {
|
||||
namespace 'io.novafoundation.nova.feature_vote'
|
||||
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
|
||||
buildFeatures {
|
||||
viewBinding true
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation project(':common')
|
||||
implementation project(':feature-account-api')
|
||||
|
||||
implementation kotlinDep
|
||||
|
||||
|
||||
implementation androidDep
|
||||
implementation materialDep
|
||||
implementation constraintDep
|
||||
|
||||
implementation coroutinesDep
|
||||
implementation coroutinesAndroidDep
|
||||
implementation viewModelKtxDep
|
||||
implementation lifeCycleKtxDep
|
||||
|
||||
implementation daggerDep
|
||||
ksp daggerCompiler
|
||||
|
||||
testImplementation jUnitDep
|
||||
testImplementation mockitoDep
|
||||
|
||||
implementation insetterDep
|
||||
|
||||
implementation shimmerDep
|
||||
|
||||
androidTestImplementation androidTestRunnerDep
|
||||
androidTestImplementation androidTestRulesDep
|
||||
androidTestImplementation androidJunitDep
|
||||
}
|
||||
Vendored
+21
@@ -0,0 +1,21 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
</manifest>
|
||||
@@ -0,0 +1,3 @@
|
||||
package io.novafoundation.nova.feature_vote.di
|
||||
|
||||
interface VoteFeatureApi
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
package io.novafoundation.nova.feature_vote.di
|
||||
|
||||
import dagger.BindsInstance
|
||||
import dagger.Component
|
||||
import io.novafoundation.nova.common.di.CommonApi
|
||||
import io.novafoundation.nova.common.di.scope.FeatureScope
|
||||
import io.novafoundation.nova.feature_account_api.di.AccountFeatureApi
|
||||
import io.novafoundation.nova.feature_vote.presentation.VoteRouter
|
||||
import io.novafoundation.nova.feature_vote.presentation.vote.di.VoteComponent
|
||||
|
||||
@Component(
|
||||
dependencies = [
|
||||
VoteFeatureDependencies::class
|
||||
],
|
||||
modules = [
|
||||
VoteFeatureModule::class,
|
||||
]
|
||||
)
|
||||
@FeatureScope
|
||||
interface VoteFeatureComponent : VoteFeatureApi {
|
||||
|
||||
@Component.Factory
|
||||
interface Factory {
|
||||
|
||||
fun create(
|
||||
@BindsInstance voteRouter: VoteRouter,
|
||||
deps: VoteFeatureDependencies
|
||||
): VoteFeatureComponent
|
||||
}
|
||||
|
||||
fun voteComponentFactory(): VoteComponent.Factory
|
||||
|
||||
@Component(
|
||||
dependencies = [
|
||||
CommonApi::class,
|
||||
AccountFeatureApi::class
|
||||
]
|
||||
)
|
||||
interface VoteFeatureDependenciesComponent : VoteFeatureDependencies
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
package io.novafoundation.nova.feature_vote.di
|
||||
|
||||
import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase
|
||||
|
||||
interface VoteFeatureDependencies {
|
||||
|
||||
val selectedAccountUseCase: SelectedAccountUseCase
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package io.novafoundation.nova.feature_vote.di
|
||||
|
||||
import io.novafoundation.nova.common.di.FeatureApiHolder
|
||||
import io.novafoundation.nova.common.di.FeatureContainer
|
||||
import io.novafoundation.nova.common.di.scope.ApplicationScope
|
||||
import io.novafoundation.nova.feature_account_api.di.AccountFeatureApi
|
||||
import io.novafoundation.nova.feature_vote.presentation.VoteRouter
|
||||
import javax.inject.Inject
|
||||
|
||||
@ApplicationScope
|
||||
class VoteFeatureHolder @Inject constructor(
|
||||
featureContainer: FeatureContainer,
|
||||
private val router: VoteRouter
|
||||
) : FeatureApiHolder(featureContainer) {
|
||||
|
||||
override fun initializeDependencies(): Any {
|
||||
val dependencies = DaggerVoteFeatureComponent_VoteFeatureDependenciesComponent.builder()
|
||||
.commonApi(commonApi())
|
||||
.accountFeatureApi(getFeature(AccountFeatureApi::class.java))
|
||||
.build()
|
||||
return DaggerVoteFeatureComponent.factory()
|
||||
.create(router, dependencies)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package io.novafoundation.nova.feature_vote.di
|
||||
|
||||
import dagger.Module
|
||||
|
||||
@Module
|
||||
class VoteFeatureModule
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
package io.novafoundation.nova.feature_vote.presentation
|
||||
|
||||
import androidx.fragment.app.Fragment
|
||||
|
||||
interface VoteRouter {
|
||||
|
||||
fun getDemocracyFragment(): Fragment
|
||||
|
||||
fun getCrowdloansFragment(): Fragment
|
||||
|
||||
fun openSwitchWallet()
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
package io.novafoundation.nova.feature_vote.presentation.vote
|
||||
|
||||
import android.view.View
|
||||
import io.novafoundation.nova.common.base.BaseFragment
|
||||
import io.novafoundation.nova.common.di.FeatureUtils
|
||||
import io.novafoundation.nova.common.utils.insets.applyStatusBarInsets
|
||||
import io.novafoundation.nova.common.utils.setupWithViewPager2
|
||||
import io.novafoundation.nova.feature_vote.databinding.FragmentVoteBinding
|
||||
import io.novafoundation.nova.feature_vote.di.VoteFeatureApi
|
||||
import io.novafoundation.nova.feature_vote.di.VoteFeatureComponent
|
||||
import io.novafoundation.nova.feature_vote.presentation.VoteRouter
|
||||
|
||||
import javax.inject.Inject
|
||||
|
||||
class VoteFragment : BaseFragment<VoteViewModel, FragmentVoteBinding>() {
|
||||
|
||||
override fun createBinding() = FragmentVoteBinding.inflate(layoutInflater)
|
||||
|
||||
@Inject
|
||||
lateinit var router: VoteRouter
|
||||
|
||||
override fun applyInsets(rootView: View) {
|
||||
binder.voteContainer.applyStatusBarInsets()
|
||||
}
|
||||
|
||||
override fun initViews() {
|
||||
val adapter = VotePagerAdapter(this, router)
|
||||
binder.voteViewPager.adapter = adapter
|
||||
binder.voteTabs.setupWithViewPager2(binder.voteViewPager, adapter::getPageTitle)
|
||||
|
||||
binder.voteAvatar.setOnClickListener { viewModel.avatarClicked() }
|
||||
}
|
||||
|
||||
override fun inject() {
|
||||
FeatureUtils.getFeature<VoteFeatureComponent>(this, VoteFeatureApi::class.java)
|
||||
.voteComponentFactory()
|
||||
.create(this)
|
||||
.inject(this)
|
||||
}
|
||||
|
||||
override fun subscribe(viewModel: VoteViewModel) {
|
||||
viewModel.selectedWalletModel.observe(binder.voteAvatar::setModel)
|
||||
}
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
package io.novafoundation.nova.feature_vote.presentation.vote
|
||||
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.viewpager2.adapter.FragmentStateAdapter
|
||||
import io.novafoundation.nova.feature_vote.R
|
||||
import io.novafoundation.nova.feature_vote.presentation.VoteRouter
|
||||
|
||||
class VotePagerAdapter(private val fragment: Fragment, private val router: VoteRouter) : FragmentStateAdapter(fragment) {
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return 2
|
||||
}
|
||||
|
||||
override fun createFragment(position: Int): Fragment {
|
||||
return when (position) {
|
||||
0 -> router.getDemocracyFragment()
|
||||
1 -> router.getCrowdloansFragment()
|
||||
else -> throw IllegalArgumentException("Invalid position")
|
||||
}
|
||||
}
|
||||
|
||||
fun getPageTitle(position: Int): CharSequence {
|
||||
return when (position) {
|
||||
0 -> fragment.getString(R.string.common_governance)
|
||||
1 -> fragment.getString(R.string.crowdloan_crowdloan)
|
||||
else -> throw IllegalArgumentException("Invalid position")
|
||||
}
|
||||
}
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package io.novafoundation.nova.feature_vote.presentation.vote
|
||||
|
||||
import io.novafoundation.nova.common.base.BaseViewModel
|
||||
import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase
|
||||
import io.novafoundation.nova.feature_vote.presentation.VoteRouter
|
||||
|
||||
class VoteViewModel(
|
||||
private val router: VoteRouter,
|
||||
private val selectedAccountUseCase: SelectedAccountUseCase,
|
||||
) : BaseViewModel() {
|
||||
|
||||
val selectedWalletModel = selectedAccountUseCase.selectedWalletModelFlow()
|
||||
.shareInBackground()
|
||||
|
||||
fun avatarClicked() {
|
||||
router.openSwitchWallet()
|
||||
}
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package io.novafoundation.nova.feature_vote.presentation.vote.di
|
||||
|
||||
import androidx.fragment.app.Fragment
|
||||
import dagger.BindsInstance
|
||||
import dagger.Subcomponent
|
||||
import io.novafoundation.nova.common.di.scope.ScreenScope
|
||||
import io.novafoundation.nova.feature_vote.presentation.vote.VoteFragment
|
||||
|
||||
@Subcomponent(
|
||||
modules = [
|
||||
VoteModule::class
|
||||
]
|
||||
)
|
||||
@ScreenScope
|
||||
interface VoteComponent {
|
||||
|
||||
@Subcomponent.Factory
|
||||
interface Factory {
|
||||
|
||||
fun create(
|
||||
@BindsInstance fragment: Fragment
|
||||
): VoteComponent
|
||||
}
|
||||
|
||||
fun inject(fragment: VoteFragment)
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
package io.novafoundation.nova.feature_vote.presentation.vote.di
|
||||
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.multibindings.IntoMap
|
||||
import io.novafoundation.nova.common.di.viewmodel.ViewModelKey
|
||||
import io.novafoundation.nova.common.di.viewmodel.ViewModelModule
|
||||
import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase
|
||||
import io.novafoundation.nova.feature_vote.presentation.VoteRouter
|
||||
import io.novafoundation.nova.feature_vote.presentation.vote.VoteViewModel
|
||||
|
||||
@Module(includes = [ViewModelModule::class])
|
||||
class VoteModule {
|
||||
|
||||
@Provides
|
||||
internal fun provideViewModel(fragment: Fragment, factory: ViewModelProvider.Factory): VoteViewModel {
|
||||
return ViewModelProvider(fragment, factory).get(VoteViewModel::class.java)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@IntoMap
|
||||
@ViewModelKey(VoteViewModel::class)
|
||||
fun provideViewModel(
|
||||
voteRouter: VoteRouter,
|
||||
selectedAccountUseCase: SelectedAccountUseCase
|
||||
): ViewModel {
|
||||
return VoteViewModel(
|
||||
router = voteRouter,
|
||||
selectedAccountUseCase = selectedAccountUseCase
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/voteContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@drawable/drawable_background_image"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/voteTitle"
|
||||
style="@style/TextAppearance.NovaFoundation.Header1"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="17dp"
|
||||
android:layout_marginTop="25dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/vote_vote"
|
||||
android:textColor="@color/text_primary" />
|
||||
|
||||
<io.novafoundation.nova.feature_account_api.view.SelectedWalletView
|
||||
android:id="@+id/voteAvatar"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="25dp"
|
||||
android:layout_marginEnd="16dp" />
|
||||
</LinearLayout>
|
||||
|
||||
<io.novafoundation.nova.common.view.SegmentedTabLayout
|
||||
android:id="@+id/voteTabs"
|
||||
style="@style/SegmentedTab"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="40dp"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginBottom="8dp" />
|
||||
|
||||
<androidx.viewpager2.widget.ViewPager2
|
||||
android:id="@+id/voteViewPager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,17 @@
|
||||
package io.novafoundation.nova.feature_vote
|
||||
|
||||
import org.junit.Test
|
||||
|
||||
import org.junit.Assert.*
|
||||
|
||||
/**
|
||||
* Example local unit test, which will execute on the development machine (host).
|
||||
*
|
||||
* See [testing documentation](http://d.android.com/tools/testing).
|
||||
*/
|
||||
class ExampleUnitTest {
|
||||
@Test
|
||||
fun addition_isCorrect() {
|
||||
assertEquals(4, 2 + 2)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user