├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── ic_menu-web.png │ ├── java │ └── com │ │ └── vrgsoft │ │ └── mygoal │ │ ├── data │ │ └── db │ │ │ ├── alerts │ │ │ └── Goal.kt │ │ │ └── habits │ │ │ ├── HabitJob.kt │ │ │ └── HabitsRepositoryLocalImp.kt │ │ ├── domain │ │ └── habits │ │ │ ├── HabitInteractor.kt │ │ │ ├── HabitRepository.kt │ │ │ ├── HabitsInteractor.kt │ │ │ └── HabitsRepository.kt │ │ └── presentation │ │ ├── common │ │ ├── BaseActivity.kt │ │ ├── BaseFragment.kt │ │ ├── BasePresenter.kt │ │ ├── BaseView.kt │ │ ├── CachedValue.kt │ │ ├── Layout.kt │ │ ├── SettingsHelper.kt │ │ └── view │ │ │ ├── CheckableButton.kt │ │ │ └── CheckableUtils.kt │ │ ├── events │ │ └── BaseEvent.kt │ │ ├── injection │ │ ├── AddHabitComponent.kt │ │ ├── App.kt │ │ ├── ApplicationComponent.kt │ │ ├── ApplicationModule.kt │ │ ├── DataModule.kt │ │ ├── DomainModule.kt │ │ ├── HabitsComponent.kt │ │ ├── HasComponent.kt │ │ └── PerActivity.kt │ │ ├── main │ │ ├── SplashActivity.kt │ │ ├── addhabit │ │ │ ├── AddHabitActivity.kt │ │ │ ├── AddHabitFragment.kt │ │ │ ├── AddHabitPresenter.kt │ │ │ └── AddHabitView.kt │ │ ├── habits │ │ │ ├── HabitsActivity.kt │ │ │ ├── HabitsFragment.kt │ │ │ ├── HabitsPresenter.kt │ │ │ ├── HabitsRouter.kt │ │ │ ├── HabitsView.kt │ │ │ └── common │ │ │ │ ├── GoalClickListener.kt │ │ │ │ ├── HabitsAdapter.kt │ │ │ │ ├── resultdialogs │ │ │ │ └── ResultDialog.kt │ │ │ │ └── themedialog │ │ │ │ ├── OnThemeChooseCallBack.kt │ │ │ │ ├── ThemeAdapter.kt │ │ │ │ ├── ThemeDialogFragment.kt │ │ │ │ └── ThemeViewModel.kt │ │ └── showhabit │ │ │ ├── ShowHabbitView.kt │ │ │ ├── ShowHabitFragment.kt │ │ │ └── ShowHabitPresenter.kt │ │ └── receivers │ │ ├── AlarmReceiver.kt │ │ └── TimeChangeReceiver.kt │ └── res │ ├── anim │ └── move_anim.xml │ ├── drawable │ ├── actionbar_shadow.xml │ ├── arts_icon.png │ ├── bt_drawable.xml │ ├── dialog_background.png │ ├── healthy_icon.png │ ├── home_icon.png │ ├── ic_add.xml │ ├── ic_collections.xml │ ├── ic_mode_edit_black_24dp.xml │ ├── icon.png │ ├── main_back.png │ ├── main_splash.png │ ├── money_icon.png │ ├── move_back.png │ ├── other_icon.png │ ├── rounded_white_rect.xml │ ├── self_improvment_icon.png │ ├── sex_dating_icon.png │ ├── social_icon.png │ └── work_and_study_icon.png │ ├── layout │ ├── activity_add_habit.xml │ ├── activity_habits.xml │ ├── activity_splash.xml │ ├── dialog_failed.xml │ ├── dialog_success.xml │ ├── fragment_add_habit.xml │ ├── fragment_dialog_theme.xml │ ├── fragment_habits.xml │ ├── fragment_show_habit.xml │ ├── item.xml │ ├── item_habit.xml │ └── recycler_dialog.xml │ ├── menu │ └── main_menu.xml │ ├── mipmap-hdpi │ ├── ic_launcher.png │ ├── ic_launcher_round.png │ └── ic_menu.png │ ├── mipmap-mdpi │ ├── ic_launcher.png │ ├── ic_launcher_round.png │ └── ic_menu.png │ ├── mipmap-xhdpi │ ├── ic_launcher.png │ ├── ic_launcher_round.png │ └── ic_menu.png │ ├── mipmap-xxhdpi │ ├── ic_launcher.png │ ├── ic_launcher_round.png │ └── ic_menu.png │ ├── mipmap-xxxhdpi │ ├── ic_launcher.png │ ├── ic_launcher_round.png │ └── ic_menu.png │ ├── values-it │ └── strings.xml │ ├── values-ru │ └── strings.xml │ ├── values-uk │ └── strings.xml │ ├── values │ ├── attrs.xml │ ├── colors.xml │ ├── dimens.xml │ ├── integers.xml │ ├── strings.xml │ └── styles.xml │ └── xml │ ├── analytics.xml │ └── filepaths.xml ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ └── gradle-wrapper.properties └── settings.gradle /README.md: -------------------------------------------------------------------------------- 1 | #### Get a new goal 2 | ![](https://lh3.googleusercontent.com/IBETVjwaw9S6XYxMVg7qWRGAJvoLIzngNxsNkIrmDJuf9R2AOygZtahMUjMz1_bieWU=w300-rw) 3 | #### We are VRG SOFT 4 | Our professionals know how to compose Cloud technologies and Internet of Things in one perfect structure. During the last 5 years we gathered strong native mobile app development tools in order to make product development process run smoothly. In our way to becoming the partner you can rely on, we are working hard and rapidly improving our product development process. Following the user’s needs we create easy-to-use and user-friendly mobile apps to deliver much more traffic to your business. 5 | 6 | First open source simple project to get your own goal 7 | 8 | Stack technology: 9 | Dagger2 + Rx2 + Realm using Clean architecture 10 | 11 | #### [HIRE US](http://vrgsoft.net/) 12 | #### Download 13 | * [Download APK from here](https://play.google.com/store/apps/details?id=com.vrgsoft.mygoal) 14 | #### Contributing 15 | * Contributions are always welcome 16 | * If you want a feature and can code, feel free to fork and add the change yourself and make a pull request 17 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'kotlin-android' 3 | apply plugin: 'realm-android' 4 | apply plugin: 'kotlin-kapt' 5 | 6 | 7 | android { 8 | compileSdkVersion 25 9 | buildToolsVersion "25.0.2" 10 | defaultConfig { 11 | applicationId "com.vrgsoft.mygoal" 12 | minSdkVersion 16 13 | targetSdkVersion 25 14 | versionCode 1 15 | versionName "1.0" 16 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 17 | vectorDrawables.useSupportLibrary = true 18 | multiDexEnabled true 19 | 20 | } 21 | buildTypes { 22 | release { 23 | minifyEnabled false 24 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 25 | } 26 | } 27 | dataBinding 28 | { 29 | enabled = true; 30 | } 31 | } 32 | 33 | dependencies { 34 | compile fileTree(dir: 'libs', include: ['*.jar']) 35 | 36 | 37 | 38 | def supportVersion = '25.2.0' 39 | 40 | compile("com.android.support:support-v4:$supportVersion") { 41 | force = true; 42 | } 43 | compile("com.android.support:appcompat-v7:$supportVersion") { 44 | force = true; 45 | } 46 | compile("com.android.support:design:$supportVersion") { 47 | force = true; 48 | } 49 | compile("com.android.support:cardview-v7:$supportVersion") { 50 | force = true; 51 | } 52 | compile("com.android.support:recyclerview-v7:$supportVersion") { 53 | force = true; 54 | } 55 | 56 | 57 | 58 | 59 | 60 | compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version" 61 | // sdk19, sdk21, sdk23 are also available 62 | // In case you need support-v4 bindings 63 | // 64 | 65 | 66 | compile('com.philliphsu:bottomsheetpickers:2.3.2') { 67 | exclude group: 'com.android.support', module: 'appcompat-v7' 68 | exclude group: 'com.android.support', module: 'design' 69 | } 70 | compile 'com.google.dagger:dagger:2.9' 71 | compile 'com.github.bumptech.glide:glide:3.7.0' 72 | compile 'com.google.code.gson:gson:2.7' 73 | compile 'io.reactivex.rxjava2:rxjava:2.0.7' 74 | compile 'org.greenrobot:eventbus:3.0.0' 75 | compile 'com.android.support.constraint:constraint-layout:1.0.2' 76 | compile 'com.evernote:android-job:1.1.9' 77 | compile 'com.android.support:support-v4:25.2.0' 78 | compile 'org.jetbrains.anko:anko-sdk23:0.10.0-beta-1' 79 | compile 'org.jetbrains.anko:anko-support-v4:0.10.0-beta-1' 80 | compile 'org.jetbrains.anko:anko-appcompat-v7:0.10.0-beta-1' 81 | compile 'com.squareup.picasso:picasso:2.5.2' 82 | kapt 'com.android.databinding:compiler:2.3.2' 83 | kapt 'com.google.dagger:dagger-compiler:2.9' 84 | provided 'javax.annotation:jsr250-api:1.0' 85 | provided 'org.glassfish:javax.annotation:10.0-b28' 86 | compile 'com.github.zurche:plain-pie:v0.2.2' 87 | compile 'com.android.support:multidex:1.0.1' 88 | } 89 | repositories { 90 | mavenCentral() 91 | } 92 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in D:\AndroidSDK/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | # Uncomment this to preserve the line number information for 20 | # debugging stack traces. 21 | #-keepattributes SourceFile,LineNumberTable 22 | 23 | # If you keep the line number information, uncomment this to 24 | # hide the original source file name. 25 | #-renamesourcefileattribute SourceFile 26 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 13 | 15 | 16 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /app/src/main/ic_menu-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VRGsoftUA/GetGoal/888eb311bfe6f999a6cfd4e6c9a13c415da71f37/app/src/main/ic_menu-web.png -------------------------------------------------------------------------------- /app/src/main/java/com/vrgsoft/mygoal/data/db/alerts/Goal.kt: -------------------------------------------------------------------------------- 1 | package com.vrgsoft.mygoal.data.db.alerts 2 | 3 | 4 | import io.realm.RealmObject 5 | import io.realm.annotations.PrimaryKey 6 | import java.util.concurrent.TimeUnit 7 | 8 | open class Goal : RealmObject() { 9 | @PrimaryKey 10 | var mId: Long = 0 11 | var mTime: Long = 0 12 | var mDescr: String = "" 13 | var mName: String = "" 14 | var mImage: Int = 0 15 | var mLatsDays:Long = System.currentTimeMillis() 16 | var mTwentyOne:Long = TimeUnit.DAYS.toMillis(21) 17 | var lastCheck:Long = System.currentTimeMillis() 18 | 19 | 20 | } 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/java/com/vrgsoft/mygoal/data/db/habits/HabitJob.kt: -------------------------------------------------------------------------------- 1 | package com.vrgsoft.mygoal.data.db.habits 2 | 3 | import com.evernote.android.job.Job 4 | import com.evernote.android.job.JobRequest 5 | 6 | class HabitJob : Job() { 7 | override fun onRunJob(params: Params?): Result { 8 | return Result.SUCCESS 9 | } 10 | 11 | companion object { 12 | val TAG: String = "habit_job_tag" 13 | fun scheduleJob() { 14 | JobRequest.Builder(TAG) 15 | .setExact(System.currentTimeMillis()+3000) 16 | .build() 17 | .schedule() 18 | } 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /app/src/main/java/com/vrgsoft/mygoal/data/db/habits/HabitsRepositoryLocalImp.kt: -------------------------------------------------------------------------------- 1 | package com.vrgsoft.mygoal.data.db.habits 2 | 3 | import com.vrgsoft.mygoal.data.db.alerts.Goal 4 | import com.vrgsoft.mygoal.domain.habits.HabitsRepository 5 | import com.vrgsoft.mygoal.presentation.receivers.AlarmReceiver 6 | import io.reactivex.Observable 7 | import io.realm.Realm 8 | import java.util.concurrent.TimeUnit 9 | import javax.inject.Inject 10 | 11 | 12 | class HabitsRepositoryLocalImp() : HabitsRepository { 13 | lateinit private var mRealm: Realm 14 | 15 | @Inject 16 | constructor(mRealm: Realm) : this() { 17 | this.mRealm = mRealm 18 | } 19 | 20 | override fun saveHabit(goal: Goal) { 21 | mRealm.executeTransaction { 22 | 23 | if(goal.mId == 0.toLong()){ 24 | val currentIdNum = mRealm.where(Goal::class.java).max("mId") 25 | val nextId: Long 26 | if (currentIdNum == null) { 27 | nextId = 1 28 | } else { 29 | nextId = currentIdNum.toLong() + 1 30 | } 31 | goal.mId = nextId 32 | } 33 | 34 | mRealm.copyToRealmOrUpdate(goal) 35 | } 36 | } 37 | 38 | 39 | override fun getGoal(id: Long): Observable { 40 | var goal:Goal = Realm.getDefaultInstance().where(Goal::class.java).equalTo("mId", id).findFirst(); 41 | if(goal == null){ 42 | return Observable.empty(); 43 | }else{ 44 | return Observable.just(Realm.getDefaultInstance().copyFromRealm(goal)) 45 | } 46 | 47 | } 48 | 49 | override fun getGoals(): Observable< List> { 50 | return Observable.just(mRealm.copyFromRealm(mRealm.where(Goal::class.java).findAll())) 51 | } 52 | 53 | fun getGoalById(id : Long): Goal { 54 | return mRealm.where(Goal::class.java).equalTo("mId", id).findFirst() 55 | } 56 | 57 | fun getAllHabits():List{ 58 | var castRealm : Realm = Realm.getDefaultInstance() 59 | return castRealm.where(Goal::class.java).findAll() 60 | } 61 | 62 | fun check(goal: Goal){ 63 | mRealm.beginTransaction() 64 | goal.lastCheck=System.currentTimeMillis() 65 | goal.mTime = goal.mTime+TimeUnit.DAYS.toMillis(1) 66 | mRealm.copyToRealmOrUpdate(goal) 67 | mRealm.commitTransaction() 68 | 69 | 70 | } 71 | 72 | 73 | fun deleteGoalById(goal: Goal){ 74 | mRealm.beginTransaction() 75 | var goalToDel:Goal = mRealm.where(Goal::class.java).equalTo("mId", goal.mId).findFirst() 76 | goalToDel.deleteFromRealm() 77 | mRealm.commitTransaction() 78 | } 79 | } -------------------------------------------------------------------------------- /app/src/main/java/com/vrgsoft/mygoal/domain/habits/HabitInteractor.kt: -------------------------------------------------------------------------------- 1 | 2 | package com.vrgsoft.mygoal.domain.habits 3 | 4 | import com.vrgsoft.mygoal.data.db.alerts.Goal 5 | import com.vrgsoft.mygoal.data.db.habits.HabitsRepositoryLocalImp 6 | import io.reactivex.Observable 7 | import javax.inject.Inject 8 | 9 | class HabitInteractor @Inject constructor(habitsRepositoryLocalImp: HabitsRepositoryLocalImp) { 10 | private val mHabitsRepository: HabitsRepositoryLocalImp = habitsRepositoryLocalImp 11 | 12 | fun saveHabit(habit: Goal) { 13 | mHabitsRepository.saveHabit(habit) 14 | } 15 | 16 | fun getGoal(mId:Long): Observable { 17 | return mHabitsRepository.getGoal(mId) 18 | } 19 | 20 | fun getGoalById(id:Long):Goal{ 21 | return mHabitsRepository.getGoalById(id) 22 | } 23 | 24 | fun getAllHabits():List{ 25 | return mHabitsRepository.getAllHabits() 26 | } 27 | 28 | fun check(goal: Goal){ 29 | mHabitsRepository.check(goal) 30 | } 31 | 32 | fun deleteGoalById(goal: Goal){ 33 | mHabitsRepository.deleteGoalById(goal) 34 | } 35 | } -------------------------------------------------------------------------------- /app/src/main/java/com/vrgsoft/mygoal/domain/habits/HabitRepository.kt: -------------------------------------------------------------------------------- 1 | package com.vrgsoft.mygoal.domain.habits 2 | 3 | import com.vrgsoft.mygoal.data.db.alerts.Goal 4 | import io.reactivex.Observable 5 | 6 | interface HabitRepository { 7 | fun saveHabit(goal: Goal) 8 | fun getGoal(id: Int): Observable 9 | 10 | } -------------------------------------------------------------------------------- /app/src/main/java/com/vrgsoft/mygoal/domain/habits/HabitsInteractor.kt: -------------------------------------------------------------------------------- 1 | package com.vrgsoft.mygoal.domain.habits 2 | 3 | import com.vrgsoft.mygoal.data.db.alerts.Goal 4 | import com.vrgsoft.mygoal.data.db.habits.HabitsRepositoryLocalImp 5 | import io.reactivex.Observable 6 | import javax.inject.Inject 7 | 8 | class HabitsInteractor @Inject constructor(habitsRepositoryLocalImp: HabitsRepositoryLocalImp) { 9 | private val mHabitsRepository: HabitsRepositoryLocalImp = habitsRepositoryLocalImp 10 | 11 | fun getGoals(): Observable> { 12 | return mHabitsRepository.getGoals() 13 | } 14 | 15 | } -------------------------------------------------------------------------------- /app/src/main/java/com/vrgsoft/mygoal/domain/habits/HabitsRepository.kt: -------------------------------------------------------------------------------- 1 | package com.vrgsoft.mygoal.domain.habits 2 | 3 | import com.vrgsoft.mygoal.data.db.alerts.Goal 4 | import io.reactivex.Observable 5 | 6 | interface HabitsRepository { 7 | fun saveHabit(goal: Goal) 8 | fun getGoal(id: Long): Observable 9 | fun getGoals(): Observable< List> 10 | } -------------------------------------------------------------------------------- /app/src/main/java/com/vrgsoft/mygoal/presentation/common/BaseActivity.kt: -------------------------------------------------------------------------------- 1 | package com.vrgsoft.mygoal.presentation.common 2 | 3 | import android.app.Activity 4 | import android.databinding.DataBindingUtil 5 | import android.databinding.ViewDataBinding 6 | import android.os.Bundle 7 | import android.support.v7.app.AppCompatActivity 8 | import android.support.v7.widget.Toolbar 9 | 10 | import com.vrgsoft.mygoal.presentation.injection.App 11 | import com.vrgsoft.mygoal.presentation.injection.ApplicationComponent 12 | 13 | abstract class BaseActivity : AppCompatActivity(), BaseView { 14 | protected var dataBinding: B? = null 15 | private set 16 | 17 | override fun onCreate(savedInstanceState: Bundle?) { 18 | super.onCreate(savedInstanceState) 19 | val cls = javaClass 20 | if (!cls.isAnnotationPresent(Layout::class.java)) { 21 | return 22 | } 23 | val annotation = cls.getAnnotation(Layout::class.java) 24 | dataBinding = DataBindingUtil.setContentView(activity, annotation.id) 25 | initComponent() 26 | } 27 | 28 | fun resolveToolbar(fragment: BaseFragment<*>) { 29 | val toolbar = fragment.toolbar 30 | setSupportActionBar(toolbar) 31 | supportActionBar!!.setDisplayShowTitleEnabled(false) 32 | 33 | } 34 | 35 | fun addFragment(viewGroupId: Int, fragment: BaseFragment<*>) { 36 | supportFragmentManager 37 | .beginTransaction() 38 | .replace(viewGroupId, fragment) 39 | .commit() 40 | } 41 | 42 | abstract fun initComponent() 43 | 44 | abstract val activity: A 45 | override fun onNetworkFailure() { 46 | TODO("not implemented") //To change body of created functions use File | Settings | File Templates. 47 | } 48 | 49 | override fun onRequestFailure() { 50 | TODO("not implemented") //To change body of created functions use File | Settings | File Templates. 51 | } 52 | protected val applicationComponent: ApplicationComponent 53 | get() = App.applicationComponent 54 | } 55 | -------------------------------------------------------------------------------- /app/src/main/java/com/vrgsoft/mygoal/presentation/common/BaseFragment.kt: -------------------------------------------------------------------------------- 1 | package com.vrgsoft.mygoal.presentation.common 2 | 3 | import android.content.DialogInterface 4 | import android.databinding.DataBindingUtil 5 | import android.databinding.ViewDataBinding 6 | import android.os.Bundle 7 | import android.support.v4.app.Fragment 8 | import android.support.v7.app.AlertDialog 9 | import android.support.v7.widget.Toolbar 10 | import android.view.LayoutInflater 11 | import android.view.View 12 | import android.view.ViewGroup 13 | import com.vrgsoft.mygoal.data.db.alerts.Goal 14 | 15 | 16 | import com.vrgsoft.mygoal.presentation.events.BaseEvent 17 | 18 | import org.greenrobot.eventbus.EventBus 19 | import org.greenrobot.eventbus.Subscribe 20 | 21 | abstract class BaseFragment : Fragment(), BaseView { 22 | private var mIsInjected = false 23 | protected var binding: B? = null 24 | private set 25 | 26 | override fun onCreate(savedInstanceState: Bundle?) { 27 | super.onCreate(savedInstanceState) 28 | try { 29 | mIsInjected = onInjectView() 30 | } catch (e: IllegalStateException) { 31 | mIsInjected = false 32 | } 33 | 34 | } 35 | 36 | override fun onViewCreated(view: View?, savedInstanceState: Bundle?) { 37 | super.onViewCreated(view, savedInstanceState) 38 | if (mIsInjected) { 39 | onViewInjected(savedInstanceState) 40 | } 41 | } 42 | 43 | override fun onCreateView(inflater: LayoutInflater?, 44 | container: ViewGroup?, 45 | savedInstanceState: Bundle?): View? { 46 | val cls = javaClass 47 | if (!cls.isAnnotationPresent(Layout::class.java)) { 48 | return null 49 | } 50 | val annotation = cls.getAnnotation(Layout::class.java) 51 | binding = DataBindingUtil.inflate(inflater, annotation.id, container, false) 52 | 53 | return binding!!.root 54 | } 55 | 56 | override fun onActivityCreated(savedInstanceState: Bundle?) { 57 | super.onActivityCreated(savedInstanceState) 58 | if (!mIsInjected) { 59 | mIsInjected = onInjectView() 60 | if (mIsInjected) { 61 | onViewInjected(savedInstanceState) 62 | } 63 | } 64 | initView() 65 | } 66 | 67 | abstract val toolbar: Toolbar? 68 | 69 | abstract fun toolbarNavigationActive(): Boolean 70 | 71 | protected abstract val presenter: BasePresenter 72 | 73 | protected abstract fun initView() 74 | 75 | @Throws(IllegalStateException::class) 76 | protected abstract fun inject() 77 | 78 | @Throws(IllegalStateException::class) 79 | protected fun onInjectView(): Boolean { 80 | inject() 81 | return true 82 | } 83 | 84 | protected fun onViewInjected(savedInstanceState: Bundle?) { 85 | presenter.view = this 86 | } 87 | 88 | override fun onStart() { 89 | super.onStart() 90 | presenter.onStart() 91 | EventBus.getDefault().register(this) 92 | } 93 | 94 | 95 | override fun onStop() { 96 | super.onStop() 97 | presenter.onStop() 98 | EventBus.getDefault().unregister(this) 99 | } 100 | 101 | @Subscribe 102 | fun onEvent(event: BaseEvent) { 103 | 104 | } 105 | 106 | override fun onNetworkFailure() { 107 | //showAlertDialog(getString(R.string.network_failure)); 108 | } 109 | 110 | override fun onRequestFailure() { 111 | //showAlertDialog(getString(R.string.request_error)); 112 | } 113 | 114 | protected fun showAlertDialog(message: String) { 115 | AlertDialog.Builder(context) 116 | .setMessage(message) 117 | .setCancelable(false) 118 | .show() 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /app/src/main/java/com/vrgsoft/mygoal/presentation/common/BasePresenter.kt: -------------------------------------------------------------------------------- 1 | package com.vrgsoft.mygoal.presentation.common 2 | 3 | abstract class BasePresenter { 4 | var view: View? = null 5 | var router: Router? = null 6 | 7 | abstract fun onStart() 8 | 9 | abstract fun onStop() 10 | } -------------------------------------------------------------------------------- /app/src/main/java/com/vrgsoft/mygoal/presentation/common/BaseView.kt: -------------------------------------------------------------------------------- 1 | package com.vrgsoft.mygoal.presentation.common 2 | 3 | interface BaseView { 4 | fun onNetworkFailure() 5 | 6 | fun onRequestFailure() 7 | } 8 | -------------------------------------------------------------------------------- /app/src/main/java/com/vrgsoft/mygoal/presentation/common/CachedValue.kt: -------------------------------------------------------------------------------- 1 | package com.vrgsoft.mygoal.presentation.common 2 | 3 | import android.annotation.SuppressLint 4 | import android.content.SharedPreferences 5 | 6 | class CachedValue(val name: String, private var value: T?, private val defValue: T?, private val type: Class<*>) { 7 | 8 | private var sp: SharedPreferences? = null 9 | private var loaded = false 10 | 11 | constructor(name: String, type: Class<*>) : this(name, null, null, type) {} 12 | 13 | constructor(name: String, defValue: T, type: Class<*>) : this(name, null, defValue, type) {} 14 | 15 | init { 16 | this.sp = sharedPref 17 | this.loaded = value != null 18 | } 19 | 20 | fun setValue(value: T) { 21 | synchronized(lock) { 22 | loaded = true 23 | write(value) 24 | } 25 | } 26 | 27 | fun getValue(): T? { 28 | synchronized(lock) { 29 | if (!loaded) { 30 | this.value = load() 31 | loaded = true 32 | } 33 | return this.value 34 | } 35 | } 36 | 37 | private fun write(value: T) { 38 | val editor = sp!!.edit() 39 | 40 | if (value is String) { 41 | 42 | editor.putString(name, value) 43 | 44 | } else if (value is Int) { 45 | 46 | editor.putInt(name, value) 47 | 48 | } else if (value is Float) { 49 | 50 | editor.putFloat(name, value) 51 | 52 | } else if (value is Long) { 53 | 54 | editor.putLong(name, value) 55 | 56 | } else if (value is Boolean) { 57 | 58 | editor.putBoolean(name, value) 59 | 60 | } 61 | 62 | editor.apply() 63 | } 64 | 65 | @SuppressLint("unchecked") 66 | private fun load(): T? { 67 | 68 | if (type == String::class.java) { 69 | 70 | return sp!!.getString(name, defValue as String?) as T 71 | 72 | } else if (type == Int::class.java) { 73 | 74 | return Integer.valueOf(sp!!.getInt(name, if (defValue != null) (defValue as Int?)!! else 0)) as T 75 | 76 | } else if (type == Float::class.java) { 77 | 78 | return java.lang.Float.valueOf(sp!!.getFloat(name, if (defValue != null) (defValue as Float?)!! else 0F)) as T 79 | 80 | } else if (type == Long::class.java) { 81 | 82 | return java.lang.Long.valueOf(sp!!.getLong(name, if (defValue != null) (defValue as Long?)!! else 0)) as T 83 | 84 | } else if (type == Boolean::class.java) { 85 | 86 | return java.lang.Boolean.valueOf(sp!!.getBoolean(name, if (defValue != null) (defValue as Boolean?)!! else false)) as T 87 | 88 | } 89 | 90 | return null 91 | } 92 | 93 | fun delete() { 94 | synchronized(lock) { 95 | sp!!.edit().remove(name).commit() 96 | clear() 97 | } 98 | } 99 | 100 | fun setSharedPreferences(sp: SharedPreferences) { 101 | this.sp = sp 102 | } 103 | 104 | fun clear() { 105 | synchronized(lock) { 106 | loaded = false 107 | this.value = null 108 | } 109 | } 110 | 111 | companion object { 112 | 113 | private val lock = Any() 114 | 115 | private var sharedPref: SharedPreferences? = null 116 | 117 | fun initialize(sp: SharedPreferences) { 118 | CachedValue.sharedPref = sp 119 | } 120 | } 121 | 122 | } -------------------------------------------------------------------------------- /app/src/main/java/com/vrgsoft/mygoal/presentation/common/Layout.kt: -------------------------------------------------------------------------------- 1 | package com.vrgsoft.mygoal.presentation.common 2 | 3 | import android.support.annotation.LayoutRes 4 | import java.lang.annotation.Retention 5 | import java.lang.annotation.RetentionPolicy 6 | 7 | @Retention(RetentionPolicy.RUNTIME) 8 | @Target(AnnotationTarget.CLASS, AnnotationTarget.FILE) 9 | annotation class Layout(@LayoutRes val id: Int) 10 | -------------------------------------------------------------------------------- /app/src/main/java/com/vrgsoft/mygoal/presentation/common/SettingsHelper.kt: -------------------------------------------------------------------------------- 1 | package com.vrgsoft.mygoal.presentation.common 2 | 3 | import android.content.Context 4 | 5 | 6 | class SettingsHelper { 7 | 8 | 9 | var adsDisabled: CachedValue? = null 10 | var dateReminder: CachedValue? = null 11 | 12 | fun init(context: Context) { 13 | CachedValue.initialize(context.getSharedPreferences(APP_PREFERENCES, Context.MODE_PRIVATE)) 14 | adsDisabled = CachedValue(ADS_DISABLED, false, Boolean::class.java) 15 | dateReminder = CachedValue(REMINDER, 0.toLong(), Long::class.java) 16 | } 17 | 18 | val isAdsDisabled: Boolean 19 | get() = adsDisabled!!.getValue()!! 20 | 21 | fun setDisabledAds(disabled: Boolean) { 22 | adsDisabled!!.setValue(disabled) 23 | } 24 | 25 | 26 | 27 | 28 | fun setReminder(now: Long) { 29 | dateReminder!!.setValue(now) 30 | } 31 | 32 | 33 | 34 | 35 | companion object { 36 | private val APP_PREFERENCES = "DailyBibleInspirations" 37 | private val ADS_DISABLED = "removeAds" 38 | private val REMINDER = "reminder" 39 | 40 | } 41 | } -------------------------------------------------------------------------------- /app/src/main/java/com/vrgsoft/mygoal/presentation/common/view/CheckableButton.kt: -------------------------------------------------------------------------------- 1 | package com.vrgsoft.mygoal.presentation.common.view 2 | 3 | import android.annotation.TargetApi 4 | import android.content.Context 5 | import android.content.res.ColorStateList 6 | import android.content.res.TypedArray 7 | import android.graphics.Canvas 8 | import android.graphics.Color 9 | import android.graphics.Typeface 10 | import android.graphics.drawable.Drawable 11 | import android.graphics.drawable.GradientDrawable 12 | import android.graphics.drawable.RippleDrawable 13 | import android.graphics.drawable.StateListDrawable 14 | import android.os.Build 15 | import android.util.AttributeSet 16 | import android.view.Gravity 17 | import android.view.View 18 | import android.widget.Checkable 19 | import android.widget.LinearLayout 20 | import android.widget.TextView 21 | import com.vrgsoft.mygoal.R 22 | 23 | class CheckableButton : LinearLayout, Checkable { 24 | 25 | 26 | private var mContext: Context? = null 27 | 28 | // # Background Style Attributes 29 | private var checkedBackgroundColor = Color.BLACK 30 | private var uncheckedBackgroundColor = Color.BLACK 31 | /** 32 | * Right Now this is disabled 33 | 34 | * @param mFocusBackgroundColor 35 | */ 36 | var focusBackgroundColor = Color.TRANSPARENT 37 | set(mFocusBackgroundColor) { 38 | field = mFocusBackgroundColor 39 | setupBackground() 40 | } 41 | private var mDisabledBackgroundColor = Color.parseColor("#f6f7f9") 42 | var disabledTextColor = Color.parseColor("#bec2c9") 43 | private var mDisabledBorderColor = Color.parseColor("#dddfe2") 44 | 45 | // # Text Style Attributes 46 | var checkedTextColor = Color.WHITE 47 | private var uncheckedTextColor = Color.WHITE 48 | private val mTextPosition = 1 49 | private var mDefaultTextSize = CheckableUtils.spToPx(context, 15f) 50 | var defaultTextGravity = 0x11 // Gravity.CENTER 51 | private lateinit var mText: String 52 | private val mDefaultTextFont = "" 53 | 54 | private var mBorderColor = Color.TRANSPARENT 55 | private var checkedBorderColor = Color.TRANSPARENT 56 | private var mBorderWidth = 0 57 | private var checkedBorderWidth = 0 58 | private var mTextTypeFace: Typeface?=null 59 | private val disableClick: Boolean = false 60 | 61 | private var mRadius = 0 62 | 63 | private var mTextAllCaps = false 64 | private val isRippleEffect = false 65 | var textView: TextView? = null 66 | private var mListener: OnCheckedChangeListener? = null 67 | private var isChecked: Boolean = false 68 | 69 | constructor(context: Context) : super(context) { 70 | this.mContext = context 71 | mTextTypeFace = CheckableUtils.findFont(context, mDefaultTextFont, null) 72 | init() 73 | } 74 | 75 | constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { 76 | this.mContext = context 77 | val attrsArray = context.obtainStyledAttributes(attrs, R.styleable.CheckableButton, 0, 0) 78 | initAttributesArray(attrs, attrsArray) 79 | attrsArray.recycle() 80 | init() 81 | } 82 | 83 | /** 84 | * Initialize CheckableButton View 85 | */ 86 | private fun init() { 87 | 88 | //Init The container view: LinearLayout 89 | this.orientation = VERTICAL 90 | val containerParams = LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT) 91 | this.layoutParams = containerParams 92 | this.gravity = Gravity.CENTER 93 | this.isClickable = true 94 | this.isFocusable = true 95 | if (paddingLeft == 0 && paddingRight == 0 && paddingTop == 0 && paddingBottom == 0) { 96 | this.setPadding(10, 10, 10, 10) 97 | } 98 | 99 | //init the Textview: 100 | setUpTextView() 101 | setUpTextColorStates() 102 | 103 | setupBackground() 104 | 105 | // for (View view : views) { 106 | //this.addView(mTextView); 107 | //} 108 | setOnClickListener { toggle() } 109 | 110 | if (isChecked) { 111 | setChecked(true) 112 | } 113 | 114 | 115 | } 116 | 117 | private fun setUpTextView() { 118 | if (true) { 119 | textView = TextView(mContext) 120 | textView!!.text = mText 121 | textView!!.gravity = defaultTextGravity 122 | textView!!.setTextColor(if (isChecked()) checkedTextColor else uncheckedTextColor) 123 | textView!!.textSize = CheckableUtils.pxToSp(context, mDefaultTextSize.toFloat()).toFloat() 124 | 125 | textView!!.layoutParams = LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT) 126 | if (!isInEditMode && mTextTypeFace != null) { 127 | textView!!.typeface = mTextTypeFace 128 | } 129 | } 130 | } 131 | 132 | private fun setUpTextColorStates() { 133 | val states = arrayOf(intArrayOf(android.R.attr.state_enabled), // enabled 134 | intArrayOf(-android.R.attr.state_enabled), // disabled 135 | intArrayOf(-android.R.attr.state_checked), // unchecked 136 | intArrayOf(android.R.attr.state_checked), // checked 137 | intArrayOf(android.R.attr.state_pressed) // pressed 138 | ) 139 | 140 | val colors = intArrayOf(checkedTextColor, disabledTextColor, uncheckedTextColor, checkedTextColor, uncheckedTextColor) 141 | 142 | val myList = ColorStateList(states, colors) 143 | 144 | if (textView != null) { 145 | this.addView(textView) 146 | } 147 | } 148 | 149 | private fun initAttributesArray(attrs: AttributeSet, attrsArray: TypedArray) { 150 | 151 | checkedBackgroundColor = attrsArray.getColor(R.styleable.CheckableButton_cb_checkedColor, checkedBackgroundColor) 152 | uncheckedBackgroundColor = attrsArray.getColor(R.styleable.CheckableButton_cb_unCheckColor, uncheckedBackgroundColor) 153 | mDisabledBackgroundColor = attrsArray.getColor(R.styleable.CheckableButton_cb_disabledColor, mDisabledBackgroundColor) 154 | 155 | this.isEnabled = attrs.getAttributeBooleanValue("http://schemas.android.com/apk/res/android", "enabled", true) 156 | 157 | disabledTextColor = attrsArray.getColor(R.styleable.CheckableButton_cb_disabledTextColor, disabledTextColor) 158 | mDisabledBorderColor = attrsArray.getColor(R.styleable.CheckableButton_cb_disabledBorderColor, mDisabledBorderColor) 159 | checkedTextColor = attrsArray.getColor(R.styleable.CheckableButton_cb_checkedTextColor, checkedTextColor) 160 | uncheckedTextColor = attrsArray.getColor(R.styleable.CheckableButton_cb_uncheckedTextColor, uncheckedTextColor) 161 | // if default color is set then the icon's color is the same (the default for icon's color) 162 | isChecked = attrsArray.getBoolean(R.styleable.CheckableButton_cb_isChecked, false) 163 | mDefaultTextSize = attrsArray.getDimension(R.styleable.CheckableButton_cb_textSize, mDefaultTextSize.toFloat()).toInt() 164 | defaultTextGravity = attrsArray.getInt(R.styleable.CheckableButton_cb_textGravity, defaultTextGravity) 165 | 166 | mBorderColor = attrsArray.getColor(R.styleable.CheckableButton_cb_unCheckBorderColor, mBorderColor) 167 | checkedBorderColor = attrsArray.getColor(R.styleable.CheckableButton_cb_checkedBorderColor, checkedBorderColor) 168 | mBorderWidth = attrsArray.getDimension(R.styleable.CheckableButton_cb_borderWidth, mBorderWidth.toFloat()).toInt() 169 | checkedBorderWidth = attrsArray.getDimension(R.styleable.CheckableButton_cb_checkedborderWidth, checkedBorderWidth.toFloat()).toInt() 170 | 171 | mRadius = attrsArray.getDimension(R.styleable.CheckableButton_cb_radius, mRadius.toFloat()).toInt() 172 | 173 | mTextAllCaps = attrsArray.getBoolean(R.styleable.CheckableButton_cb_textAllCaps, false) 174 | 175 | val text = attrsArray.getString(R.styleable.CheckableButton_cb_text) 176 | if (text != null) 177 | mText = if (mTextAllCaps) text.toUpperCase() else text 178 | } 179 | 180 | /** 181 | * Uses the backgroud color of the unchecked state to create a lighter color 182 | * to be used for the focusable drawable 183 | 184 | * @param color 185 | * * 186 | * @return 187 | */ 188 | private fun lightenColor(color: Int): Int { 189 | val hsv = FloatArray(3) 190 | val mColor: Int 191 | Color.colorToHSV(color, hsv) 192 | 193 | hsv[2] = 1.0f - 0.8f * (1.0f - hsv[2]) 194 | mColor = Color.HSVToColor(hsv) 195 | return mColor 196 | } 197 | 198 | /** 199 | * SETup container's background 200 | * assign drawable states 201 | */ 202 | private fun setupBackground() { 203 | 204 | // Default Drawable 205 | val defaultDrawable = GradientDrawable() 206 | defaultDrawable.cornerRadius = mRadius.toFloat() 207 | defaultDrawable.setColor(uncheckedBackgroundColor) 208 | 209 | //Focus Drawable 210 | lightenColor(uncheckedBackgroundColor) 211 | val focusDrawable = GradientDrawable() 212 | focusDrawable.cornerRadius = mRadius.toFloat() 213 | focusDrawable.setColor(focusBackgroundColor) 214 | 215 | // Disabled Drawable 216 | val disabledDrawable = GradientDrawable() 217 | disabledDrawable.cornerRadius = mRadius.toFloat() 218 | disabledDrawable.setColor(mDisabledBackgroundColor) 219 | disabledDrawable.setStroke(mBorderWidth, mDisabledBorderColor) 220 | 221 | // Disabled Drawable disabled 222 | val disabledDrawable2 = GradientDrawable() 223 | disabledDrawable2.cornerRadius = mRadius.toFloat() 224 | disabledDrawable2.setColor(mDisabledBackgroundColor) 225 | disabledDrawable2.setStroke(mBorderWidth, mDisabledBorderColor) 226 | 227 | // checked Drawable 228 | val drawable3 = GradientDrawable() 229 | drawable3.cornerRadius = mRadius.toFloat() 230 | drawable3.setColor(checkedBackgroundColor) 231 | 232 | 233 | // Handle Border 234 | if (mBorderColor != 0) { 235 | defaultDrawable.setStroke(mBorderWidth, mBorderColor) 236 | disabledDrawable.setStroke(mBorderWidth, mBorderColor) 237 | } 238 | if (checkedBorderColor != 0) { 239 | drawable3.setStroke(checkedBorderWidth, checkedBorderColor) 240 | disabledDrawable2.setStroke(mBorderWidth, checkedBorderColor) 241 | } 242 | 243 | // Handle disabled border color 244 | if (!isEnabled) { 245 | defaultDrawable.setStroke(mBorderWidth, mDisabledBorderColor) 246 | } 247 | 248 | 249 | if (isRippleEffect && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 250 | this.background = getRippleDrawable(defaultDrawable, focusDrawable, disabledDrawable) 251 | 252 | } else { 253 | 254 | val states = StateListDrawable() 255 | // Focus/Pressed Drawable 256 | val drawable2 = GradientDrawable() 257 | drawable2.cornerRadius = mRadius.toFloat() 258 | drawable2.setColor(focusBackgroundColor) 259 | 260 | // Handle Button Border 261 | if (mBorderColor != 0) { 262 | drawable2.setStroke(mBorderWidth, mBorderColor) 263 | } 264 | 265 | if (!isEnabled) { 266 | drawable2.setStroke(mBorderWidth, mDisabledBorderColor) 267 | } 268 | 269 | if (focusBackgroundColor != 0) { 270 | states.addState(intArrayOf(android.R.attr.state_pressed), drawable2) 271 | states.addState(intArrayOf(android.R.attr.state_focused), drawable2) 272 | states.addState(intArrayOf(-android.R.attr.state_enabled), disabledDrawable) 273 | states.addState(intArrayOf(-android.R.attr.state_enabled, -android.R.attr.state_checked), disabledDrawable2) 274 | } 275 | if (checkedBackgroundColor != 0) { 276 | states.addState(intArrayOf(android.R.attr.state_checked), drawable3) 277 | states.addState(intArrayOf(-android.R.attr.state_checked), defaultDrawable) 278 | } 279 | states.addState(intArrayOf(), defaultDrawable) 280 | 281 | 282 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { 283 | this.setBackgroundDrawable(states) 284 | } else { 285 | this.background = states 286 | } 287 | 288 | } 289 | } 290 | 291 | 292 | @TargetApi(Build.VERSION_CODES.LOLLIPOP) 293 | private fun getRippleDrawable(defaultDrawable: Drawable, focusDrawable: Drawable, disabledDrawable: Drawable): Drawable { 294 | if (!isEnabled) { 295 | return disabledDrawable 296 | } else { 297 | return RippleDrawable(ColorStateList.valueOf(focusBackgroundColor), defaultDrawable, focusDrawable) 298 | } 299 | 300 | } 301 | 302 | override fun setChecked(checked: Boolean) { 303 | if (isChecked && !checked) { 304 | switchToHide() 305 | isChecked = false 306 | } else if (!isChecked && checked) { 307 | switchToCheck() 308 | isChecked = true 309 | } 310 | textView!!.setTextColor(if (checked) checkedTextColor else uncheckedTextColor) 311 | refreshDrawableState() 312 | if (mListener != null) { 313 | mListener!!.onCheckedChanged(this, checked) 314 | } 315 | } 316 | 317 | private fun switchToCheck() { 318 | //Might apply checked animations in the future 319 | //invalidate(); 320 | } 321 | 322 | private fun switchToHide() { 323 | //Might apply checked animations in the future 324 | // invalidate(); 325 | } 326 | 327 | 328 | override fun onDraw(canvas: Canvas) { 329 | super.onDraw(canvas) 330 | } 331 | 332 | public override fun onCreateDrawableState(extraSpace: Int): IntArray { 333 | val drawableState = super.onCreateDrawableState(extraSpace + 1) 334 | if (isChecked()) { 335 | View.mergeDrawableStates(drawableState, CHECKED_STATE_SET) 336 | } 337 | return drawableState 338 | } 339 | 340 | override fun isChecked(): Boolean { 341 | return isChecked 342 | } 343 | 344 | override fun toggle() { 345 | this.setChecked(!isChecked()) 346 | } 347 | 348 | fun setOnCheckChangeLisnter(onCheckChangeListener: OnCheckedChangeListener) { 349 | mListener = onCheckChangeListener 350 | } 351 | 352 | interface OnCheckedChangeListener { 353 | fun onCheckedChanged(buttonView: View, isChecked: Boolean) 354 | } 355 | 356 | fun getCheckedBackgroundColor(): Int { 357 | return checkedBackgroundColor 358 | } 359 | 360 | fun setCheckedBackgroundColor(checkedBackgroundColor: Int) { 361 | this.checkedBackgroundColor = checkedBackgroundColor 362 | setupBackground() 363 | } 364 | 365 | fun getUncheckedBackgroundColor(): Int { 366 | return uncheckedBackgroundColor 367 | } 368 | 369 | fun setUncheckedBackgroundColor(uncheckedBackgroundColor: Int) { 370 | this.uncheckedBackgroundColor = uncheckedBackgroundColor 371 | setupBackground() 372 | } 373 | 374 | var disabledBackgroundColor: Int 375 | get() = mDisabledBackgroundColor 376 | set(mDisabledBackgroundColor) { 377 | this.mDisabledBackgroundColor = mDisabledBackgroundColor 378 | setupBackground() 379 | } 380 | 381 | var disabledBorderColor: Int 382 | get() = mDisabledBorderColor 383 | set(mDisabledBorderColor) { 384 | this.mDisabledBorderColor = mDisabledBorderColor 385 | setupBackground() 386 | } 387 | 388 | fun getUncheckedTextColor(): Int { 389 | return uncheckedTextColor 390 | } 391 | 392 | fun setUncheckedTextColor(uncheckedTextColor: Int) { 393 | this.uncheckedTextColor = uncheckedTextColor 394 | setupBackground() 395 | } 396 | 397 | var defaultTextSize: Int 398 | get() = mDefaultTextSize 399 | set(mDefaultTextSize) { 400 | this.mDefaultTextSize = CheckableUtils.spToPx(context, mDefaultTextSize.toFloat()) 401 | } 402 | 403 | var text: String 404 | get() = mText 405 | set(text) = if (textView != null) 406 | this.textView!!.text = text 407 | else 408 | mText = text 409 | 410 | var borderColor: Int 411 | get() = mBorderColor 412 | set(mBorderColor) { 413 | this.mBorderColor = mBorderColor 414 | setupBackground() 415 | } 416 | 417 | fun getCheckedBorderColor(): Int { 418 | return checkedBorderColor 419 | } 420 | 421 | fun setCheckedBorderColor(checkedBorderColor: Int) { 422 | this.checkedBorderColor = checkedBorderColor 423 | setupBackground() 424 | } 425 | 426 | var borderWidth: Int 427 | get() = mBorderWidth 428 | set(mBorderWidth) { 429 | this.mBorderWidth = mBorderWidth 430 | setupBackground() 431 | } 432 | 433 | fun getCheckedBorderWidth(): Int { 434 | return checkedBorderWidth 435 | } 436 | 437 | fun setCheckedBorderWidth(checkedBorderWidth: Int) { 438 | this.checkedBorderWidth = checkedBorderWidth 439 | setupBackground() 440 | } 441 | 442 | var radius: Int 443 | get() = mRadius 444 | set(mRadius) { 445 | this.mRadius = mRadius 446 | setupBackground() 447 | } 448 | 449 | companion object { 450 | private val CHECKED_STATE_SET = intArrayOf(android.R.attr.state_checked) 451 | } 452 | } -------------------------------------------------------------------------------- /app/src/main/java/com/vrgsoft/mygoal/presentation/common/view/CheckableUtils.kt: -------------------------------------------------------------------------------- 1 | package com.vrgsoft.mygoal.presentation.common.view 2 | 3 | import android.content.Context 4 | import android.content.res.AssetManager 5 | import android.graphics.Typeface 6 | import android.text.TextUtils 7 | 8 | import java.io.File 9 | import java.util.Arrays 10 | import java.util.HashMap 11 | 12 | object CheckableUtils { 13 | private val cachedFontMap = HashMap() 14 | 15 | fun pxToSp(context: Context, px: Float): Int { 16 | return Math.round(px / context.resources.displayMetrics.scaledDensity) 17 | } 18 | 19 | fun spToPx(context: Context, sp: Float): Int { 20 | return Math.round(sp * context.resources.displayMetrics.scaledDensity) 21 | } 22 | 23 | fun findFont(context: Context, fontPath: String?, defaultFontPath: String?): Typeface? { 24 | 25 | if (fontPath == null) { 26 | return Typeface.DEFAULT 27 | } 28 | 29 | val fontName = File(fontPath).name 30 | var defaultFontName = "" 31 | if (!TextUtils.isEmpty(defaultFontPath)) { 32 | defaultFontName = File(defaultFontPath).name 33 | } 34 | 35 | if (cachedFontMap.containsKey(fontName)) { 36 | return cachedFontMap[fontName] 37 | } else { 38 | try { 39 | val assets = context.resources.assets 40 | 41 | if (Arrays.asList(*assets.list("")).contains(fontPath)) { 42 | val typeface = Typeface.createFromAsset(context.assets, fontName) 43 | cachedFontMap.put(fontName, typeface) 44 | return typeface 45 | } else if (Arrays.asList(*assets.list("fonts")).contains(fontName)) { 46 | val typeface = Typeface.createFromAsset(context.assets, String.format("fonts/%s", fontName)) 47 | cachedFontMap.put(fontName, typeface) 48 | return typeface 49 | } else if (Arrays.asList(*assets.list("iconfonts")).contains(fontName)) { 50 | val typeface = Typeface.createFromAsset(context.assets, String.format("iconfonts/%s", fontName)) 51 | cachedFontMap.put(fontName, typeface) 52 | return typeface 53 | } else if (!TextUtils.isEmpty(defaultFontPath) && Arrays.asList(*assets.list("")).contains(defaultFontPath)) { 54 | val typeface = Typeface.createFromAsset(context.assets, defaultFontPath) 55 | cachedFontMap.put(defaultFontName, typeface) 56 | return typeface 57 | } else { 58 | throw Exception("Font not Found") 59 | } 60 | 61 | } catch (e: Exception) { 62 | return Typeface.DEFAULT 63 | } 64 | 65 | } 66 | 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /app/src/main/java/com/vrgsoft/mygoal/presentation/events/BaseEvent.kt: -------------------------------------------------------------------------------- 1 | package com.vrgsoft.mygoal.presentation.events 2 | 3 | interface BaseEvent -------------------------------------------------------------------------------- /app/src/main/java/com/vrgsoft/mygoal/presentation/injection/AddHabitComponent.kt: -------------------------------------------------------------------------------- 1 | package com.vrgsoft.mygoal.presentation.injection 2 | 3 | import com.vrgsoft.mygoal.presentation.main.addhabit.AddHabitActivity 4 | import com.vrgsoft.mygoal.presentation.main.addhabit.AddHabitFragment 5 | import com.vrgsoft.mygoal.presentation.main.habits.HabitsActivity 6 | import com.vrgsoft.mygoal.presentation.main.showhabit.ShowHabitFragment 7 | import dagger.Component 8 | 9 | @PerActivity 10 | @Component(dependencies = arrayOf(ApplicationComponent::class)) 11 | interface AddHabitComponent { 12 | fun inject(habitsActivity: AddHabitActivity) 13 | fun inject(habitsActivity: AddHabitFragment) 14 | fun inject(habitsActivity: ShowHabitFragment) 15 | } -------------------------------------------------------------------------------- /app/src/main/java/com/vrgsoft/mygoal/presentation/injection/App.kt: -------------------------------------------------------------------------------- 1 | package com.vrgsoft.mygoal.presentation.injection 2 | 3 | import android.content.Context 4 | import android.support.multidex.MultiDex 5 | import android.support.multidex.MultiDexApplication 6 | import com.vrgsoft.mygoal.presentation.common.SettingsHelper 7 | import io.realm.Realm 8 | import io.realm.RealmConfiguration 9 | 10 | 11 | 12 | 13 | class App : MultiDexApplication(), HasComponent { 14 | 15 | 16 | companion object { 17 | lateinit var applicationComponent: ApplicationComponent 18 | var settings: SettingsHelper = SettingsHelper() 19 | 20 | } 21 | 22 | override fun onCreate() { 23 | super.onCreate() 24 | settings.init(this) 25 | Realm.init(applicationContext) 26 | initializeInjector() 27 | initRealmConfiguration() 28 | // settings.setDisabledAds(false)//disable ads 29 | } 30 | 31 | 32 | 33 | 34 | private fun initializeInjector() { 35 | applicationComponent = DaggerApplicationComponent.builder() 36 | .applicationModule(ApplicationModule(this)) 37 | .dataModule(DataModule()) 38 | .domainModule(DomainModule()).build(); 39 | } 40 | 41 | private fun initRealmConfiguration() { 42 | val realmConfiguration = RealmConfiguration.Builder() 43 | .deleteRealmIfMigrationNeeded() 44 | .build() 45 | Realm.setDefaultConfiguration(realmConfiguration) 46 | } 47 | 48 | override val component: ApplicationComponent 49 | get() = applicationComponent 50 | 51 | override fun attachBaseContext(base: Context) { 52 | super.attachBaseContext(base) 53 | MultiDex.install(this) 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /app/src/main/java/com/vrgsoft/mygoal/presentation/injection/ApplicationComponent.kt: -------------------------------------------------------------------------------- 1 | package com.vrgsoft.mygoal.presentation.injection 2 | 3 | import javax.inject.Singleton 4 | 5 | import dagger.Component 6 | import io.realm.Realm 7 | 8 | @Singleton 9 | @Component(modules = arrayOf(ApplicationModule::class, DataModule::class, DomainModule::class)) 10 | interface ApplicationComponent { 11 | fun provideRealm(): Realm 12 | } 13 | -------------------------------------------------------------------------------- /app/src/main/java/com/vrgsoft/mygoal/presentation/injection/ApplicationModule.kt: -------------------------------------------------------------------------------- 1 | package com.vrgsoft.mygoal.presentation.injection 2 | 3 | import android.app.Application 4 | import android.content.Context 5 | import android.content.SharedPreferences 6 | import android.preference.PreferenceManager 7 | import com.vrgsoft.mygoal.data.db.habits.HabitsRepositoryLocalImp 8 | import com.vrgsoft.mygoal.domain.habits.HabitsRepository 9 | 10 | import javax.inject.Singleton 11 | 12 | import dagger.Module 13 | import dagger.Provides 14 | 15 | @Module 16 | class ApplicationModule(private val mApplication: Application) { 17 | 18 | @Provides 19 | @Singleton 20 | fun provideContext(): Context { 21 | return mApplication.applicationContext 22 | } 23 | 24 | @Provides 25 | @Singleton 26 | fun provideSharedPreferences(context: Context): SharedPreferences { 27 | return PreferenceManager.getDefaultSharedPreferences(context) 28 | } 29 | 30 | @Provides 31 | @Singleton 32 | fun provideHabitRepositoryLocal(): HabitsRepository { 33 | return HabitsRepositoryLocalImp() 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /app/src/main/java/com/vrgsoft/mygoal/presentation/injection/DataModule.kt: -------------------------------------------------------------------------------- 1 | package com.vrgsoft.mygoal.presentation.injection 2 | 3 | import dagger.Module 4 | import dagger.Provides 5 | import io.realm.Realm 6 | 7 | @Module 8 | class DataModule { 9 | @Provides 10 | fun provideRealm(): Realm { 11 | return Realm.getDefaultInstance() 12 | } 13 | 14 | 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/com/vrgsoft/mygoal/presentation/injection/DomainModule.kt: -------------------------------------------------------------------------------- 1 | package com.vrgsoft.mygoal.presentation.injection 2 | 3 | import dagger.Module 4 | 5 | @Module 6 | class DomainModule 7 | -------------------------------------------------------------------------------- /app/src/main/java/com/vrgsoft/mygoal/presentation/injection/HabitsComponent.kt: -------------------------------------------------------------------------------- 1 | package com.vrgsoft.mygoal.presentation.injection 2 | 3 | import com.vrgsoft.mygoal.presentation.main.habits.HabitsActivity 4 | import com.vrgsoft.mygoal.presentation.main.habits.HabitsFragment 5 | import dagger.Component 6 | import javax.inject.Singleton 7 | 8 | @PerActivity 9 | @Component(dependencies = arrayOf(ApplicationComponent::class)) 10 | interface HabitsComponent { 11 | fun inject(habitsActivity: HabitsActivity) 12 | fun inject(fragment: HabitsFragment) 13 | } -------------------------------------------------------------------------------- /app/src/main/java/com/vrgsoft/mygoal/presentation/injection/HasComponent.kt: -------------------------------------------------------------------------------- 1 | package com.vrgsoft.mygoal.presentation.injection 2 | 3 | interface HasComponent { 4 | val component: C 5 | } 6 | -------------------------------------------------------------------------------- /app/src/main/java/com/vrgsoft/mygoal/presentation/injection/PerActivity.kt: -------------------------------------------------------------------------------- 1 | package com.vrgsoft.mygoal.presentation.injection 2 | 3 | import java.lang.annotation.Retention 4 | import java.lang.annotation.RetentionPolicy 5 | 6 | import javax.inject.Scope 7 | 8 | @Scope 9 | @Retention(RetentionPolicy.RUNTIME) 10 | annotation class PerActivity -------------------------------------------------------------------------------- /app/src/main/java/com/vrgsoft/mygoal/presentation/main/SplashActivity.kt: -------------------------------------------------------------------------------- 1 | package com.vrgsoft.mygoal.presentation.main 2 | 3 | import android.content.Intent 4 | import android.support.v7.app.AppCompatActivity 5 | import android.os.Bundle 6 | import android.view.View 7 | import android.view.Window 8 | import android.view.WindowManager 9 | import android.view.animation.Animation 10 | import android.view.animation.AnimationUtils 11 | import android.widget.ImageView 12 | 13 | import com.vrgsoft.mygoal.R 14 | import com.vrgsoft.mygoal.presentation.main.habits.HabitsActivity 15 | 16 | class SplashActivity : AppCompatActivity() { 17 | 18 | lateinit var ivSplashCircle:ImageView 19 | 20 | override fun onCreate(savedInstanceState: Bundle?) { 21 | super.onCreate(savedInstanceState) 22 | requestWindowFeature(Window.FEATURE_NO_TITLE) 23 | window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, 24 | WindowManager.LayoutParams.FLAG_FULLSCREEN) 25 | setContentView(R.layout.activity_splash) 26 | setContentView(R.layout.activity_splash) 27 | window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN 28 | 29 | ivSplashCircle = findViewById(R.id.iv_cirlce) as ImageView 30 | 31 | val animation = AnimationUtils.loadAnimation(this, R.anim.move_anim) 32 | animation.setAnimationListener(object : Animation.AnimationListener { 33 | override fun onAnimationStart(animation: Animation) { 34 | 35 | } 36 | 37 | override fun onAnimationEnd(animation: Animation) { 38 | startActivity(Intent(this@SplashActivity, HabitsActivity::class.java)) 39 | finish() 40 | } 41 | 42 | override fun onAnimationRepeat(animation: Animation) { 43 | 44 | } 45 | }) 46 | ivSplashCircle.startAnimation(animation) 47 | 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /app/src/main/java/com/vrgsoft/mygoal/presentation/main/addhabit/AddHabitActivity.kt: -------------------------------------------------------------------------------- 1 | package com.vrgsoft.mygoal.presentation.main.addhabit 2 | 3 | import android.os.Bundle 4 | 5 | import com.vrgsoft.mygoal.R 6 | import com.vrgsoft.mygoal.databinding.ActivityAddHabitBinding 7 | import com.vrgsoft.mygoal.presentation.common.BaseActivity 8 | import com.vrgsoft.mygoal.presentation.common.Layout 9 | import com.vrgsoft.mygoal.presentation.injection.AddHabitComponent 10 | import com.vrgsoft.mygoal.presentation.injection.DaggerAddHabitComponent 11 | import com.vrgsoft.mygoal.presentation.main.habits.common.themedialog.OnThemeChooseCallBack 12 | import com.vrgsoft.mygoal.presentation.main.habits.common.themedialog.ThemeViewModel 13 | import com.vrgsoft.mygoal.presentation.main.showhabit.ShowHabitFragment 14 | 15 | @Layout(id = R.layout.activity_add_habit) 16 | class AddHabitActivity : BaseActivity(), OnThemeChooseCallBack { 17 | lateinit var addHabitComponent: AddHabitComponent 18 | lateinit var addHabitFragment: AddHabitFragment 19 | 20 | lateinit var showHabitFragment: ShowHabitFragment 21 | val NEW_EXTRA: String = "new_extra" 22 | val ID_EXTRA: String = "id_extra" 23 | override fun initComponent() { 24 | addHabitComponent = DaggerAddHabitComponent.builder() 25 | .applicationComponent(applicationComponent) 26 | .build() 27 | } 28 | 29 | override val activity: AddHabitActivity 30 | get() = this 31 | 32 | override fun onCreate(savedInstanceState: Bundle?) { 33 | super.onCreate(savedInstanceState) 34 | if (intent.getBooleanExtra(NEW_EXTRA, true)) { 35 | addHabitFragment = AddHabitFragment.newInstance(intent.getLongExtra(ID_EXTRA, 0)) 36 | supportFragmentManager.beginTransaction().replace(R.id.container, addHabitFragment).commit() 37 | } else { 38 | showHabitFragment = ShowHabitFragment.newInstance(intent.getLongExtra(ID_EXTRA, 0)) 39 | supportFragmentManager.beginTransaction().replace(R.id.container, showHabitFragment).commit() 40 | } 41 | } 42 | 43 | override fun onThemeClick(themeViewModel: ThemeViewModel) { 44 | addHabitFragment.setThemeImage(themeViewModel) 45 | } 46 | 47 | fun showEditFragment() { 48 | addHabitFragment = AddHabitFragment.newInstance(intent.getLongExtra(ID_EXTRA, 0)) 49 | supportFragmentManager.beginTransaction().replace(R.id.container, addHabitFragment).commit() 50 | } 51 | 52 | 53 | } 54 | -------------------------------------------------------------------------------- /app/src/main/java/com/vrgsoft/mygoal/presentation/main/addhabit/AddHabitFragment.kt: -------------------------------------------------------------------------------- 1 | package com.vrgsoft.mygoal.presentation.main.addhabit 2 | 3 | 4 | import android.annotation.SuppressLint 5 | import android.app.DialogFragment 6 | import android.os.Bundle 7 | 8 | import android.support.v7.widget.Toolbar 9 | import com.vrgsoft.mygoal.R 10 | import com.vrgsoft.mygoal.data.db.alerts.Goal 11 | import com.vrgsoft.mygoal.databinding.FragmentAddHabitBinding 12 | import com.vrgsoft.mygoal.presentation.common.BaseFragment 13 | import com.vrgsoft.mygoal.presentation.common.BasePresenter 14 | import com.vrgsoft.mygoal.presentation.common.BaseView 15 | import com.vrgsoft.mygoal.presentation.common.Layout 16 | import org.jetbrains.anko.onClick 17 | import javax.inject.Inject 18 | import android.text.format.DateFormat 19 | import android.view.ViewGroup 20 | import com.philliphsu.bottomsheetpickers.time.BottomSheetTimePickerDialog 21 | import com.philliphsu.bottomsheetpickers.time.grid.GridTimePickerDialog 22 | import com.squareup.picasso.Picasso 23 | import com.vrgsoft.mygoal.presentation.main.habits.common.themedialog.ThemeDialogFragment 24 | import com.vrgsoft.mygoal.presentation.main.habits.common.themedialog.ThemeViewModel 25 | import com.vrgsoft.mygoal.presentation.receivers.AlarmReceiver 26 | import org.jetbrains.anko.imageResource 27 | import java.text.SimpleDateFormat 28 | 29 | import java.util.* 30 | import java.util.concurrent.TimeUnit 31 | 32 | 33 | @Layout(id = R.layout.fragment_add_habit) 34 | class AddHabitFragment : BaseFragment(), AddHabitView, BottomSheetTimePickerDialog.OnTimeSetListener { 35 | 36 | 37 | lateinit var themeDialog: DialogFragment 38 | var chosenTime: Long = Calendar.getInstance().timeInMillis 39 | var chosenTheme: Int = R.drawable.other_icon 40 | val EMOJI_TAG: String = "EmojiDialog" 41 | val DIALOG_TAG: String = "Dialog" 42 | override fun onTimeSet(viewGroup: ViewGroup?, hourOfDay: Int, minute: Int) { 43 | val cal: GregorianCalendar = GregorianCalendar() 44 | cal.set(Calendar.HOUR_OF_DAY, hourOfDay) 45 | cal.set(Calendar.MINUTE, minute) 46 | binding!!.notifyTime.text = DateFormat.getTimeFormat(context).format(cal.time) 47 | chosenTime = if (cal.timeInMillis <= System.currentTimeMillis()) cal.timeInMillis + TimeUnit.DAYS.toMillis(1) else cal.timeInMillis 48 | 49 | } 50 | 51 | companion object { 52 | val ID_EXTRA: String = "id_extra" 53 | fun newInstance(mId: Long): AddHabitFragment { 54 | val mBundl: Bundle = Bundle() 55 | mBundl.putLong(ID_EXTRA, mId) 56 | val fragment: AddHabitFragment = AddHabitFragment() 57 | fragment.arguments = mBundl 58 | return fragment 59 | } 60 | } 61 | 62 | @Inject 63 | lateinit var mHabitPresenter: AddHabitPresenter 64 | override val toolbar: Toolbar? 65 | get() = null 66 | 67 | override fun onActivityCreated(savedInstanceState: Bundle?) { 68 | super.onActivityCreated(savedInstanceState) 69 | if (this.arguments.getLong(ID_EXTRA, 0) == 0.toLong()) { 70 | initView() 71 | } else { 72 | mHabitPresenter.getGoal(this.arguments.getLong(ID_EXTRA, 0)) 73 | } 74 | } 75 | 76 | override fun toolbarNavigationActive(): Boolean { 77 | return false 78 | } 79 | 80 | override val presenter: BasePresenter 81 | get() = mHabitPresenter as BasePresenter 82 | 83 | override fun initView() { 84 | 85 | val currentTime: String = SimpleDateFormat("HH:mm").format(Calendar.getInstance().time) 86 | binding!!.notifyTime.text = currentTime 87 | if (binding!!.checkBox.isChecked) { 88 | chosenTime = System.currentTimeMillis() + TimeUnit.DAYS.toMillis(1) 89 | } else { 90 | chosenTime = 0 91 | } 92 | binding!!.saveHabit.onClick { 93 | 94 | mHabitPresenter.saveHabit(binding!!.habitName.editText!!.text.toString(), 95 | binding!!.habitDescription.editText!!.text.toString(), chosenTime, chosenTheme, this.arguments.getLong(ID_EXTRA, 0)) 96 | 97 | if (binding!!.checkBox.isChecked) { 98 | AlarmReceiver.updateDailyReminder(context) 99 | } 100 | 101 | activity.finish() 102 | } 103 | 104 | 105 | binding!!.notifyTime.onClick { 106 | GridTimePickerDialog.newInstance(this, Calendar.getInstance().get(Calendar.HOUR_OF_DAY), 107 | Calendar.getInstance().get(Calendar.MINUTE), DateFormat.is24HourFormat(context)).show(activity.supportFragmentManager, DIALOG_TAG) 108 | 109 | } 110 | 111 | 112 | binding!!.emoji.onClick { 113 | 114 | themeDialog = ThemeDialogFragment().newInstance() 115 | themeDialog.show(activity.fragmentManager, EMOJI_TAG) 116 | } 117 | 118 | 119 | } 120 | 121 | override fun setGoal(goal: Goal) { 122 | 123 | binding!!.goal = goal 124 | Picasso.with(context).load(goal.mImage).into(binding!!.emoji) 125 | if (goal.mTime != 0.toLong()) { 126 | val currentTime: String = SimpleDateFormat("HH:mm").format(goal.mTime) 127 | binding!!.notifyTime.text = currentTime 128 | } 129 | 130 | } 131 | 132 | override fun inject() { 133 | val habitsComponent = (activity as AddHabitActivity).addHabitComponent 134 | habitsComponent.inject(this) 135 | } 136 | 137 | fun setThemeImage(themeViewModel: ThemeViewModel) { 138 | binding!!.emoji.imageResource = themeViewModel.ivTheme 139 | chosenTheme = themeViewModel.ivTheme 140 | themeDialog.dismiss() 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /app/src/main/java/com/vrgsoft/mygoal/presentation/main/addhabit/AddHabitPresenter.kt: -------------------------------------------------------------------------------- 1 | package com.vrgsoft.mygoal.presentation.main.addhabit 2 | 3 | import com.vrgsoft.mygoal.data.db.alerts.Goal 4 | import com.vrgsoft.mygoal.domain.habits.HabitInteractor 5 | import com.vrgsoft.mygoal.presentation.common.BasePresenter 6 | import com.vrgsoft.mygoal.presentation.main.habits.HabitsRouter 7 | import javax.inject.Inject 8 | 9 | class AddHabitPresenter @Inject constructor(habitsInteractor: HabitInteractor) : BasePresenter() { 10 | val mHabitInteractor: HabitInteractor = habitsInteractor 11 | 12 | override fun onStart() { 13 | 14 | } 15 | 16 | override fun onStop() { 17 | } 18 | 19 | fun saveHabit(habitName: String, habitDescr: String, time:Long, theme:Int, id :Long) { 20 | val goal: Goal = Goal() 21 | goal.mId = id 22 | goal.mDescr = habitDescr 23 | goal.mName = habitName 24 | goal.mTime = time 25 | goal.mImage = theme 26 | mHabitInteractor.saveHabit(goal) 27 | } 28 | 29 | fun getGoal(mId: Long) { 30 | mHabitInteractor.getGoal(mId).subscribe({ goal: Goal -> view!!.setGoal(goal) }, Throwable::printStackTrace) 31 | } 32 | 33 | fun getGoalBuId(id:Long):Goal{ 34 | return mHabitInteractor.getGoalById(id) 35 | } 36 | 37 | fun getAllHabits():List{ 38 | return mHabitInteractor.getAllHabits() 39 | } 40 | 41 | 42 | } 43 | -------------------------------------------------------------------------------- /app/src/main/java/com/vrgsoft/mygoal/presentation/main/addhabit/AddHabitView.kt: -------------------------------------------------------------------------------- 1 | package com.vrgsoft.mygoal.presentation.main.addhabit 2 | 3 | import com.vrgsoft.mygoal.data.db.alerts.Goal 4 | import com.vrgsoft.mygoal.presentation.common.BaseView 5 | 6 | interface AddHabitView : BaseView { 7 | fun setGoal(goal: Goal) 8 | } -------------------------------------------------------------------------------- /app/src/main/java/com/vrgsoft/mygoal/presentation/main/habits/HabitsActivity.kt: -------------------------------------------------------------------------------- 1 | package com.vrgsoft.mygoal.presentation.main.habits 2 | 3 | import android.content.Intent 4 | import android.os.Bundle 5 | import com.vrgsoft.mygoal.R 6 | import com.vrgsoft.mygoal.databinding.ActivityHabitsBinding 7 | import com.vrgsoft.mygoal.presentation.common.BaseActivity 8 | import com.vrgsoft.mygoal.presentation.common.Layout 9 | import com.vrgsoft.mygoal.presentation.injection.DaggerHabitsComponent 10 | import com.vrgsoft.mygoal.presentation.injection.HabitsComponent 11 | import com.vrgsoft.mygoal.presentation.main.addhabit.AddHabitActivity 12 | import org.jetbrains.anko.intentFor 13 | import org.jetbrains.anko.support.v4.intentFor 14 | 15 | 16 | @Layout(id = R.layout.activity_habits) 17 | class HabitsActivity : BaseActivity(), HabitsRouter { 18 | val NEW_EXTRA: String = "new_extra" 19 | val ID_EXTRA: String = "id_extra" 20 | lateinit var habitsComponent: HabitsComponent 21 | 22 | override fun initComponent() { 23 | habitsComponent = DaggerHabitsComponent.builder() 24 | .applicationComponent(applicationComponent) 25 | .build() 26 | } 27 | 28 | override fun onCreate(savedInstanceState: Bundle?) { 29 | super.onCreate(savedInstanceState) 30 | supportFragmentManager.beginTransaction().replace(R.id.container, HabitsFragment.newInstance()).commit() 31 | 32 | 33 | } 34 | 35 | 36 | override fun onBackPressed() { 37 | finishAffinity() 38 | 39 | } 40 | 41 | override val activity: HabitsActivity 42 | get() = this 43 | 44 | override fun openGoal(isNew: Boolean, id: Long) { 45 | val intent: Intent = intentFor() 46 | intent.putExtra(ID_EXTRA, id) 47 | intent.putExtra(NEW_EXTRA, isNew) 48 | startActivity(intent) 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /app/src/main/java/com/vrgsoft/mygoal/presentation/main/habits/HabitsFragment.kt: -------------------------------------------------------------------------------- 1 | package com.vrgsoft.mygoal.presentation.main.habits 2 | 3 | 4 | import android.content.Intent 5 | import android.support.v4.app.Fragment 6 | import android.support.v7.widget.LinearLayoutManager 7 | import android.support.v7.widget.PopupMenu 8 | import android.support.v7.widget.Toolbar 9 | import android.view.View 10 | import com.vrgsoft.mygoal.R 11 | import com.vrgsoft.mygoal.data.db.alerts.Goal 12 | import com.vrgsoft.mygoal.databinding.FragmentHabitsBinding 13 | import com.vrgsoft.mygoal.presentation.common.BaseFragment 14 | import com.vrgsoft.mygoal.presentation.common.BasePresenter 15 | import com.vrgsoft.mygoal.presentation.common.BaseView 16 | import com.vrgsoft.mygoal.presentation.common.Layout 17 | import com.vrgsoft.mygoal.presentation.main.addhabit.AddHabitActivity 18 | import com.vrgsoft.mygoal.presentation.main.habits.common.GoalClickListener 19 | import com.vrgsoft.mygoal.presentation.main.habits.common.HabitsAdapter 20 | import org.jetbrains.anko.onClick 21 | import org.jetbrains.anko.support.v4.intentFor 22 | import javax.inject.Inject 23 | 24 | 25 | /** 26 | * A simple [Fragment] subclass. 27 | */ 28 | @Layout(id = R.layout.fragment_habits) 29 | open class HabitsFragment : BaseFragment(), HabitsView, GoalClickListener { 30 | val NEW_EXTRA: String = "isNew" 31 | 32 | companion object { 33 | fun newInstance(): Fragment { 34 | val habitsFragment: HabitsFragment = HabitsFragment() 35 | return habitsFragment 36 | } 37 | } 38 | 39 | 40 | override fun setList(goals: List, mListener: GoalClickListener) { 41 | 42 | val mAdapter: HabitsAdapter = HabitsAdapter(goals, mListener, activity) 43 | 44 | binding!!.habbitsContainer.adapter = mAdapter 45 | binding!!.habbitsContainer.layoutManager = LinearLayoutManager(context) 46 | 47 | } 48 | 49 | 50 | @Inject 51 | lateinit var habitsPresenter: HabitsPresenter 52 | 53 | override val presenter: BasePresenter 54 | get() = habitsPresenter as BasePresenter 55 | 56 | override val toolbar: Toolbar? 57 | get() = null 58 | 59 | override fun toolbarNavigationActive(): Boolean { 60 | return false 61 | } 62 | 63 | override fun initView() { 64 | 65 | binding!!.addHabbit.onClick { 66 | habitsPresenter.openGoal() 67 | } 68 | binding!!.menuButton.onClick { 69 | showPopupMenu(binding!!.menuButton) 70 | } 71 | habitsPresenter.router = activity as HabitsActivity 72 | 73 | 74 | } 75 | 76 | override fun onGoalClick(mGoal: Goal) { 77 | val intent: Intent = intentFor() 78 | intent.putExtra(NEW_EXTRA, false) 79 | activity.startActivity(intent) 80 | } 81 | 82 | override fun inject() { 83 | val habitsComponent = (activity as HabitsActivity).habitsComponent 84 | habitsComponent.inject(this) 85 | 86 | } 87 | 88 | 89 | private fun showPopupMenu(v: View) { 90 | val popupMenu = PopupMenu(context, v) 91 | popupMenu.inflate(R.menu.main_menu) 92 | popupMenu 93 | .setOnMenuItemClickListener { item -> 94 | when (item.itemId) { 95 | else -> false 96 | } 97 | } 98 | popupMenu.show() 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /app/src/main/java/com/vrgsoft/mygoal/presentation/main/habits/HabitsPresenter.kt: -------------------------------------------------------------------------------- 1 | package com.vrgsoft.mygoal.presentation.main.habits 2 | 3 | import com.vrgsoft.mygoal.data.db.alerts.Goal 4 | import com.vrgsoft.mygoal.domain.habits.HabitsInteractor 5 | import com.vrgsoft.mygoal.presentation.common.BasePresenter 6 | import com.vrgsoft.mygoal.presentation.main.addhabit.AddHabitActivity 7 | import com.vrgsoft.mygoal.presentation.main.habits.common.GoalClickListener 8 | import org.jetbrains.anko.support.v4.intentFor 9 | import javax.inject.Inject 10 | 11 | class HabitsPresenter @Inject constructor(habitsInteractor: HabitsInteractor) : BasePresenter(), GoalClickListener { 12 | 13 | 14 | override fun onGoalClick(mGoal: Goal) { 15 | router!!.openGoal(false, mGoal.mId); 16 | } 17 | 18 | val mHabitInteractor: HabitsInteractor = habitsInteractor 19 | 20 | override fun onStart() { 21 | 22 | mHabitInteractor.getGoals().subscribe({ goal: List -> view?.setList(goal, this) }, 23 | { t: Throwable? -> t!!.printStackTrace() }) 24 | } 25 | 26 | override fun onStop() { 27 | } 28 | 29 | fun openGoal() { 30 | router!!.openGoal(true, 0) 31 | } 32 | 33 | } -------------------------------------------------------------------------------- /app/src/main/java/com/vrgsoft/mygoal/presentation/main/habits/HabitsRouter.kt: -------------------------------------------------------------------------------- 1 | package com.vrgsoft.mygoal.presentation.main.habits 2 | 3 | interface HabitsRouter { 4 | fun openGoal(isNew: Boolean, id: Long) 5 | } -------------------------------------------------------------------------------- /app/src/main/java/com/vrgsoft/mygoal/presentation/main/habits/HabitsView.kt: -------------------------------------------------------------------------------- 1 | package com.vrgsoft.mygoal.presentation.main.habits 2 | 3 | import com.vrgsoft.mygoal.data.db.alerts.Goal 4 | import com.vrgsoft.mygoal.presentation.common.BaseView 5 | import com.vrgsoft.mygoal.presentation.main.habits.common.GoalClickListener 6 | 7 | interface HabitsView : BaseView { 8 | 9 | fun setList(goals: List,mListener:GoalClickListener) 10 | } -------------------------------------------------------------------------------- /app/src/main/java/com/vrgsoft/mygoal/presentation/main/habits/common/GoalClickListener.kt: -------------------------------------------------------------------------------- 1 | package com.vrgsoft.mygoal.presentation.main.habits.common 2 | 3 | import com.vrgsoft.mygoal.data.db.alerts.Goal 4 | 5 | 6 | interface GoalClickListener { 7 | 8 | fun onGoalClick (mGoal: Goal) 9 | 10 | } -------------------------------------------------------------------------------- /app/src/main/java/com/vrgsoft/mygoal/presentation/main/habits/common/HabitsAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.vrgsoft.mygoal.presentation.main.habits.common 2 | 3 | import android.content.Context 4 | import android.databinding.DataBindingUtil 5 | import android.support.v7.widget.RecyclerView 6 | import android.view.LayoutInflater 7 | import android.view.View 8 | import android.view.ViewGroup 9 | import com.squareup.picasso.Picasso 10 | import com.vrgsoft.mygoal.R 11 | import com.vrgsoft.mygoal.data.db.alerts.Goal 12 | import com.vrgsoft.mygoal.databinding.ItemHabitBinding 13 | import java.util.concurrent.TimeUnit 14 | 15 | /** 16 | * Created by pavlonikitin on 3/21/17. 17 | */ 18 | 19 | class HabitsAdapter(private val mItems: List,private val listener: GoalClickListener, val context : Context) : RecyclerView.Adapter() { 20 | 21 | override fun onBindViewHolder(holder: ViewHolder, position: Int) { 22 | holder.binding.goal = mItems[position] 23 | Picasso.with(context).load(mItems[position].mImage).into(holder.binding.imageView) 24 | 25 | val leftDays:String = (((mItems[position].lastCheck-mItems[position].mLatsDays)/ TimeUnit.DAYS.toMillis(1))*100/21).toString()+" %" 26 | holder.binding.tvDayLeft.text = leftDays 27 | holder.binding.listener = listener 28 | } 29 | 30 | override fun getItemCount(): Int { 31 | return mItems.size 32 | } 33 | 34 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { 35 | val layoutInflater = LayoutInflater.from(parent.context) 36 | return ViewHolder(layoutInflater.inflate(R.layout.item_habit, parent, false)) 37 | } 38 | 39 | 40 | class ViewHolder(view: View) : RecyclerView.ViewHolder(view) { 41 | var binding: ItemHabitBinding = DataBindingUtil.bind(view) 42 | 43 | } 44 | } -------------------------------------------------------------------------------- /app/src/main/java/com/vrgsoft/mygoal/presentation/main/habits/common/resultdialogs/ResultDialog.kt: -------------------------------------------------------------------------------- 1 | package com.vrgsoft.mygoal.presentation.main.habits.common.resultdialogs 2 | 3 | import android.content.Intent 4 | import android.databinding.generated.callback.OnClickListener 5 | import android.graphics.Color 6 | import android.os.Bundle 7 | import android.graphics.drawable.ColorDrawable 8 | import android.support.v4.app.DialogFragment 9 | import android.view.ViewGroup 10 | import android.view.LayoutInflater 11 | import android.view.View 12 | import com.vrgsoft.mygoal.R 13 | import com.vrgsoft.mygoal.presentation.main.addhabit.AddHabitActivity 14 | import com.vrgsoft.mygoal.presentation.main.habits.common.themedialog.ThemeDialogFragment 15 | 16 | class ResultDialog : DialogFragment(), View.OnClickListener { 17 | val NEW_EXTRA: String = "new_extra" 18 | companion object { 19 | val FAILED_EXTRA = "failed_extra" 20 | fun newInstance(idFailed: Boolean): DialogFragment { 21 | val resultDialog: ResultDialog = ResultDialog() 22 | val bundle: Bundle = Bundle() 23 | bundle.putBoolean(FAILED_EXTRA, idFailed) 24 | resultDialog.arguments = bundle 25 | return resultDialog 26 | } 27 | } 28 | 29 | override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? { 30 | val layout = if (arguments.getBoolean(FAILED_EXTRA)) R.layout.dialog_failed else R.layout.dialog_success 31 | val v = inflater!!.inflate(layout, null) 32 | v.findViewById(R.id.ok).setOnClickListener(this) 33 | dialog.window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) 34 | return v 35 | } 36 | 37 | 38 | override fun onCreate(savedInstanceState: Bundle?) { 39 | super.onCreate(savedInstanceState) 40 | setStyle(DialogFragment.STYLE_NO_TITLE, 0) 41 | } 42 | 43 | override fun onClick(view: View) { 44 | val intentLaunchApp = Intent(activity, AddHabitActivity::class.java) 45 | intentLaunchApp.putExtra(NEW_EXTRA, true) 46 | activity.startActivity(intentLaunchApp) 47 | dismiss() 48 | activity.finish() 49 | } 50 | } -------------------------------------------------------------------------------- /app/src/main/java/com/vrgsoft/mygoal/presentation/main/habits/common/themedialog/OnThemeChooseCallBack.kt: -------------------------------------------------------------------------------- 1 | package com.vrgsoft.mygoal.presentation.main.habits.common.themedialog 2 | 3 | 4 | interface OnThemeChooseCallBack { 5 | 6 | fun onThemeClick(themeViewModel: ThemeViewModel) 7 | } -------------------------------------------------------------------------------- /app/src/main/java/com/vrgsoft/mygoal/presentation/main/habits/common/themedialog/ThemeAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.vrgsoft.mygoal.presentation.main.habits.common.themedialog 2 | 3 | import android.content.Context 4 | import android.support.v7.widget.RecyclerView 5 | import android.view.LayoutInflater 6 | import android.view.View 7 | import android.view.ViewGroup 8 | import android.widget.ImageView 9 | import android.widget.TextView 10 | import com.vrgsoft.mygoal.R 11 | 12 | import com.squareup.picasso.Picasso 13 | import org.jetbrains.anko.onClick 14 | 15 | 16 | 17 | class ThemeAdapter constructor(private val themeViewModel: List, val context: Context) : RecyclerView.Adapter() { 18 | 19 | override fun onBindViewHolder(holder: ThemeViewHolder?, position: Int) { 20 | Picasso.with(context).load(themeViewModel[position].ivTheme).into(holder!!.ivImageTheme) 21 | holder.tvTextTheme.text = themeViewModel[position].tvTheme 22 | 23 | holder.itemView.onClick { 24 | context as OnThemeChooseCallBack 25 | context.onThemeClick(themeViewModel[position]) 26 | } 27 | 28 | } 29 | 30 | override fun getItemCount(): Int { 31 | return themeViewModel.size 32 | } 33 | 34 | override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): ThemeViewHolder { 35 | val layoutInflater: View = LayoutInflater.from(parent!!.context).inflate(R.layout.item, parent, false) 36 | return ThemeViewHolder(layoutInflater) 37 | } 38 | 39 | class ThemeViewHolder(v: View) : RecyclerView.ViewHolder(v) { 40 | 41 | var ivImageTheme: ImageView = v.findViewById(R.id.theme_icon) as ImageView 42 | var tvTextTheme: TextView = v.findViewById(R.id.theme_name) as TextView 43 | 44 | 45 | } 46 | } -------------------------------------------------------------------------------- /app/src/main/java/com/vrgsoft/mygoal/presentation/main/habits/common/themedialog/ThemeDialogFragment.kt: -------------------------------------------------------------------------------- 1 | package com.vrgsoft.mygoal.presentation.main.habits.common.themedialog 2 | 3 | import android.app.DialogFragment 4 | import android.databinding.DataBindingUtil 5 | import android.databinding.ViewDataBinding 6 | import android.os.Bundle 7 | import android.support.v4.app.Fragment 8 | import android.support.v7.widget.LinearLayoutManager 9 | import android.view.LayoutInflater 10 | import android.view.View 11 | import android.view.ViewGroup 12 | import com.bumptech.glide.load.model.stream.StreamStringLoader 13 | import com.vrgsoft.mygoal.R 14 | import com.vrgsoft.mygoal.databinding.FragmentDialogThemeBinding 15 | import com.vrgsoft.mygoal.databinding.ItemBinding 16 | import org.jetbrains.anko.imageResource 17 | 18 | 19 | class ThemeDialogFragment : DialogFragment() { 20 | 21 | 22 | lateinit var binding:FragmentDialogThemeBinding 23 | 24 | fun newInstance(): DialogFragment { 25 | val themeDialogFragment: ThemeDialogFragment = ThemeDialogFragment() 26 | return themeDialogFragment 27 | } 28 | 29 | override fun onCreate(savedInstanceState: Bundle?) { 30 | super.onCreate(savedInstanceState) 31 | setStyle(STYLE_NO_TITLE, 0) 32 | 33 | } 34 | 35 | override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View { 36 | binding = DataBindingUtil.inflate(inflater, R.layout.fragment_dialog_theme, container, false) 37 | binding.recyclerTheme.layoutManager = LinearLayoutManager(activity) 38 | binding.recyclerTheme.adapter=ThemeAdapter(createListViewModels(), activity) 39 | return binding.root 40 | 41 | } 42 | 43 | 44 | fun createListViewModels():ArrayList{ 45 | val themeListModel:ArrayList = ArrayList() 46 | 47 | val themeIcon:IntArray = intArrayOf(R.drawable.healthy_icon, R.drawable.money_icon, 48 | R.drawable.self_improvment_icon, R.drawable.sex_dating_icon, R.drawable.work_and_study_icon, 49 | R.drawable.arts_icon, R.drawable.social_icon, R.drawable.home_icon, R.drawable.other_icon) 50 | val themeNames:Array = activity.resources.getStringArray(R.array.themesNames) 51 | 52 | (0..8).mapTo(themeListModel) { ThemeViewModel(themeIcon[it], themeNames[it]) } 53 | 54 | return themeListModel 55 | } 56 | 57 | 58 | } -------------------------------------------------------------------------------- /app/src/main/java/com/vrgsoft/mygoal/presentation/main/habits/common/themedialog/ThemeViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.vrgsoft.mygoal.presentation.main.habits.common.themedialog 2 | 3 | 4 | class ThemeViewModel(var ivTheme: Int, var tvTheme: String) -------------------------------------------------------------------------------- /app/src/main/java/com/vrgsoft/mygoal/presentation/main/showhabit/ShowHabbitView.kt: -------------------------------------------------------------------------------- 1 | package com.vrgsoft.mygoal.presentation.main.showhabit 2 | 3 | import com.vrgsoft.mygoal.data.db.alerts.Goal 4 | 5 | interface ShowHabbitView { 6 | 7 | fun setGoal(goal: Goal) 8 | } -------------------------------------------------------------------------------- /app/src/main/java/com/vrgsoft/mygoal/presentation/main/showhabit/ShowHabitFragment.kt: -------------------------------------------------------------------------------- 1 | package com.vrgsoft.mygoal.presentation.main.showhabit 2 | 3 | 4 | import android.os.Bundle 5 | import android.support.v4.app.DialogFragment 6 | import android.support.v7.widget.Toolbar 7 | import com.squareup.picasso.Picasso 8 | import com.vrgsoft.mygoal.R 9 | import com.vrgsoft.mygoal.data.db.alerts.Goal 10 | import com.vrgsoft.mygoal.databinding.FragmentShowHabitBinding 11 | import com.vrgsoft.mygoal.presentation.common.BaseFragment 12 | import com.vrgsoft.mygoal.presentation.common.BasePresenter 13 | import com.vrgsoft.mygoal.presentation.common.BaseView 14 | import com.vrgsoft.mygoal.presentation.common.Layout 15 | import com.vrgsoft.mygoal.presentation.main.addhabit.AddHabitActivity 16 | import com.vrgsoft.mygoal.presentation.main.habits.common.resultdialogs.ResultDialog 17 | import com.vrgsoft.mygoal.presentation.receivers.AlarmReceiver 18 | import org.jetbrains.anko.onClick 19 | import java.text.SimpleDateFormat 20 | import java.util.* 21 | import java.util.concurrent.TimeUnit 22 | import javax.inject.Inject 23 | import az.plainpie.animation.PieAngleAnimation 24 | import com.vrgsoft.mygoal.presentation.main.addhabit.AddHabitFragment.Companion.ID_EXTRA 25 | 26 | 27 | @Layout(id = R.layout.fragment_show_habit) 28 | class ShowHabitFragment : BaseFragment(), ShowHabbitView { 29 | val TAG_FAILED = "Failed" 30 | override fun setGoal(goal: Goal) { 31 | binding!!.goal = goal 32 | if (goal.mTime != 0.toLong()) { 33 | val currentTime: String = SimpleDateFormat("HH:mm").format(goal.mTime) 34 | binding!!.notifyTimeToShow.text = currentTime 35 | } else { 36 | binding!!.notifyTimeToShow.text = getString(R.string.none) 37 | } 38 | 39 | Picasso.with(context).load(goal.mImage).into(binding!!.emojiShow) 40 | 41 | 42 | var percentage: Float = (((goal.lastCheck - goal.mLatsDays) / TimeUnit.DAYS.toMillis(1)) * 100 / 21).toFloat() 43 | if (percentage == 0.toFloat()) { 44 | percentage = 0.1.toFloat() 45 | } 46 | binding!!.pieView.percentage = percentage 47 | 48 | val animation = PieAngleAnimation(binding!!.pieView) 49 | animation.duration = 1500 50 | binding!!.pieView.startAnimation(animation) 51 | 52 | val calLastCheck: Calendar = Calendar.getInstance() 53 | calLastCheck.timeInMillis = goal.lastCheck 54 | calLastCheck.set(Calendar.HOUR_OF_DAY, 0) 55 | calLastCheck.set(Calendar.MINUTE, 1) 56 | 57 | if ((System.currentTimeMillis() - calLastCheck.timeInMillis) > TimeUnit.DAYS.toMillis(2)) { 58 | 59 | val failedDialog: DialogFragment = ResultDialog.newInstance(true) 60 | failedDialog.show(fragmentManager, TAG_FAILED) 61 | mHabitPresenter.deleteGoalById(goal) 62 | } else { 63 | if ((calLastCheck.timeInMillis + TimeUnit.DAYS.toMillis(1)) <= System.currentTimeMillis()) { 64 | binding!!.checkHabbit.isEnabled = true 65 | binding!!.checkHabbit.onClick { 66 | mHabitPresenter.check(goal) 67 | AlarmReceiver.updateDailyReminder(context) 68 | if ((goal.mLatsDays + goal.mTwentyOne) <= System.currentTimeMillis()) { 69 | val failedDialog: DialogFragment = ResultDialog.newInstance(false) 70 | failedDialog.show(fragmentManager, TAG_FAILED) 71 | mHabitPresenter.deleteGoalById(goal) 72 | } 73 | binding!!.checkHabbit.isEnabled = false 74 | activity.finish() 75 | } 76 | } else { 77 | binding!!.checkHabbit.isEnabled = false 78 | } 79 | } 80 | 81 | } 82 | 83 | override val toolbar: Toolbar? 84 | get() = null 85 | 86 | companion object { 87 | fun newInstance(mId: Long): ShowHabitFragment { 88 | val mBundl: Bundle = Bundle() 89 | mBundl.putLong(ID_EXTRA, mId) 90 | val fragment: ShowHabitFragment = ShowHabitFragment() 91 | fragment.arguments = mBundl 92 | return fragment 93 | } 94 | } 95 | 96 | @Inject 97 | lateinit var mHabitPresenter: ShowHabitPresenter 98 | 99 | override fun toolbarNavigationActive(): Boolean { 100 | return false 101 | } 102 | 103 | override fun initView() { 104 | binding!!.ivEdit.onClick { 105 | val tmp: AddHabitActivity = activity as AddHabitActivity 106 | tmp.showEditFragment() 107 | } 108 | } 109 | 110 | override fun inject() { 111 | val habitsComponent = (activity as AddHabitActivity).addHabitComponent 112 | habitsComponent.inject(this) 113 | } 114 | 115 | override val presenter: BasePresenter 116 | get() = mHabitPresenter as BasePresenter 117 | 118 | override fun onActivityCreated(savedInstanceState: Bundle?) { 119 | super.onActivityCreated(savedInstanceState) 120 | 121 | mHabitPresenter.getGoal(this.arguments.getLong(ID_EXTRA, 0)) 122 | 123 | initView() 124 | } 125 | 126 | 127 | } -------------------------------------------------------------------------------- /app/src/main/java/com/vrgsoft/mygoal/presentation/main/showhabit/ShowHabitPresenter.kt: -------------------------------------------------------------------------------- 1 | package com.vrgsoft.mygoal.presentation.main.showhabit 2 | 3 | import com.vrgsoft.mygoal.data.db.alerts.Goal 4 | import com.vrgsoft.mygoal.domain.habits.HabitInteractor 5 | import com.vrgsoft.mygoal.presentation.common.BasePresenter 6 | import com.vrgsoft.mygoal.presentation.main.habits.HabitsRouter 7 | import javax.inject.Inject 8 | 9 | /** 10 | * Created by Павел on 04.04.2017. 11 | */ 12 | class ShowHabitPresenter @Inject constructor(habitsInteractor: HabitInteractor) : BasePresenter(){ 13 | 14 | val mHabitInteractor: HabitInteractor = habitsInteractor 15 | 16 | 17 | override fun onStart() { 18 | 19 | } 20 | 21 | override fun onStop() { 22 | 23 | } 24 | 25 | fun showHabit() { 26 | 27 | } 28 | 29 | fun getGoal(mId: Long) { 30 | mHabitInteractor.getGoal(mId).subscribe({ goal: Goal -> view!!.setGoal(goal) }, Throwable::printStackTrace) 31 | 32 | } 33 | 34 | fun check(goal: Goal){ 35 | mHabitInteractor.check(goal) 36 | } 37 | 38 | fun deleteGoalById(goal: Goal){ 39 | mHabitInteractor.deleteGoalById(goal) 40 | } 41 | 42 | fun getGoalById(id:Long){ 43 | mHabitInteractor.getGoalById(id) 44 | } 45 | 46 | 47 | 48 | 49 | 50 | 51 | } -------------------------------------------------------------------------------- /app/src/main/java/com/vrgsoft/mygoal/presentation/receivers/AlarmReceiver.kt: -------------------------------------------------------------------------------- 1 | package com.vrgsoft.mygoal.presentation.receivers 2 | 3 | import android.annotation.TargetApi 4 | import android.app.AlarmManager 5 | import android.app.Notification 6 | import android.app.NotificationManager 7 | import android.app.PendingIntent 8 | import android.content.BroadcastReceiver 9 | import android.content.Context 10 | import android.content.Intent 11 | import android.graphics.BitmapFactory 12 | import android.os.Build 13 | import android.support.annotation.RequiresApi 14 | import android.support.v4.app.NotificationCompat 15 | import com.vrgsoft.mygoal.R 16 | import com.vrgsoft.mygoal.data.db.alerts.Goal 17 | import com.vrgsoft.mygoal.data.db.habits.HabitsRepositoryLocalImp 18 | import com.vrgsoft.mygoal.domain.habits.HabitInteractor 19 | import com.vrgsoft.mygoal.domain.habits.HabitsInteractor 20 | import com.vrgsoft.mygoal.presentation.common.SettingsHelper 21 | import com.vrgsoft.mygoal.presentation.injection.App 22 | import com.vrgsoft.mygoal.presentation.main.addhabit.AddHabitActivity 23 | import com.vrgsoft.mygoal.presentation.main.addhabit.AddHabitPresenter 24 | import com.vrgsoft.mygoal.presentation.main.habits.HabitsActivity 25 | import com.vrgsoft.mygoal.presentation.main.habits.HabitsPresenter 26 | import java.util.* 27 | import java.util.concurrent.TimeUnit 28 | import javax.inject.Inject 29 | 30 | 31 | class AlarmReceiver : BroadcastReceiver() { 32 | 33 | 34 | override fun onReceive(context: Context, intent: Intent?) { 35 | var context = context 36 | if (intent == null || intent.action == null) { 37 | return 38 | } 39 | 40 | // When device boots, need to reschedule alarm 41 | context = context.applicationContext 42 | when (intent.action) { 43 | Intent.ACTION_DATE_CHANGED -> updateReminder(context) 44 | UPDATE_REMINDER -> updateReminder(context) 45 | UPDATE_RANDOM_REMINDER -> updateRandomReminder(context) 46 | ACTION_SHOW_DAILY_REMINDER -> 47 | showDailyReminderNotification(context, intent) 48 | 49 | } 50 | } 51 | 52 | private fun updateReminder(context: Context) { 53 | scheduleDailyReminderAlarm(context) 54 | } 55 | 56 | private fun updateRandomReminder(context: Context) { 57 | scheduleRandomReminderAlarms(context) 58 | } 59 | 60 | 61 | private fun scheduleDailyReminderAlarm(context: Context) { 62 | 63 | val habitsRepository: HabitsRepositoryLocalImp = HabitsRepositoryLocalImp() 64 | val habitInteractor: HabitInteractor = HabitInteractor(habitsRepository) 65 | val mHabitPresenter: AddHabitPresenter = AddHabitPresenter(habitInteractor) 66 | val listAlarm: List = mHabitPresenter.getAllHabits() 67 | listAlarm 68 | .filter { it.mTime != 0.toLong() } 69 | .forEach { 70 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 71 | makeMarshMallowNotif(it, context) 72 | } else { 73 | scheduleAlarm(context, createDailyReminderIntent(context, it), it.mTime) 74 | } 75 | } 76 | } 77 | 78 | @RequiresApi(api = 23) 79 | fun makeMarshMallowNotif(goal: Goal, context: Context) { 80 | for (i in 1..22) { 81 | val pendingIntent = createDailyReminderIntentMarshmalow(context, goal, i) 82 | val timeToCall: Long = goal.mTime + TimeUnit.DAYS.toMillis(i.toLong()) 83 | val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager 84 | alarmManager.cancel(pendingIntent) 85 | alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, timeToCall, pendingIntent); 86 | } 87 | 88 | } 89 | 90 | private fun scheduleRandomReminderAlarms(context: Context) { 91 | val hour = 8 92 | val minute = 30 93 | scheduleAlarmTwoDays(context, createRandomReminderIntent(context), hour, minute) 94 | 95 | } 96 | 97 | private fun scheduleAlarm(context: Context, intent: PendingIntent, reminderTime: Long) { 98 | //var nextTime : Long = reminderTime+TimeUnit.DAYS.toMillis(1); 99 | // Will override existing alarm if necessary. 100 | val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager 101 | alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, reminderTime, AlarmManager.INTERVAL_DAY, intent) 102 | 103 | } 104 | 105 | private fun scheduleAlarmTwoDays(context: Context, intent: PendingIntent, hourOfDay: Int, minute: Int) { 106 | // get a calendar instance, which defaults to "now" 107 | val calendar = Calendar.getInstance() 108 | // get a date to represent "today" 109 | val today = calendar.time 110 | println("today: " + today) 111 | // add one day to the date/calendar 112 | calendar.add(Calendar.DAY_OF_YEAR, 2) 113 | // now get "tomorrow" 114 | val tomorrow = calendar.time 115 | 116 | val reminderTime = Calendar.getInstance() // Start with right now. 117 | reminderTime.set(Calendar.DATE, tomorrow.date) 118 | reminderTime.set(Calendar.HOUR_OF_DAY, hourOfDay) 119 | reminderTime.set(Calendar.MINUTE, minute) 120 | reminderTime.set(Calendar.SECOND, 0) 121 | // Start from tomorrow if today's alarm time has already passed. 122 | if (reminderTime.before(Calendar.getInstance())) { 123 | reminderTime.add(Calendar.DAY_OF_MONTH, 1) 124 | } 125 | // Will override existing alarm if necessary. 126 | val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager 127 | alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, reminderTime.timeInMillis, AlarmManager.INTERVAL_DAY, intent) 128 | App.settings.setReminder(System.currentTimeMillis() + 1000 * 60 * 60 * 24) 129 | } 130 | 131 | private fun createDailyReminderIntentMarshmalow(context: Context, goal: Goal, counter: Int): PendingIntent { 132 | val intent = Intent(context, AlarmReceiver::class.java) 133 | intent.action = ACTION_SHOW_DAILY_REMINDER 134 | intent.putExtra("theme", goal.mName) 135 | intent.putExtra("question", goal.mDescr) 136 | intent.putExtra("id", goal.mId) 137 | intent.putExtra("time", goal.mTime) 138 | intent.putExtra("startTime", goal.mLatsDays) 139 | 140 | return PendingIntent.getBroadcast(context, goal.mId.toInt() * 1000 + counter, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_ONE_SHOT) 141 | } 142 | 143 | // Use same pending intent for all queries to AlarmManager to ensure only one is being updated/cancelled. 144 | private fun createDailyReminderIntent(context: Context, goal: Goal): PendingIntent { 145 | val intent = Intent(context, AlarmReceiver::class.java) 146 | intent.action = ACTION_SHOW_DAILY_REMINDER 147 | intent.putExtra("theme", goal.mName) 148 | intent.putExtra("question", goal.mDescr) 149 | intent.putExtra("id", goal.mId) 150 | intent.putExtra("time", goal.mTime) 151 | intent.putExtra("startTime", goal.mLatsDays) 152 | 153 | return PendingIntent.getBroadcast(context, goal.mId.toInt(), intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_ONE_SHOT) 154 | } 155 | 156 | private fun createRandomReminderIntent(context: Context): PendingIntent { 157 | val intent = Intent(context, AlarmReceiver::class.java) 158 | intent.action = ACTION_SHOW_DAILY_RANDOM_REMINDER 159 | return PendingIntent.getBroadcast(context, RANDOM_ALARM_BASE_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_ONE_SHOT) 160 | } 161 | 162 | companion object { 163 | 164 | val UPDATE_REMINDER = ".UPDATE_REMINDER" 165 | val UPDATE_RANDOM_REMINDER = ".UPDATE_RANDOM_REMINDER" 166 | private val ACTION_SHOW_DAILY_REMINDER = ".ACTION_SHOW_DAILY_REMINDER" 167 | private val ACTION_SHOW_DAILY_RANDOM_REMINDER = ".ACTION_SHOW_RANDOM_DAILY_REMINDER" 168 | 169 | private val ALARM_ID = 100218 170 | private val RANDOM_ALARM_BASE_ID = 210223 171 | 172 | fun updateDailyReminder(context: Context) { 173 | val intent = Intent(context, AlarmReceiver::class.java) 174 | intent.action = UPDATE_REMINDER 175 | context.sendBroadcast(intent) 176 | } 177 | 178 | fun updateRandomDailyReminder(context: Context) { 179 | val intent = Intent(context, AlarmReceiver::class.java) 180 | intent.action = UPDATE_RANDOM_REMINDER 181 | context.sendBroadcast(intent) 182 | } 183 | 184 | fun showDailyReminderNotification(context: Context, intent: Intent) { 185 | // Show daily reminder notification to user. 186 | val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager 187 | val intentLaunchApp = Intent(context, AddHabitActivity::class.java) 188 | intentLaunchApp.putExtra("isNew", false) 189 | intentLaunchApp.putExtra("id", intent.getLongExtra("id", 0)) 190 | val pendingIntent = PendingIntent.getActivity(context, ALARM_ID, intentLaunchApp, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_ONE_SHOT) 191 | val notification = createNotification(context, intent.getStringExtra("question"), intent.getStringExtra("theme"), pendingIntent) 192 | // Sets an ID for the notification, so it can be updated 193 | notificationManager.notify(ALARM_ID, notification) 194 | 195 | } 196 | 197 | 198 | private fun createNotification(context: Context, text: String, textTheme: String, pendingIntent: PendingIntent): Notification { 199 | val builder = NotificationCompat.Builder(context) 200 | builder.setLargeIcon(BitmapFactory.decodeResource(context.resources, R.drawable.icon)) 201 | builder.setContentTitle(textTheme) 202 | builder.setSmallIcon(R.drawable.icon) 203 | builder.setDefaults(Notification.DEFAULT_SOUND) 204 | builder.setWhen(System.currentTimeMillis()) 205 | builder.setContentIntent(pendingIntent) 206 | builder.setContentText(text) 207 | builder.setAutoCancel(true) 208 | return builder.build() 209 | } 210 | } 211 | 212 | 213 | } 214 | 215 | -------------------------------------------------------------------------------- /app/src/main/java/com/vrgsoft/mygoal/presentation/receivers/TimeChangeReceiver.kt: -------------------------------------------------------------------------------- 1 | package com.vrgsoft.mygoal.presentation.receivers 2 | 3 | import android.app.AlarmManager 4 | import android.app.PendingIntent 5 | import android.content.BroadcastReceiver 6 | import android.content.Context 7 | import android.content.Intent 8 | import java.util.* 9 | 10 | /** 11 | * Created by pavlonikitin on 4/4/17. 12 | */ 13 | 14 | class TimeChangeReceiver : BroadcastReceiver() { 15 | val DAY_CHANGE_ALARM_ID:Int = 100220 16 | 17 | 18 | override fun onReceive(context: Context?, intent: Intent?) { 19 | AlarmReceiver.updateRandomDailyReminder(context!!) 20 | 21 | } 22 | 23 | fun scheduleDayChangeAlarm(context: Context?){ 24 | val calendar:Calendar = Calendar.getInstance() 25 | calendar.set(Calendar.HOUR_OF_DAY, 0) 26 | calendar.set(Calendar.MINUTE, 0) 27 | calendar.set(Calendar.SECOND, 0) 28 | calendar.add(Calendar.DAY_OF_YEAR, 1) 29 | 30 | val am:AlarmManager = context!!.getSystemService(Context.ALARM_SERVICE) as AlarmManager 31 | val intent = Intent(context, TimeChangeReceiver::class.java) 32 | val pendingIntent = PendingIntent.getBroadcast(context, DAY_CHANGE_ALARM_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT) 33 | // Don't need this to fire exactly on the dot. 34 | am.setInexactRepeating(AlarmManager.RTC_WAKEUP, calendar.timeInMillis, AlarmManager.INTERVAL_DAY, pendingIntent) 35 | 36 | } 37 | } -------------------------------------------------------------------------------- /app/src/main/res/anim/move_anim.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/actionbar_shadow.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/arts_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VRGsoftUA/GetGoal/888eb311bfe6f999a6cfd4e6c9a13c415da71f37/app/src/main/res/drawable/arts_icon.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/bt_drawable.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/dialog_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VRGsoftUA/GetGoal/888eb311bfe6f999a6cfd4e6c9a13c415da71f37/app/src/main/res/drawable/dialog_background.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/healthy_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VRGsoftUA/GetGoal/888eb311bfe6f999a6cfd4e6c9a13c415da71f37/app/src/main/res/drawable/healthy_icon.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/home_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VRGsoftUA/GetGoal/888eb311bfe6f999a6cfd4e6c9a13c415da71f37/app/src/main/res/drawable/home_icon.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_add.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_collections.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_mode_edit_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VRGsoftUA/GetGoal/888eb311bfe6f999a6cfd4e6c9a13c415da71f37/app/src/main/res/drawable/icon.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/main_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VRGsoftUA/GetGoal/888eb311bfe6f999a6cfd4e6c9a13c415da71f37/app/src/main/res/drawable/main_back.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/main_splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VRGsoftUA/GetGoal/888eb311bfe6f999a6cfd4e6c9a13c415da71f37/app/src/main/res/drawable/main_splash.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/money_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VRGsoftUA/GetGoal/888eb311bfe6f999a6cfd4e6c9a13c415da71f37/app/src/main/res/drawable/money_icon.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/move_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VRGsoftUA/GetGoal/888eb311bfe6f999a6cfd4e6c9a13c415da71f37/app/src/main/res/drawable/move_back.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/other_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VRGsoftUA/GetGoal/888eb311bfe6f999a6cfd4e6c9a13c415da71f37/app/src/main/res/drawable/other_icon.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/rounded_white_rect.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/self_improvment_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VRGsoftUA/GetGoal/888eb311bfe6f999a6cfd4e6c9a13c415da71f37/app/src/main/res/drawable/self_improvment_icon.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/sex_dating_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VRGsoftUA/GetGoal/888eb311bfe6f999a6cfd4e6c9a13c415da71f37/app/src/main/res/drawable/sex_dating_icon.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/social_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VRGsoftUA/GetGoal/888eb311bfe6f999a6cfd4e6c9a13c415da71f37/app/src/main/res/drawable/social_icon.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/work_and_study_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VRGsoftUA/GetGoal/888eb311bfe6f999a6cfd4e6c9a13c415da71f37/app/src/main/res/drawable/work_and_study_icon.png -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_add_habit.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | 15 | 16 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_habits.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 12 | 13 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_splash.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 20 | 21 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/layout/dialog_failed.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 18 | 19 | 25 | 26 | 30 | 31 |