Skip to content

Commit

Permalink
Release v2.0. Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
alexandr7035 committed Sep 14, 2021
2 parents e31cee3 + b447050 commit e32189d
Show file tree
Hide file tree
Showing 66 changed files with 2,007 additions and 653 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
.idea/
app/release
keystore.properties

####

Expand Down
34 changes: 34 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# GitStat
GitStat is a simple android app designed to aggregate Github profile data into informative cards and graphs.

<img src="doc/logo.png" width="20%"/>

### Screenshots
<p align="center">
<img src="doc/screenshot_login.png" width="30%"/>
<img src="doc/screenshot_repositories_stat.png" width="30%"/>
<img src="doc/screenshot_filters.png" width="30%"/>
</p>


### Technology (some notes)

- Used single activity approach and [Navigation component](https://developer.android.com/guide/navigation) to navigate across fragments.
- [View binding](https://developer.android.com/topic/libraries/view-binding) is used to interact with views within fragments and recyclerview adapters.
- Kotlin coroutines are used for asynchronous operations.
- [Retrofit](https://github.com/square/retrofit) is used to perform [Github API](https://docs.github.com/en/rest) calls to obtain the data. Also use [OkHttp Logging Interceptor](https://github.com/square/okhttp/tree/master/okhttp-logging-interceptor) to log requests.
- [Room](https://developer.android.com/jetpack/androidx/releases/room) database is used for cache implementation.
- [colors.json]() file is borrowed from the [github-colors](https://github.com/ozh/github-colors) repository and parsed with [Gson](https://github.com/google/gson) library in order to obtain and display native github colors for programming languages.
- Google's [FlexboxLayout](https://github.com/google/flexbox-layout) as LayoutManager and custom checkable LinearLayout are
used to implement languages filter (see third screenshot).
- [CircleImageView](https://github.com/hdodenhof/CircleImageView) and [Picasso](https://github.com/square/picasso) libs are involved to obtain and display user profile image.
- [MPAndroidChart](https://github.com/PhilJay/MPAndroidChart) library is used for plots and diagrams in the application.


### How to authorize
- Download APK from the [releases](https://github.com/alexandr7035/gitstat/releases) page and install it.
- Go to [Personal access tokens](https://github.com/settings/tokens) section in your Github profile settings.
- Create personal access token with ```read:user``` and ```repo``` access scopes. (**Note**: full ```repo``` scope is used only to have access to your private repos data. No malicious write operations are performed by the app).
- Use the obtained token as auth credetial in the application login form.

More user-friendly auth method may be implemented later. Authorization process in the app **needs additional research and refactoring**.
25 changes: 25 additions & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,23 @@ plugins {
id 'kotlin-kapt'
}

def keystorePropertiesFile = rootProject.file("keystore.properties")
def keystoreProperties = new Properties()
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))

android {
compileSdkVersion 30
buildToolsVersion "30.0.3"

signingConfigs {
config {
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
storeFile file(keystoreProperties['storeFile'])
storePassword keystoreProperties['storePassword']
}
}

defaultConfig {
applicationId 'com.alexandr7035.gitstat'
minSdkVersion 21
Expand All @@ -23,6 +36,14 @@ android {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}

debug {
signingConfig signingConfigs.config
applicationIdSuffix ".debug"
debuggable true
versionNameSuffix ".debug"
}

}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
Expand All @@ -35,6 +56,8 @@ android {
buildFeatures {
viewBinding true
}


}


Expand All @@ -54,6 +77,7 @@ dependencies {

implementation "com.squareup.retrofit2:retrofit:2.9.0"
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation "com.squareup.okhttp3:logging-interceptor:4.9.1"

implementation 'de.hdodenhof:circleimageview:3.1.0'
implementation 'com.squareup.picasso:picasso:2.71828'
Expand All @@ -65,4 +89,5 @@ dependencies {
implementation "androidx.room:room-ktx:$room_version"
annotationProcessor "androidx.room:room-compiler:$room_version"
kapt("androidx.room:room-compiler:$room_version")
implementation 'com.google.android.flexbox:flexbox:3.0.0'
}
3 changes: 2 additions & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@
<uses-permission android:name="android.permission.INTERNET" />

<application
android:name=".core.App"
android:allowBackup="false"
android:icon="@drawable/ic_app"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.GitStat">
<activity
android:name="com.alexandr7035.gitstat.presentation.MainActivity"
android:name="com.alexandr7035.gitstat.view.MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
Expand Down

This file was deleted.

13 changes: 13 additions & 0 deletions app/src/main/java/com/alexandr7035/gitstat/core/App.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.alexandr7035.gitstat.core

import android.app.Application

class App: Application() {

lateinit var progLangManager: ProgLangManager

override fun onCreate() {
super.onCreate()
progLangManager = ProgLangManager(context = applicationContext)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.alexandr7035.gitstat.core

import android.R.attr.state_checked as attr_state_checked
import android.content.Context
import android.util.AttributeSet
import android.widget.Checkable
import android.widget.LinearLayout

class CheckableLinearLayout: LinearLayout, Checkable {

constructor(context: Context): super(context)
constructor(context: Context, attrs: AttributeSet): super(context, attrs)

companion object {
private val checkedStateSet = intArrayOf(attr_state_checked)
}

private var isChecked: Boolean = false

override fun setChecked(checked: Boolean) {
if (isChecked != checked) {
isChecked = checked
refreshDrawableState()
}
}

override fun isChecked(): Boolean {
return isChecked
}

override fun toggle() {
setChecked(! isChecked)
}

override fun performClick(): Boolean {
//Log.d("DEBUG", "toggle checkable layout $id")
toggle()
return super.performClick()
}


override fun onCreateDrawableState(extraSpace: Int): IntArray? {
val drawableState = super.onCreateDrawableState(extraSpace + 1)
if (isChecked()) {
mergeDrawableStates(drawableState, checkedStateSet)
}
return drawableState
}

}
7 changes: 7 additions & 0 deletions app/src/main/java/com/alexandr7035/gitstat/core/Language.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.alexandr7035.gitstat.core

data class Language(
val name: String,
val color: String,
val count: Int
)
5 changes: 5 additions & 0 deletions app/src/main/java/com/alexandr7035/gitstat/core/Mapper.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.alexandr7035.gitstat.core

interface Mapper<SRC, DST> {
fun transform(data: SRC): DST
}
74 changes: 74 additions & 0 deletions app/src/main/java/com/alexandr7035/gitstat/core/ProgLangManager.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package com.alexandr7035.gitstat.core

import android.content.Context
import com.alexandr7035.gitstat.R
import com.alexandr7035.gitstat.data.local.model.RepositoryEntity
import com.google.gson.GsonBuilder
import com.google.gson.reflect.TypeToken
import java.io.InputStreamReader
import java.util.*
import kotlin.collections.ArrayList

class ProgLangManager(context: Context) {

private var languagesColorsList: Map<String, Map<String, String>>? = null
private val colorUnknownLanguageOrNullColor = "#C3C3C3"
private val UNKNOWN_LANGUAGE = "Unknown"

init {
val inputStream = context.resources.openRawResource(R.raw.language_colors)
val reader = InputStreamReader(inputStream)
val builder = GsonBuilder()
val itemsMapType = object : TypeToken<Map<String, Map<String, String>>>() {}.type

languagesColorsList = builder.create().fromJson(reader, itemsMapType)
}


fun getLanguageColor(language: String): String {
return when(language) {
// When repo language can't be defined
// E.g when there are no commits in main branch
UNKNOWN_LANGUAGE -> colorUnknownLanguageOrNullColor

else -> {
when (languagesColorsList!![language]!!["color"]) {
// When Lang color is explicitly defined in JSON as null ¯\_(-_-)_/
null -> colorUnknownLanguageOrNullColor
else -> languagesColorsList!![language]!!["color"]!!
}
}
}
}


// TODO simplify - too many loops
fun getLanguagesList(repositories: List<RepositoryEntity>): List<Language> {

val languagesList = ArrayList<Language>()

val languagesTreeMap: TreeMap<String, Int> = TreeMap()

// Init languages map
repositories.forEachIndexed { i, repo ->
languagesTreeMap[repo.language] = 0
}

// Populate languages map
repositories.forEachIndexed { i, repo ->
languagesTreeMap[repo.language] = languagesTreeMap[repo.language]!! + 1
}

languagesTreeMap.forEach {
languagesList.add(
Language(
name = it.key,
count = it.value,
color = getLanguageColor(it.key)
))
}

return languagesList
}

}
7 changes: 7 additions & 0 deletions app/src/main/java/com/alexandr7035/gitstat/core/SyncStatus.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.alexandr7035.gitstat.core

enum class SyncStatus {
SUCCESS,
PENDING,
FAILED
}
Loading

0 comments on commit e32189d

Please sign in to comment.