Skip to content

Commit

Permalink
Add password history feature (#189)
Browse files Browse the repository at this point in the history
  • Loading branch information
behzodhalil authored Jan 10, 2024
2 parents 791610c + a99e844 commit a0a48ce
Show file tree
Hide file tree
Showing 84 changed files with 1,813 additions and 117 deletions.
34 changes: 20 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,16 @@
</a>
<a href="">
<img src="https://img.shields.io/badge/iOS-14.0%2B-green">
</a>
</a>
<a href="">
<img src="https://img.shields.io/badge/Swift-5-F16D39.svg?style=flat">
</a>
</a>
<a href="">
<img src="http://img.shields.io/badge/platform-android-6EDB8D.svg?style=flat">
</a>
</a>
</a>
<a href="">
<img src="http://img.shields.io/badge/platform-ios-EAEAEA.svg?style=flat">
</a>
</a>
</p>

# AnyPass (Work In Progress ⛏)
Expand All @@ -39,6 +38,13 @@ This pattern brings multiple benefits:
- It makes changes to the data more traceable. Thus, bugs are easier to spot.

In an offline-first application, the source of truth for application data is typically a database. In some other cases, the source of truth can be a ViewModel or even the UI.

## Screenshots

<p style="text-align: center;">
<img src="media/home.png" width="250" alt="Home Screen"/>
</p>

# Technology

- [Kotlin](https://kotlinlang.org)
Expand Down Expand Up @@ -131,7 +137,7 @@ graph TD;
features-->auth;
features-->account;
features-->generatepassword;
onboarding-->shared;
auth-->shared;
home-->shared;
Expand All @@ -142,7 +148,7 @@ graph TD;

# Setup

1. Check your **Xcode** version is 14.1 or newer. Additionally, check your **Android Studio** version is Flamingo or newer.
1. Check your **Xcode** version is 14.1 or newer. Additionally, check your **Android Studio** version is Flamingo or newer.

2. Clone the repository using the following command:

Expand All @@ -154,15 +160,15 @@ graph TD;

- **Issue**: ```Unicode Normalization not appropriate for ASCII-8BIT```
- **Solution**: Try add your `~/.zprofile`, `~/.zshrc` files:

```
LANG=en_US.UTF-8
LANGUAGE=en_US.UFT-8
LC_ALL=en_US.UFT-8
```
- **Issue**: Sometimes you can not build your iOS app from Xcode
- **Issue**: Sometimes you can not build your iOS app from Xcode
- **Solution**: Follow these steps after executing the cleanup script:

1. `pod deintegrate`
2. `pod init`
3. Copy the `pod` modules
Expand All @@ -173,15 +179,15 @@ graph TD;
> :warning: Make fake `google-services`.json for building properly.
5. We recommend including linkers from Xcode. To include linkers from Xcode, follow these steps:

1. Navigate to **iosApp/Build Settings/Linking**.
2. Add the following linkers to your **Other Linking Flags**:
- `lsqlite3`
- `ObjC`

## Screenshots

## Contributers
## Contributers

**Want to contribute?** See **[CONTRIBUTING.md](/CONTRIBUTING.md)** [![Fork AnyPass](https://img.shields.io/github/forks/getspherelabs/anypass-kmp?logo=github&style=social)](https://github.com/getspherelabs/anypass-kmp/fork)

Expand All @@ -196,7 +202,7 @@ graph TD;
</a>
<br>
<a href="https://github.com/behzodhalil">Behzod Halil</a>
</td>
</td>
<td align="center">
<a href="https://github.com/oybekjon94">
<img src="https://avatars.githubusercontent.com/u/91370134?v=4" width="100" alt="John Doe">
Expand Down
Empty file added androidApp/google-services.json
Empty file.
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,7 @@ internal fun Project.configureCommonMultiplatform(
val commonMain by getting {
dependencies {
api(findLibrary(name = "coroutine"))
api(findLibrary(name = "datetime"))
}
}
val commonTest by getting {
Expand Down
10 changes: 0 additions & 10 deletions cleanup.sh

This file was deleted.

2 changes: 2 additions & 0 deletions core/admob/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ kotlin {
implementation(compose.material)
implementation(compose.materialIconsExtended)
implementation(compose.ui)

implementation(projects.core.system.ui)
}
}
val commonTest by getting {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,45 +1,91 @@
package io.spherelabs.admob

import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import com.google.android.gms.ads.AdSize
import com.google.android.gms.ads.AdView as AndroidBannerView
import android.annotation.SuppressLint
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.runtime.*
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
import com.google.android.gms.ads.AdListener
import com.google.android.gms.ads.AdRequest
import com.google.android.gms.ads.LoadAdError
import io.spherelabs.system.ui.shimmer.shimmer


@SuppressLint("MissingPermission")
@Composable
actual fun GADBannerView(
adId: String,
modifier: Modifier,
onAdLoaded: (loaded: Boolean) -> Unit,
) {
val context = LocalContext.current
val bannerView: AndroidBannerView = remember { AndroidBannerView(context) }
var adLoaded by remember { mutableStateOf(false) }

DisposableEffect(adId) {
onDispose {
bannerView.destroy()
}
}

val bannerListener = rememberBannerAdListener(
onAdFailedToLoad = {},
onAdLoaded = { adLoaded = true },
)

val currentAdSize = remember {
AdSize.BANNER
}

val adRequest = AdRequest.Builder().build()

val bannerView = remember {
AndroidBannerView(context).apply {
setAdSize(currentAdSize)
adUnitId = adId
Box(modifier = modifier.height(currentAdSize.height.dp).padding(horizontal = 24.dp)) {
if (!adLoaded) {
Box(
Modifier
.fillMaxWidth().fillMaxHeight().shimmer()
.background(color = Color.White.copy(0.5f)),
)
}

AndroidView(
factory = {
bannerView.apply {
setAdSize(currentAdSize)
adUnitId = adId
adListener = bannerListener
}
},
modifier = modifier.fillMaxSize(),
update = { currentBannerView ->
currentBannerView.loadAd(adRequest)
},
)
}


AndroidView(
factory = {
bannerView
},
modifier = modifier.fillMaxWidth(),
update = { currentBannerView ->
currentBannerView.loadAd(adRequest)
},
)
}


@Composable
private fun rememberBannerAdListener(
onAdFailedToLoad: (LoadAdError) -> Unit,
onAdLoaded: () -> Unit,
) = remember {
object : AdListener() {
override fun onAdFailedToLoad(error: LoadAdError) {
onAdFailedToLoad(error)
}

override fun onAdLoaded() {
super.onAdLoaded()
onAdLoaded()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ import androidx.compose.ui.Modifier
@Composable
expect fun GADBannerView(
adId: String,
modifier: Modifier = Modifier
modifier: Modifier = Modifier,
onAdLoaded: (loaded: Boolean) -> Unit
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package io.spherelabs.admob.di

data class LoadGADError(
val code: Int,
val message: String,
)
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,24 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.interop.LocalUIViewController
import androidx.compose.ui.interop.UIKitView
import cocoapods.GoogleMobileAds.GADAdSize
import cocoapods.GoogleMobileAds.GADBannerView as IosBannerView
import cocoapods.GoogleMobileAds.GADCurrentOrientationInlineAdaptiveBannerAdSizeWithWidth
import cocoapods.GoogleMobileAds.GADAdSizeBanner
import cocoapods.GoogleMobileAds.GADRequest
import kotlinx.cinterop.ExperimentalForeignApi
import kotlinx.cinterop.cValue
import platform.UIKit.NSLayoutConstraint
import platform.UIKit.UIView

@OptIn(ExperimentalForeignApi::class)
@Composable
actual fun GADBannerView(
adId: String,
modifier: Modifier,
onAdLoaded: (loaded: Boolean) -> Unit
) {
val uiViewController = LocalUIViewController.current

val bannerSize = remember {
cValue<GADAdSize> {
GADAdSize.size
}
GADAdSizeBanner
}

val bannerView = remember {
Expand All @@ -42,11 +40,11 @@ actual fun GADBannerView(
val iosView = UIView().apply {
bannerView.translatesAutoresizingMaskIntoConstraints = false
addSubview(bannerView)
NSLayoutConstraint.activate(listOf(
label.topAnchor.constraintEqualToAnchor(topAnchor),
label.bottomAnchor.constraintEqualToAnchor(bottomAnchor),
label.leadingAnchor.constraintEqualToAnchor(leadingAnchor),
label.trailingAnchor.constraintEqualToAnchor(trailingAnchor)
NSLayoutConstraint.activateConstraints(listOf(
bannerView.topAnchor.constraintEqualToAnchor(topAnchor),
bannerView.bottomAnchor.constraintEqualToAnchor(bottomAnchor),
bannerView.leadingAnchor.constraintEqualToAnchor(leadingAnchor),
bannerView.trailingAnchor.constraintEqualToAnchor(trailingAnchor)
))
}
iosView
Expand Down
1 change: 1 addition & 0 deletions core/common/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@

@file:Suppress("DSL_SCOPE_VIOLATION")

plugins { alias(libs.plugins.anypass.common) }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package io.spherelabs.common

import kotlinx.datetime.Instant
import kotlinx.datetime.TimeZone
import kotlinx.datetime.toLocalDateTime

val Instant.timestamp: String
get() {
val timezone = TimeZone.currentSystemDefault()
val datetime = this.toLocalDateTime(timezone)
val year = datetime.year
val month = datetime.monthNumber
val dayOfMonth = datetime.dayOfMonth

val hour = datetime.hour
val minutes = datetime.minute
val seconds = datetime.second

return "$year/$month/$dayOfMonth $hour:$minutes:$seconds"
}

val Instant.month: Int
get() {
val timezone = TimeZone.currentSystemDefault()
val datetime = this.toLocalDateTime(timezone)
return datetime.monthNumber
}

fun Long.getMonth(): Int {
return Instant.fromEpochMilliseconds(this).month
}

fun Long.formatLongTime(): String {
return Instant.fromEpochMilliseconds(this).timestamp
}

16 changes: 16 additions & 0 deletions core/common/src/commonTest/kotlin/LocalDateTimeExtensionTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import assertk.assertThat
import assertk.assertions.isEqualTo
import io.spherelabs.common.formatLongTime
import kotlin.test.Test

class LocalDateTimeExtensionTest {
@Test
fun `GIVEN the current time WHEN format to string THEN checks the right timestamp`() {
// val now = 1704760525488
//
// val instant = now.formatLongTime()
// val currentTimestamp = "2024/1/9 9:35:25"
//
// assertThat(instant).isEqualTo(currentTimestamp)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -77,14 +77,6 @@ fun LKPasswordCard(
modifier = modifier.fillMaxWidth().padding(horizontal = 24.dp),
) { password() }

// Text(
// modifier = modifier.fillMaxWidth().padding(horizontal = 24.dp),
// text = password,
// fontFamily = passwordCardStyle.passwordFontFamily().value,
// fontWeight = FontWeight.Medium,
// fontSize = passwordCardStyle.passwordFontSize().value,
// color = passwordCardColor.passwordColor().value,
// )
Spacer(modifier.weight(1f))
Row(modifier = modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceAround) {
Box(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package io.spherelabs.system.ui.shimmer

import android.content.res.Resources
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.geometry.Rect

/**
* Copied from https://github.com/valentinilk/compose-shimmer/tree/master
*/

@Composable
internal actual fun rememberWindowBounds(): Rect = remember {
val metrics = Resources.getSystem().displayMetrics

Rect(0f, 0f, metrics.widthPixels.toFloat(), metrics.heightPixels.toFloat())
}
Loading

0 comments on commit a0a48ce

Please sign in to comment.