Skip to content

Commit

Permalink
Merge branch '1.2.3'
Browse files Browse the repository at this point in the history
  • Loading branch information
aksh1618 committed Feb 23, 2019
2 parents c23a899 + d477dc0 commit 21014f3
Show file tree
Hide file tree
Showing 42 changed files with 197 additions and 79 deletions.
120 changes: 118 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,118 @@
# Bitotsav-19
Official app for Bitotsav 19
# Bitotsav '19

<img src="art/ic_launcher-web.png" align="left" width="200" hspace="10" vspace="10">

The official app for the 29th edition of Bitotsav, BIT Mesra's annual socio-cultural fest.

Note: The functionality of the app is limited after the fest, as the servers are offline, but most of the data related to events and rankings has been preserved as json for archival purposes, and full functionality exists in the code.

<p align="center">
<a href="https://play.google.com/store/apps/details?id=in.bitotsav">
<img
alt="Get it on Google Play"
height="80"
src="https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png" />
</a>
</p>

## 🎨 About

Bitotsav '19, the 29th edition of Birla Institute of Technology, Mesra's annual socio-cultural fest, took place from the 14th to the 17th of February, 2019, featuring 4 nights and 48 events. This app was created by the tech team for proper management of the fest, assisting both participants and organizers by acting as a medium for latest updates as well as the source of knowledge for event details like rules, timings & venues, payment status, rankings & results and much more, all dynamic and real time. Additionally, to complement the theme i.e. "Colours of Asia", the UI colors change on every start.

## ✨ Features

- **Profile:** Login with Bitotsav Id to access Team Statistics, Activity and Night Pass status.
- **Individual Registration:** Register and get your Bitotsav Id.
- **Championship Registration:** Register a team of 6-8 for Bitotsav Championship.
- **Schedule:** Full events listed sorted by time, separated by day and a dedicated section for nights.
- **Event Filters:** Filter the event list based on categories and starred status.
- **Event Details:** Select any event to get detailed information, contact coordinators, see results etc.
- **Event Registration:** Register a team for any event.
- **Subscription:** Subscribe to events you like to receive personalised alerts and updates.
- **Feed:** Real time updates from the Bitotsav '19 team.
- **Leaderboard:** Live standings of all registered championship teams.

## 🖼 Screenshots

<p float="left">
<img src="art/screen1.jpeg" width="200" hspace="12" vspace="12">
<img src="art/screen2.jpeg" width="200" hspace="12" vspace="12">
<img src="art/screen3.jpeg" width="200" hspace="12" vspace="12">
<br>
<br>
<img src="art/screen4.jpeg" width="200" hspace="12" vspace="12">
<img src="art/screen5.jpeg" width="200" hspace="12" vspace="12">
<img src="art/screen6.jpeg" width="200" hspace="12" vspace="12">
<br>
<br>
<img src="art/screen7.jpeg" width="200" hspace="12" vspace="12">
<img src="art/screen8.jpeg" width="200" hspace="12" vspace="12">
<img src="art/screen9.jpeg" width="200" hspace="12" vspace="12">
</p>

## ℹ️ Permissions

No explicit permissions are used by this app, but it does prompt users of devices of certain manufacturers to enable autostart and disable battery optimization to ensure timely delivery of notifications.

## 💻 Tech

### 🗒 Overview

- Developed in **Kotlin** with **Android Studio Canary** as IDE and latest technologies such as AndroidX, Jetpack Architecture Components, Coroutines etc.
- MVVM architecture
- Feature based package structure

### 📱 Android SDK Components

- AndroidX
- Navigation
- Room
- WorkManager
- Data Binding
- Live Data
- ViewModel
- Palette

### 🌐 Network Libraries

- [Retrofit 2](https://github.com/square/retrofit) by Square
- [Gson](https://github.com/google/gson) by Google
- Firebase (FCM)
- Safety Net (reCAPTCHA v2)

### 🔌 Other Third Party Libraries

- [Koin 2 (Beta)](https://github.com/InsertKoinIO/koin) by [InsertKoin.io](insert-koin.io)
- [Retrofit Kotlin Coroutine Adapter](https://github.com/JakeWharton/retrofit2-kotlin-coroutines-adapter) by Jake Wharton
- [AppKillerManager](https://github.com/thelittlefireman/AppKillerManager/tree/master) by thelittlefireman
- [Smart App Rate](https://github.com/codemybrainsout/smart-app-rate) by Code My Brains Out
- [Glide](https://github.com/bumptech/glide) by Sam Judd
- [Android image slider](https://github.com/smarteist/android-image-slider) by Smarteist

### 🖮 Other Tech

- Git Workflow - [Gitflow](https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow) (using [gitflow-avh](https://github.com/petervanderdoes/gitflow-avh))
- Versioning - [Semantic Versioning 2.0.0](https://semver.org/)

## ✅ TODO

- [ ] Tests
- [ ] Better documentation

## 🏛 License

```
Copyright 2019 Aakarshit Uppal, Ashank Anshuman
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.
```
18 changes: 12 additions & 6 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ apply plugin: 'kotlin-android'

apply plugin: 'kotlin-kapt'

// This leads to in.bitotsav... in autogenerated code, but as in is a keyword in Kotlin, compilation
// fails. Bug report created: https://issuetracker.google.com/issues/126020455.
//apply plugin: "androidx.navigation.safeargs.kotlin"
apply plugin: "androidx.navigation.safeargs"

android {
Expand All @@ -12,10 +15,11 @@ android {
applicationId "in.bitotsav"
minSdkVersion 21
targetSdkVersion 28
versionCode 7
versionName "1.2.2"
versionCode 8
versionName "1.2.3"
kapt {
arguments {
// Generate room schema, this allows compile-time check for migration errors
arg("room.schemaLocation", "$projectDir/schemas".toString())
}
}
Expand All @@ -30,6 +34,8 @@ android {
shrinkResources true
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'

// Append version to apk and mapping file names to prevent overwrite
android.applicationVariants.all { variant ->
variant.outputs.all {
outputFileName = "${variant.name}-${variant.versionName}.apk"
Expand All @@ -43,6 +49,7 @@ android {
}
}
}

}
}
dataBinding {
Expand All @@ -51,18 +58,17 @@ android {
}

ext {
// TODO: Move these to project.ext in project level build.gradle
gson_version = "2.8.5"
room_version = "2.1.0-alpha04"
coroutines_version = "1.1.0"
firebase_core_version = "16.0.7"
firebase_messaging_version = "17.3.4"
firebase_messaging_version = "17.4.0"
firebase_jobdispatcher_version = "0.8.5"
retrofit_version = "2.5.0"
retrofit2_kotlin_coroutines_version = "0.9.2"
nav_version = "1.0.0-beta02"
nav_version = "1.0.0-rc01"
koin_version = "2.0.0-beta-1"
workmanager_version = "1.0.0-rc01"
workmanager_version = "1.0.0-rc02"
lifecycle_version = "2.1.0-alpha02"
material_version = "1.0.0"
safetynet_version = "16.0.0"
Expand Down
47 changes: 29 additions & 18 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,33 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" package="in.bitotsav">
xmlns:tools="http://schemas.android.com/tools"
package="in.bitotsav">

<!--TODO: Fix ignores-->
<!-- ACTION-VIEW Intent Filter is automatically generated by the nav-graph element. -->
<!-- The replace is needed to override backup behaviour specified in libraries. -->
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme.Launcher"
android:name=".Bitotsav19"
tools:ignore="AllowBackup,GoogleAppIndexingWarning">
<activity android:name=".HomeActivity"
android:windowSoftInputMode="stateAlwaysHidden|adjustResize"
android:documentLaunchMode="intoExisting">
<nav-graph android:value="@navigation/nav_bitotsav"/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
android:name=".Bitotsav19"
android:allowBackup="false"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme.Launcher"
tools:ignore="GoogleAppIndexingWarning"
tools:replace="android:allowBackup">

<activity
android:name=".HomeActivity"
android:documentLaunchMode="intoExisting"
android:windowSoftInputMode="stateAlwaysHidden|adjustResize">

<category android:name="android.intent.category.LAUNCHER"/>
<nav-graph android:value="@navigation/nav_bitotsav" />

<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>

</activity>

<service android:name="in.bitotsav.notification.fcm.DefaultFirebaseMessagingService">
<service android:name="in.bitotsav.notification.fcm.DefaultFirebaseMessagingService"
tools:ignore="ExportedService">

<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>

</service>

</application>

</manifest>
15 changes: 9 additions & 6 deletions app/src/main/java/in/bitotsav/Bitotsav19.kt
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,12 @@ class Bitotsav19 : Application() {
}

// Global TODOs
// TODO: Move tools:context in all layout files from <layout> to root inside <layout>
// TODO: [Refactor] The magnum opus: Wire color change into the lifecycle, so every
// major interactions causes a color change!
// TODO: [WARN]: Figure out if lifecycleOwner passed to data binding should be
// viewLifecycleOwner or
// TODO: [Refactor] Inject all services as AuthenticationService is right now
// TODO [WARN]: Figure out if lifecycleOwner passed to data binding should be
// viewLifecycleOwner or fragment.this
// TODO [WARN]: Figure out if app:layout_behavior="@string/appbar_scrolling_view_behavior" can
// break in various layout files.
// TODO [Refactor]: Inject all services as AuthenticationService is right now
// TODO [Refactor]: Try removing as many observers from fragments as possible, observing should
// preferably be done by data binding view only.
// TODO [WARN]: Figure out which fragment lifecycle method should contain what code, instead of putting
// everything in onCreateView. Might lead to increased performance.
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,6 @@ class EventDetailFragment : Fragment() {
}

binding.share.setOnClickListener {
// FIXME [WARN] : Use deep link here.
eventViewModel.currentEvent.value?.let {
val link = "bitotsav.in/event/${it.id}"
val textToShare = getString(R.string.event_format_share_text, it.name, link)
Expand All @@ -102,7 +101,7 @@ class EventDetailFragment : Fragment() {
eventViewModel.isUserAlreadyRegistered
.onTrue {
Log.d(TAG, "Deregistering...")
// FIXME [WARN]: Add Confirmation Dialog
// TODO [Refactor]: Add Confirmation Dialog
toast("Deregistering...")
eventViewModel.deregister()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,6 @@ class EventRegistrationFragment : Fragment() {

isUserRegistered.setObserver(viewLifecycleOwner) { registered ->
if (registered) {
// TODO: Show success in some way
this@EventRegistrationFragment.toast(
getString(
R.string.event_format_registration_message,
Expand Down Expand Up @@ -107,4 +106,4 @@ class EventRegistrationFragment : Fragment() {

}

// FIXME [WARN]: Ask for confirmation before going back from registration
// TODO [Refactor]: Ask for confirmation before going back from registration
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ class NightDetailFragment : Fragment() {
return binding.root
}

// TODO : Create a back button somewhere
// TODO [Refactor] : Create a back button somewhere
// private fun setClickListeners(binding: FragmentEventDetailBinding) {
//
// binding.back.setOnClickListener {
Expand Down
4 changes: 1 addition & 3 deletions app/src/main/java/in/bitotsav/events/ui/ScheduleFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ class ScheduleFragment : Fragment() {
private lateinit var binding: FragmentScheduleBinding
private val filterAdapter by lazy { ScheduleFilterAdapter(scheduleViewModel) }

// TODO: Get colors from resources
private val filterColors by lazy {
context?.resources?.getIntArray(R.array.categoryColors)
?: intArrayOf(scheduleViewModel.mColor)
Expand All @@ -49,7 +48,7 @@ class ScheduleFragment : Fragment() {
): View? {

uiUtilViewModel.showBottomNav()
// TODO: May need to account for sheet closed on swipe
// TODO [Refactor] : May need to account for sheet closed on swipe
scheduleViewModel.hideFiltersSheet()
scheduleViewModel.setupFilters()
scheduleViewModel.filterColors = filterColors
Expand All @@ -58,7 +57,6 @@ class ScheduleFragment : Fragment() {
}.data

binding = FragmentScheduleBinding.inflate(inflater, container, false)
// TODO: Putting everything from here on in onActivityCreated may increase performance.
.apply {
lifecycleOwner = this@ScheduleFragment
viewModel = scheduleViewModel
Expand Down
3 changes: 1 addition & 2 deletions app/src/main/java/in/bitotsav/events/ui/ScheduleViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class ScheduleViewModel(
get() = scheduleFiltersList
lateinit var filterColors: IntArray
private lateinit var allCategories: List<String>
// TODO: Use switch map with double trigger for this
// TODO [Refactor]: Use switch map with double trigger for this ?
val areFiltersActive = MutableLiveData<Boolean>()
val filterFabVisible = NonNullMutableLiveData(true)

Expand All @@ -57,7 +57,6 @@ class ScheduleViewModel(
throw IllegalStateException("Categories and/or starred are null, somehow")
when (categories) {
ALL_CATEGORIES -> eventRepository.getByDay(day, starredOnly)
// TODO: May need to be sorted by time
else -> eventRepository.getByCategoriesForDay(
day,
starredOnly,
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/java/in/bitotsav/info/ui/InfoFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ class InfoFragment : Fragment() {
.formSubmitText("Submit")
.formCancelText("Cancel")
.playstoreUrl(getString(R.string.app_url_play_store))
.onRatingChanged { rating, thresholdCleared ->
.onRatingChanged { _, thresholdCleared ->
thresholdCleared.onTrue {
context?.let { "Please leave a review!".toast(it) }
}
Expand Down
4 changes: 2 additions & 2 deletions app/src/main/java/in/bitotsav/koin/modules.kt
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import retrofit2.converter.gson.GsonConverterFactory

private const val baseUrl = "https://bitotsav.in/api/app/"

// TODO: Should modules conform to package division?
// TODO [Refactor]: Should modules conform to package division?
val repositoriesModule = module {

single {
Expand Down Expand Up @@ -67,7 +67,7 @@ val retrofitModule = module {
}
).create()
}
// TODO: Check if custom client is required
// TODO @ashank : Check if custom client is required
single {
Retrofit.Builder()
.baseUrl(baseUrl)
Expand Down
Loading

0 comments on commit 21014f3

Please sign in to comment.