Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improvements for Compose App #198

Merged
merged 27 commits into from
Aug 6, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
27893c3
Add dependency: accompanist swipe refresh
PatilShreyas Aug 2, 2021
8f64558
Handle swipe refresh and UI mode in Notes screen
PatilShreyas Aug 2, 2021
5356d05
Cleanup code
PatilShreyas Aug 2, 2021
db109f1
Bump dagger version to 2.38.1
PatilShreyas Aug 4, 2021
54a7c23
Bump compose version to 1.0.1 and kotlin to 1.5.21
PatilShreyas Aug 5, 2021
fcfae18
Remove preview from main activity
PatilShreyas Aug 5, 2021
a9fb4ab
Add common text field component
PatilShreyas Aug 5, 2021
c1be766
Add sealed class for value validation
PatilShreyas Aug 5, 2021
0372838
Add text field components for username and password
PatilShreyas Aug 5, 2021
6f95163
Reuse component in login and signup screen
PatilShreyas Aug 5, 2021
e04377e
Reformat with ktlint
PatilShreyas Aug 5, 2021
e2c1bbe
Refactor: rename colors
PatilShreyas Aug 6, 2021
d64292a
Add basic variant of Text field
PatilShreyas Aug 6, 2021
33c3864
Add common note text fields
PatilShreyas Aug 6, 2021
a75e986
Use common note fields in note details screen
PatilShreyas Aug 6, 2021
2f0cd0f
Use common note fields in add note screen
PatilShreyas Aug 6, 2021
6ccfd20
Add annotation @ExperimentalAnimationApi across usage
PatilShreyas Aug 6, 2021
85336b4
Avoid syncing multiple time after every re-composition
PatilShreyas Aug 6, 2021
8232f41
Add details of Accompanist in docs
PatilShreyas Aug 6, 2021
1481425
Bump datastore version to 1.0.0
PatilShreyas Aug 6, 2021
04c89d9
Keep file name and key token private in session manager
PatilShreyas Aug 6, 2021
424c467
Annotate utility classes with ExperimentalAnimationApi usage
PatilShreyas Aug 6, 2021
f89cd70
Use viewmodel for changing UI mode
PatilShreyas Aug 6, 2021
30cef59
Add docs for NotyTaskManager.kt
PatilShreyas Aug 6, 2021
e96cc24
Add docs for PreferenceManager.kt
PatilShreyas Aug 6, 2021
7ce1cb3
Rename ViewState -> UIDataState
PatilShreyas Aug 6, 2021
deb3c79
Reformat source with Ktlint
PatilShreyas Aug 6, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/pages/noty-android/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,4 +86,6 @@ For single source of data. Implements `local` and `remote` modules.

- [Jetpack Compose UI Toolkit](https://developer.android.com/jetpack/compose) - Modern UI development toolkit.

- [Accompanist](https://google.github.io/accompanist/) - Accompanist is a group of libraries that aim to supplement Jetpack Compose with features that are commonly required by developers but not yet available.

- [LeakCanary](https://square.github.io/leakcanary/) - Memory leak detection library for Android
1 change: 1 addition & 0 deletions noty-android/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ Design of this awesome application is implemented by [Sanju S](https://github.co
- [Moshi Converter](https://github.com/square/retrofit/tree/master/retrofit-converters/moshi) - A Converter which uses Moshi for serialization to and from JSON.
- [Material Components for Android](https://github.com/material-components/material-components-android) - Modular and customizable Material Design UI components for Android.
- [Jetpack Compose UI Toolkit](https://developer.android.com/jetpack/compose) - Modern UI development toolkit.
- [Accompanist](https://google.github.io/accompanist/) - Accompanist is a group of libraries that aim to supplement Jetpack Compose with features that are commonly required by developers but not yet available.
- [LeakCanary](https://square.github.io/leakcanary/) - Memory leak detection library for Android

## Modules
Expand Down
3 changes: 3 additions & 0 deletions noty-android/app/composeapp/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,9 @@ dependencies {
// Compose Lifecycle
implementation "androidx.compose.runtime:runtime-livedata:$composeVersion"

// Accompanist
implementation "com.google.accompanist:accompanist-swiperefresh:$accompanistVersion"

// Navigation
implementation "androidx.navigation:navigation-compose:$composeNavVersion"

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
* Copyright 2020 Shreyas Patil
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package dev.shreyaspatil.noty.composeapp.component.text

import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.text.BasicTextField
import androidx.compose.material.MaterialTheme
import androidx.compose.material.OutlinedTextField
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.unit.TextUnit
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import dev.shreyaspatil.noty.composeapp.ui.theme.getTextFieldHintColor

@Composable
fun NotyTextField(
value: String,
label: String,
onValueChange: (String) -> Unit,
modifier: Modifier = Modifier,
fontSize: TextUnit = 16.sp,
color: Color = MaterialTheme.colors.onPrimary,
leadingIcon: @Composable() (() -> Unit)? = null,
isError: Boolean = false,
visualTransformation: VisualTransformation = VisualTransformation.None
) {
OutlinedTextField(
value = value,
label = { Text(text = label) },
modifier = modifier,
onValueChange = onValueChange,
leadingIcon = leadingIcon,
textStyle = TextStyle(color, fontSize = fontSize),
isError = isError,
visualTransformation = visualTransformation
)
}

@ExperimentalAnimationApi
@Composable
fun BasicNotyTextField(
modifier: Modifier = Modifier,
value: String = "",
label: String = "",
textStyle: TextStyle = TextStyle(fontSize = 16.sp, fontWeight = FontWeight.Normal),
onTextChange: (String) -> Unit,
maxLines: Int = Int.MAX_VALUE
) {

Box(modifier = modifier.padding(4.dp)) {
AnimatedVisibility(visible = value.isBlank()) {
Text(
text = label,
color = getTextFieldHintColor(),
fontSize = textStyle.fontSize,
fontWeight = textStyle.fontWeight
)
}
BasicTextField(
value = value,
onValueChange = onTextChange,
textStyle = textStyle.copy(color = MaterialTheme.colors.onPrimary),
maxLines = maxLines,
cursorBrush = SolidColor(MaterialTheme.colors.primary)
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* Copyright 2020 Shreyas Patil
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package dev.shreyaspatil.noty.composeapp.component.text

import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.material.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.sp

@ExperimentalAnimationApi
@Composable
fun NoteTitleField(
modifier: Modifier = Modifier,
value: String = "",
onTextChange: (String) -> Unit
) {
BasicNotyTextField(
modifier,
value = value,
label = "Title",
onTextChange = onTextChange,
textStyle = MaterialTheme.typography.h6,
maxLines = 2
)
}

@ExperimentalAnimationApi
@Composable
fun NoteField(
modifier: Modifier = Modifier,
value: String = "",
onTextChange: (String) -> Unit
) {
BasicNotyTextField(
modifier,
value = value,
label = "Write here",
onTextChange = onTextChange,
textStyle = TextStyle(fontSize = 18.sp, fontWeight = FontWeight.Light)
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/*
* Copyright 2020 Shreyas Patil
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package dev.shreyaspatil.noty.composeapp.component.text

import androidx.compose.material.Icon
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Password
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.input.PasswordVisualTransformation
import dev.shreyaspatil.noty.utils.validator.AuthValidator.isPasswordAndConfirmPasswordSame
import dev.shreyaspatil.noty.utils.validator.AuthValidator.isValidPassword

@Composable
fun PasswordTextField(
modifier: Modifier = Modifier,
value: String = "",
onTextChange: (TextFieldValue<String>) -> Unit,
) {
var startedTyping by remember { mutableStateOf(false) }
var isValid by remember { mutableStateOf(false) }

NotyTextField(
value = value,
label = "Password",
onValueChange = {
isValid = isValidPassword(it)
onTextChange(if (isValid) TextFieldValue.Valid(it) else TextFieldValue.Invalid(it))
if (!startedTyping) {
startedTyping = true
}
},
modifier = modifier,
leadingIcon = { Icon(Icons.Outlined.Password, "Password") },
visualTransformation = PasswordVisualTransformation(),
isError = !isValid && startedTyping
)
}

@Composable
fun ConfirmPasswordTextField(
modifier: Modifier = Modifier,
value: String = "",
expectedValue: String = "",
onTextChange: (TextFieldValue<String>) -> Unit,
) {
var startedTyping by remember { mutableStateOf(false) }
var isValid by remember { mutableStateOf(false) }

NotyTextField(
value = value,
label = "Confirm Password",
onValueChange = {
isValid = isValidPassword(it) && isPasswordAndConfirmPasswordSame(expectedValue, it)
onTextChange(if (isValid) TextFieldValue.Valid(it) else TextFieldValue.Invalid(it))
if (!startedTyping) {
startedTyping = true
}
},
modifier = modifier,
leadingIcon = { Icon(Icons.Outlined.Password, "Confirm Password") },
visualTransformation = PasswordVisualTransformation(),
isError = !isValid && startedTyping
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* Copyright 2020 Shreyas Patil
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package dev.shreyaspatil.noty.composeapp.component.text

sealed class TextFieldValue<T>(val data: T) {
class Valid<T>(data: T) : TextFieldValue<T>(data)
class Invalid<T>(data: T) : TextFieldValue<T>(data)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* Copyright 2020 Shreyas Patil
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package dev.shreyaspatil.noty.composeapp.component.text

import androidx.compose.material.Icon
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Person
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import dev.shreyaspatil.noty.utils.validator.AuthValidator

@Composable
fun UsernameTextField(
modifier: Modifier = Modifier,
value: String = "",
onTextChange: (TextFieldValue<String>) -> Unit,
) {
var startedTyping by remember { mutableStateOf(false) }
var isValid by remember { mutableStateOf(false) }

NotyTextField(
value = value,
label = "Username",
onValueChange = {
isValid = AuthValidator.isValidUsername(it)
onTextChange(if (isValid) TextFieldValue.Valid(it) else TextFieldValue.Invalid(it))
if (!startedTyping) {
startedTyping = true
}
},
modifier = modifier,
leadingIcon = { Icon(Icons.Outlined.Person, "User") },
isError = !isValid && startedTyping
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package dev.shreyaspatil.noty.composeapp.navigation

import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.runtime.Composable
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.NavType
Expand All @@ -37,10 +38,11 @@ import kotlinx.coroutines.InternalCoroutinesApi

const val NOTY_NAV_HOST_ROUTE = "noty-main-route"

@ExperimentalAnimationApi
@InternalCoroutinesApi
@ExperimentalCoroutinesApi
@Composable
fun NotyNavigation(toggleTheme: () -> Unit) {
fun NotyNavigation() {
val navController = rememberNavController()

NavHost(navController, startDestination = Screen.Notes.route, route = NOTY_NAV_HOST_ROUTE) {
Expand All @@ -54,7 +56,7 @@ fun NotyNavigation(toggleTheme: () -> Unit) {
AddNoteScreen(navController, hiltViewModel())
}
composable(Screen.Notes.route) {
NotesScreen(toggleTheme, navController, hiltViewModel())
NotesScreen(navController, hiltViewModel())
}
composable(
Screen.NotesDetail.route,
Expand Down
Loading