Skip to content

Commit

Permalink
Merge pull request #8 from mughalasim/feature/version-checker
Browse files Browse the repository at this point in the history
- App checks for latest version automatically and notifies the user
- Members can be searched by name
  • Loading branch information
mughalasim authored Jul 16, 2024
2 parents 135444c + ed8a7f5 commit d8e6c80
Show file tree
Hide file tree
Showing 22 changed files with 344 additions and 173 deletions.
17 changes: 12 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
**Ndemi Garden Gym App**

// Will be using this app as a template soon
https://play.google.com/store/apps/details?id=homeworkout.homeworkouts.noequipment

Allows the gym coach/ Admin to
- Register new members
- Track each members attendance
- Update active status
- Update their membership renewal
- Update payment plans and membership expiry

Available app updates are prompted by the app

Member types

**Members**
- Can register sign up and reset their password
Expand All @@ -18,5 +18,12 @@ Allows the gym coach/ Admin to

**Admins**
- Can Register new members
- Can delete a member
- Can upload their profile picture
- Can update each members membership renewal date, attendance, has a coach, active status and profile pictures
- Can view and edit all members

**Supervisor**
- Can view all members
- Can view each members attendance and payments
- Can upload their profile picture
3 changes: 3 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ android {
setConfigVariable(variableName = "ADMIN_STAGING", variableSource = "ADMIN_STAGING")
setConfigVariable(variableName = "PATH_USER_IMAGES", variableSource = "PATH_USER_IMAGES")
setConfigVariable(variableName = "PATH_PAYMENT", variableSource = "PATH_PAYMENT")
setConfigVariable(variableName = "PATH_APP_VERSION", variableSource = "PATH_APP_VERSION")

proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
vectorDrawables { useSupportLibrary = true }
Expand All @@ -61,6 +62,7 @@ android {
setConfigVariable(variableName = "PATH_USER", variableSource = "PATH_USER")
setConfigVariable(variableName = "PATH_ATTENDANCE", variableSource = "PATH_ATTENDANCE")
setConfigVariable(variableName = "PATH_PAYMENT_PLAN", variableSource = "PATH_PAYMENT_PLAN")
setConfigVariable(variableName = "PATH_APP_VERSION_TYPE", variableSource = "PATH_APP_VERSION_TYPE")
}

getByName("debug") {
Expand All @@ -71,6 +73,7 @@ android {
setConfigVariable(variableName = "PATH_USER", variableSource = "DEBUG_PATH_USER")
setConfigVariable(variableName = "PATH_ATTENDANCE", variableSource = "DEBUG_PATH_ATTENDANCE")
setConfigVariable(variableName = "PATH_PAYMENT_PLAN", variableSource = "DEBUG_PATH_PAYMENT")
setConfigVariable(variableName = "PATH_APP_VERSION_TYPE", variableSource = "DEBUG_PATH_APP_VERSION_TYPE")
}
}

Expand Down
1 change: 0 additions & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@

<activity
android:name=".ui.screens.main.MainActivity"
android:windowSoftInputMode="adjustResize"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ val repositoryModule =
single<AuthRepository> {
AuthRepositoryImp(
pathUser = BuildConfig.PATH_USER,
pathVersion = BuildConfig.PATH_APP_VERSION,
pathVersionType = BuildConfig.PATH_APP_VERSION_TYPE,
currentAppVersion = BuildConfig.VERSION_CODE,
logger = get()
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import androidx.compose.runtime.livedata.observeAsState
import androidx.navigation.compose.rememberNavController
import com.ndemi.garden.gym.ui.widgets.LoadingScreenWidget
import com.ndemi.garden.gym.ui.widgets.WarningWidget
import com.ndemi.garden.gym.ui.screens.main.MainScreenViewModel.AuthState
import com.ndemi.garden.gym.ui.screens.main.MainScreenViewModel.VersionState
import cv.domain.entities.MemberType
import org.koin.androidx.compose.koinViewModel

Expand All @@ -14,47 +16,51 @@ fun MainScreen(
) {
val navController = rememberNavController()
viewModel.setNavController(navController)
val authState = viewModel.authState.observeAsState()
val versionState = viewModel.appVersion.observeAsState(initial = VersionState.Loading)

when(authState.value){
MainScreenViewModel.AuthState.Authorised -> {
val data = viewModel.loggedInMember.observeAsState()
when(val response = data.value){
when (versionState.value) {
VersionState.Loading -> LoadingScreenWidget()

is MainScreenViewModel.UiState.Error -> {
WarningWidget(title = response.message)
}
is VersionState.UpdateRequired ->
NewVersionScreen(url = (versionState.value as VersionState.UpdateRequired).url)

MainScreenViewModel.UiState.Loading -> {
LoadingScreenWidget()
}
VersionState.Success -> {
val authState =
viewModel.authState.observeAsState(initial = AuthState.Loading)

is MainScreenViewModel.UiState.Success -> {
when (authState.value) {
AuthState.Loading -> LoadingScreenWidget()

AuthState.UnAuthorised ->
MainDetailsScreen(
isAuthenticated = true,
isAdmin = response.member.memberType != MemberType.MEMBER,
isAuthenticated = false,
isAdmin = false,
navController = navController,
navigationService = viewModel.getNavigationService()
)
}

null -> {
LoadingScreenWidget()
}
}
}

MainScreenViewModel.AuthState.UnAuthorised -> {
MainDetailsScreen(
isAuthenticated = false,
isAdmin = false,
navController = navController,
navigationService = viewModel.getNavigationService()
)
}
AuthState.Authorised -> {
val data =
viewModel.loggedInMember.observeAsState(initial = MainScreenViewModel.UiState.Loading)

when (val response = data.value) {
MainScreenViewModel.UiState.Loading -> LoadingScreenWidget()

is MainScreenViewModel.UiState.Error ->
WarningWidget(title = response.message)

null -> {
LoadingScreenWidget()

is MainScreenViewModel.UiState.Success ->
MainDetailsScreen(
isAuthenticated = true,
isAdmin = response.member.memberType != MemberType.MEMBER,
navController = navController,
navigationService = viewModel.getNavigationService()
)
}
}
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class MainScreenViewModel(
fun getNavigationService(): NavigationService = navigationService

val authState = liveData(Dispatchers.IO) {
emit(AuthState.UnAuthorised)
emit(AuthState.Loading)
authUseCase.getAuthState().collect{
when(it){
is DomainResult.Success ->
Expand All @@ -32,7 +32,18 @@ class MainScreenViewModel(
emit(AuthState.UnAuthorised)
}
}
}

val appVersion = liveData(Dispatchers.IO) {
emit(VersionState.Loading)
authUseCase.getAppVersion().collect{
when(it){
is DomainResult.Success ->
emit(VersionState.UpdateRequired(it.data))

is DomainResult.Error -> emit(VersionState.Success)
}
}
}

val loggedInMember = liveData(Dispatchers.IO) {
Expand All @@ -49,8 +60,19 @@ class MainScreenViewModel(
}
}

@Immutable
sealed interface VersionState {
data object Loading : VersionState

data object Success : VersionState

data class UpdateRequired(val url: String) : VersionState
}

@Immutable
sealed interface AuthState {
data object Loading : AuthState

data object Authorised : AuthState

data object UnAuthorised : AuthState
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package com.ndemi.garden.gym.ui.screens.main

import android.net.Uri
import android.util.Log
import android.widget.Toast
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.res.stringResource
import com.ndemi.garden.gym.R
import com.ndemi.garden.gym.ui.theme.AppThemeComposable
import com.ndemi.garden.gym.ui.theme.padding_screen
import com.ndemi.garden.gym.ui.utils.AppPreview
import com.ndemi.garden.gym.ui.widgets.ButtonWidget
import com.ndemi.garden.gym.ui.widgets.TextRegular
import com.ndemi.garden.gym.ui.widgets.TextRegularBold

@Composable
fun NewVersionScreen(
url: String,
) {
Column(
modifier = Modifier
.fillMaxSize()
.padding(padding_screen),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
val uriHandler = LocalUriHandler.current
val context = LocalContext.current
TextRegularBold(
text = stringResource(R.string.txt_app_update_title)
)
TextRegular(
modifier = Modifier.padding(top = padding_screen),
text =
stringResource(R.string.txt_app_update_desc)
)
ButtonWidget(title = stringResource(R.string.txt_download)) {
if (isValidUri(url)) {
uriHandler.openUri(url)
} else {
Toast.makeText(
context,
context.getString(R.string.error_failed_to_open_link), Toast.LENGTH_LONG
).show()
}
}
}
}

@Suppress("TooGenericExceptionCaught")
fun isValidUri(uriString: String): Boolean {
return try {
val uri = Uri.parse(uriString)
uri.scheme != null && uri.host != null
} catch (e: Exception) {
Log.e("isValidUri", e.message?: "IllegalArgumentException")
false
}
}

@AppPreview
@Composable
fun NewVersionScreenPreview() {
AppThemeComposable {
NewVersionScreen(url = "SampleUrl")
}
}

This file was deleted.

Loading

0 comments on commit d8e6c80

Please sign in to comment.