Skip to content

ItalianCoders/mybudget2-mobile-android

Repository files navigation

GitHub last commit GitHub issues by-label GitHub issues GitHub closed issues CircleCI

💰 My Budget

📝 Introduzione

Grazie alla comunità degli autori di italianCoders nasce My Budget, un progetto opensource, mantenuto dagli stessi che si propone di raggiungere i seguenti obiettivi:

  1. Aumentare il bagaglio di conoscenze degli autori tramite lo scambio di idee, abilità ed esperienze.

  2. Condividere con la numerosa comunità di programmatori che ruota attorno a italianCoders un esempio di quali tecniche di programmazione e framework utilizzare e in che modo per offrire un aiuto attraverso il codice presente o con domande agli stessi autori.

  3. Ultimo ma non meno importante, quello di offrire un'applicazione gratuita e pratica che possa trovare un utilizzo concreto nella vita di tutti i giorni.

✒️ Autori

FrontEnd Android: Gianluca Fattarsi

BackEnd: Dario Frongillo

📱 My Budget Android

Linguaggio utilizzato: Kotlin.

Questo repository ospita il codice del frontend del progetto mentre il backend lo si può trovare a questo indirizzo.

🔬 Architettura

Di seguito verrà riportato un elenco delle tecniche di programmazione e framework utilizzati per realizzare l'applicazione.

✔️ DataBinding

  • One-way / Two-way

    File: activity_registration_user_info.xml

    Il FrameLayout con id sign_up_button binda le sue proprietà background e clickable alla proprietà dataValid del ViewModel

    Il TextInputEditText con id firstname_ET binda la proprietà text alla proprietà firstname del ViewModel. Utilizzando @={model.firstname} il binding viene fatto in Two-way quindi scrivendo del testo nella vista si aggiorna anche la proprietà del ViewModel e viceversa

  • Converters

    Directory: converters

    Un esempio è possibile trovarlo in list_item_movement.xml in cui è stato aggiunto l'import nel tag data di AmountStringConversion e utilizzato per visualizzare il totale del documento.

    Il converter è stato creato per visualizzare l'importo del documento formattato secondo le impostazioni di sistema con il simbolo della valuta impostato nelle settings dell'applicazione.

  • Adapters

    Directory: adapters

    Nel layout activity_registration_user_info.xml viene utilizzato l'adapter ValidationBindingAdapter su tutti i TextInputLayout.

    Le proprietà che vengono prese in considerazione sono app:validation che rappresenta la rule da applicare per la validazione e app:errorMsg che rappresenta il messaggio di errore che verrà impostato se la rule non viene rispettata.

✔️ ViewModel

  • ViewModel

    I ViewModel presenti sono utilizzati in activity, fragment e custom view all'interno di tutta l'applicazione. Di seguito viene riportato un esempio per ogni tipologia.

    Activity: RegistrationUserInfoActivity

    Fragment: ListMovementsFragment

    Custom view: SearchMovementsView |

  • ViewModelFactory

    In Android non esiste la possibilità di poter instanziare un ViewModel con un costruttore con 1 o più parametri attraverso un ViewModelProviders. Per questo motivo si rende necessario l'uso di ViewModelFactory.

    Nell'applicazione possiamo trovare l'uso di factory quasi ovunque. Un esempio può essere quello in CategoriesActivity dove il ViewModel viene creato nel metodo onCreate. In realtà non esite un factory per ogni ViewModel perchè tramite Dagger injection viene utilizzata la classe DaggerViewModelFactory. Se invece si decidesse di non utilizzare questa libreria l'implementazione del factory da utilizzare sarebbe:

    import androidx.lifecycle.ViewModel
    import androidx.lifecycle.ViewModelProvider
    import it.italiancoders.mybudget.manager.categories.CategoriesManager
    
    class CategoriesViewModelFactory(private val categoriesManager: CategoriesManager) : ViewModelProvider.Factory {
    
        override fun <T : ViewModel> create(modelClass: Class<T>): T {
            return CategoriesViewModel(categoriesManager) as T
        }
    }
LiveData

🚧 In costruzione 🚧

Observable

🚧 In costruzione 🚧

✔️ Animation

  • ValueAnimator

    Esempio: LoginActivity

    Le animaizoni utilizzatate nell'activity di login sono 2 e, al click del pulsante di login, si occupano rispettivamente di:

    • Ridurre la larghezza del pulsante
    • Cambiare la trasparenza del testo del pulsante e alla fine visualizzare la progress bar

    Prendendo come esempio la prima animazione ecco il codice:

    val finalWidth = resources.getDimension(R.dimen.sign_button_loading_width).toInt()
    val anim = ValueAnimator.ofInt(binding.signInButton.measuredWidth, finalWidth)
    anim.addUpdateListener {
        val value: Int = it.animatedValue as Int
        val layoutParam = binding.signInButton.layoutParams
        layoutParam.width = value
        binding.signInButton.requestLayout()
    }
    anim.duration = 250
    anim.start()

    Il ValueAnimator si basa su un range di valori dalla normale larghezza del pulsante a quella finale (finalWidth) definita nelle resources. Il listener aggiunto contiene il valore corrente dell'animazione (it.animatedValue) che viene utilizzato per settare la nuova larghezza al layout del pulsante (layoutParam.width).

    Per altri esempi sull'uso di animazioni con ValueAnimator o utilizzando un ConstraintLayout è possibile consultare i miei articoli a questi indirizzi:

    Android: creare favolose animazioni con ConstraintLayout – Parte 1

    Android: creare favolose animazioni con ConstraintLayout – Parte 2

✔️ Kotlin

  • Extensions

    Per approfondire: documentazione kotlinlang

    Kotlin permette di aggiungere nuove funzionalità ad una classe senza doverla estendere tramite delle speciali dichiarazioni chiamate appunto Kotlin extensions.

    Un esempio è possibile trovarlo nella classe ViewModelExtensions in cui vengono aggiunti 3 nuovi metodi alla classe ViewModel: uiJob, ioJob e backgroundJob.

    Nella classe LoginViewModel nel metodo login troviamo l'uso dei primi 2 metodi citati in quanto chiunque estenda ViewModel potrà averli a disposizione.

    Prendendo come riferimento Java tutto ciò sarebbe stato possibile realizzarlo creando una classe (astratta) BaseViewModel che estende ViewModel in cui implementare i 3 metodi e successivamente far estendere da questa classe LoginViewModel.

  • Coroutines

    Per approfondire: documentazione kotlinlang

    Il capitolo delle coroutines in kotlin è molto vasto e prima di utilizzarle è assolutamente obbligatorio leggerne la documentazione. L'uso in questa applicazione per ora si limita alla gestione dei thread come quando succedeva in Java con l'utilizzo degli AsyncTask.

    Un esempio di utilizzo nell'applicazione può essere quello nella classe RegistrationUserInfoManager nel metodo resend. In questo caso specifico viene eseguita la chiamata rest in background con

    CoroutineScope(Dispatchers.IO).launch {}

    e la response viene processata con

    withContext(Dispatchers.Main) {}

    Il tutto risulta

    CoroutineScope(Dispatchers.IO).launch {
        // Operazioni in background
        val response = registrationUserInfoRestService.resend(userName)
        withContext(Dispatchers.Main) {
            // Operazioni su UI thread
            processResponse(response, onSuccessAction, onFailureAction)
        }
    }
Dagger injection

🚧 In costruzione 🚧

  • Application
  • Module
  • Components
REST client

🚧 In costruzione 🚧

  • Client
  • Interceptor

✔️ Tutorials

I tutorials presenti nelle varie activity dell'applicazione sono stati realizzati utilizzando la libreria Spotlight.

La BaseActivity comprende il metodo createTutorial() che è possibile sovrascrivere per far restituire il tutorial da visualizzare all'apertura dell'activity.

Ogni tutorial estende da AbstractTutorialActivity in cui sono presenti i metodi per aprirlo, controllare se è già stato visualizzato e marcarlo come già visto utilizzando un file di preference dedicato (tutorial_prefs).

Nelle preference dell'applicazione è presente inoltre la possibilità di effettuare un reset dei tutorials per poterli rivedere anche in un secondo momento. Il tutto è gestito dalla classe PrefResetTutorialHandler.

RecyclerView

🚧 In costruzione 🚧

  • PagerSnapHelper
  • Adapter
  • Item click listener

✔️ State Machine

L'uso di una State Machine in Informatica rientra in uno dei pattern più usati tradizionalmente. Non si tratta di un pattern coding oriented, quelli per internderci che fanno parte dei tipi della Gang of Four, ma system oriented.

In questa applicazione possiamo trovare un esempio nella classe PeriodType. Il metodo nextType() resituisce lo stato successivo a cui quello attuale può portare.

Nel caso specifico dell'applicazione la successione degli stati è infinita in questo modo:
MONTH --> WEEK --> DAY --> MONTH --> WEEK --> ecc...

Activity startActivityForResult

🚧 In costruzione 🚧

BottomSheetBehavior

🚧 In costruzione 🚧

✔️ Connectivity monitor

L'applicazione prevede la possibilità di funzionare, con ovvie limitazioni, anche in assenza di una connessione a internet.

Il monitoraggio della connesisone è gestito nella classe ConnectivityLiveData in cui sfruttando i LiveData viene registrata una callback su ConnectivityManager che esegue un postValue sugli eventi onAvailable e onLost.

In questo modo registrando un observer su questa classe è possibile essere informati in tempo reale delle presenza o assenza di connessione. Questo viene fatto nella BaseActivity con

SessionData.networkAvailable?.observe(this, networkAvailabilityObserver)

L'observer richiama il metodo syncNetworkStateOption() che può essere sovrascritto in ogni activity per aggiornare lo stato dei vari componenti.

Firebase

🚧 In costruzione 🚧

Crashlytics

🚧 In costruzione 🚧

Settings

🚧 In costruzione 🚧

  • Summary
  • Custom preference
  • Custom file

✔️ Launch screen

La creazione della launch screen è stata fatta con l'utilizzo di un tema dedicato impostato sull'activity di partenza. Per approfondimenti è possibile fare riferimento al mio articolo:

Splash Screen in Android: impariamo a crearle nel modo corretto

Nel file styles.xml è presente il tema AppTheme.Launcher seguente:

<style name="AppTheme.Launcher">
  <item name="android:windowBackground">@drawable/launcher_screen_with_logo</item>
  <item name="android:windowNoTitle">true</item>
  <item name="android:windowActionBar">false</item>
  <item name="android:windowFullscreen">true</item>
  <item name="android:windowContentOverlay">@null</item>
</style>

Nel Manifest.xml il tema è stato impostato alla main activity

<activity
  android:name=".activity.main.MainActivity"
  android:label="@string/app_name"
  android:screenOrientation="portrait"
  android:theme="@style/AppTheme.Launcher">
  <intent-filter>
      <action android:name="android.intent.action.MAIN" />
      <category android:name="android.intent.category.LAUNCHER" />
  </intent-filter>
</activity>
Room ORM

🚧 In costruzione 🚧

  • Database
  • Entity
  • Dao
  • Converter
ProGuard

🚧 In costruzione 🚧

Menu

🚧 In costruzione 🚧

  • Global
  • Activity
Local Junit Test

🚧 In costruzione 🚧

Instrumented Test

🚧 In costruzione 🚧

Shared test

🚧 In costruzione 🚧

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages