13 |
14 | RateMe is a powerful system to get rates from users in Android applications.
15 |
16 | RateMe takes cares to show pretty dialogs to collect rates from users so you don't have to.
17 | One thing you do is to define some rules and send events to RateMe library.
18 | RateMe watch the events you define and show the a pretty dialog to users on correct time.
19 |
20 | # Table of Contents
21 |
22 | 1. [Gradle Dependency](https://github.com/zingat/RateMe-Android/#gradle-dependency)
23 | 2. [Quick Start](https://github.com/zingat/RateMe-Android/#quick-start)
24 | 1. [Initialize RateMe](https://github.com/zingat/RateMe-Android/#initialize-rateme-in-your-application-class)
25 | 2. [How events are sent to RateMe](https://github.com/zingat/RateMe-Android/#how-touch_me_event-is-sent-to-rateme)
26 | 3. [How button works](https://github.com/zingat/RateMe-Android/#how-buttons-works)
27 | 1. [Rate Us](https://github.com/zingat/RateMe-Android/#rate-us)
28 | 2. [Remind Me Later](https://github.com/zingat/RateMe-Android/#remind-me-later)
29 | 3. [Don't Ask Again](https://github.com/zingat/RateMe-Android/#dont-ask-again)
30 | 4. [Arranging delay time](https://github.com/zingat/RateMe-Android/#arranging-delay-time)
31 | 5. [Callbacks](https://github.com/zingat/RateMe-Android/#callbacks)
32 | 6. [Custom Views](https://github.com/zingat/RateMe-Android/#custom-views)
33 | 7. [Custom Buttons](https://github.com/zingat/RateMe-Android/#custom-buttons)
34 | 8. [Changing colors and texts](https://github.com/zingat/RateMe-Android/#changing-colors-and-texts)
35 | 1. [colors.xml](https://github.com/zingat/RateMe-Android/#colorsxml)
36 | 2. [strings.xml](https://github.com/zingat/RateMe-Android/#strings.xml)
37 | 9. [Adding Multiple Conditions](https://github.com/zingat/RateMe-Android/#adding-multiple-conditions)
38 | 1. [Adding one by one](https://github.com/zingat/RateMe-Android/#adding-one-by-one)
39 | 2. [Adding all as Collection](https://github.com/zingat/RateMe-Android/#adding-all-as-collection)
40 | 3. [How multiple conditions work](https://github.com/zingat/RateMe-Android/#how-multiple-conditions-work)
41 |
42 | ------
43 |
44 | # GRADLE DEPENDENCY
45 | The minimum API level supported by this library is API 15.
46 | Add the dependency to your `build.gradle`:
47 |
48 | ```Gradle
49 | dependencies {
50 | implementation 'com.zingat:rateme:1.3.0'
51 | }
52 | ```
53 |
54 | # Quick start
55 |
56 | ### Initialize `RateMe` in your `Application` class
57 | ```kotlin
58 | class App : Application() {
59 |
60 | override fun onCreate() {
61 | super.onCreate()
62 |
63 | Rateme.getInstance(this@App)
64 | // `addCondition(conditionName,repeatTime)`
65 | .addCondition("touch_me_event", 3)
66 | .reminderDuration(3)
67 | }
68 |
69 | }
70 | ```
71 |
72 | Now we are telling to RateMe that you can show a dialog when 3 times `touch_me_event` is sent.
73 |
74 | ### How `touch_me_event` is sent to RateMe.
75 | ```kotlin
76 | Rateme.getInstance(this)
77 | .addEvent("touch_me_event")
78 | ```
79 |
80 | The event can be sent for each statement. For example when a user opens the app 4 times you can send `app_opened` event or user can like
81 | a product in your app 2 times you can send `product_liked` event. For all statements you can send event seperately.
82 |
83 | The default appearance is like picture below.
84 |
85 |
86 |
87 |
88 |
89 | `When dialog shown on screen, user have to choose one of these options to close the window.
90 | To touch background and back button don't close the window.`
91 |
92 | # How Buttons works
93 |
94 | ### Rate Us
95 |
96 | RateMe library detects your applicationId(for example com.zingat.rateme) and
97 | When user clicks the `Rate Us` button, your app's Google Play page opens automaticly
98 | and user can rate your app easily.
99 |
100 | ### Remind Me Later
101 |
102 | When user clicks the `Remind Me Later` button, the dialog disappears until the days finished
103 | you defined in initialization code. `reminderDuration(day:Int)` is used define the necessary time.
104 | The parameter is given in days.
105 |
106 | ### Don't Ask Again
107 |
108 | When user clicks the `Don't Ask Again` button, the dialog disappears and never appear again.
109 |
110 | # Arranging delay time
111 |
112 | RateMe supports to arrange the delay time
113 | `delay(time : Long)` indicates the time to display dialog after all events completed.
114 | Default value is 0.
115 |
116 |
117 | ```kotlin
118 | Rateme.getInstance(this@App)
119 | .addCondition("touch_me_event", 3)
120 | .reminderDuration(3)
121 | .delay(1000)
122 | ```
123 |
124 | # Callbacks
125 |
126 | To know when the user selects an action button, you set callbacks:
127 |
128 | ```kotlin
129 | Rateme.getInstance(this@App)
130 | .addCondition("touch_me_event", 3)
131 | .delay(1000)
132 | .onRateCallback( object : RMEventCallback{
133 | override fun onEvent() {
134 | // TODO
135 | }
136 | })
137 | .onDontAskCallback(object : RMEventCallback{
138 | override fun onEvent() {
139 | // TODO
140 | }
141 | })
142 | .onRemindLaterCallback(object : RMEventCallback{
143 | override fun onEvent() {
144 | // TODO
145 | }
146 | })
147 | .onShowCallback(object : RMEventCallback{
148 | override fun onEvent() {
149 | // TODO
150 | }
151 | })
152 | .onRMCallback(object : RMCallback{
153 | override fun onEvent(eventName: String, count: Int, which: Int) {
154 | // TODO
155 | }
156 | })
157 | ```
158 | If you are listening for all three action buttons, you could just use `onRMCallback()`.
159 |
160 | * `eventName (String)` parameter tells completed event name. In our case this is `touch_me_event`
161 | * `count (Int)` parameter tells completed event count value. In our case this is `3`.
162 | The count value is defined by developer in `addCondition()` method.
163 | * `which (Int)` parameter tells which action is happening. Each number indicates different state.
164 | * STARTED = -1
165 | * POSITIVE = 0
166 | * NEUTRAL = 1
167 | * NEGATIVE = 2
168 |
169 | # Custom Views
170 |
171 | Custom views are very easy to implement.
172 |
173 | ```kotlin
174 | Rateme.getInstance(this@App)
175 | .addCondition("touch_me_event", 3)
176 | .reminderDuration(3)
177 | .delay(1000)
178 | .custom(R.layout.layout_dialog)
179 | ```
180 |
181 | After custom view is added appearance is like picture below.
182 |
183 |
184 |
185 |
186 |
187 | When `custom()` method is used, default title and content disappears. Only the you layout file will display on screen.
188 |
189 | It is recommended not to use buttons and different type views in custom layout.
190 | Because you can not provide callbacks for buttons.
191 |
192 | # Custom Buttons
193 |
194 | You can use `customButton()` and `customButtonReverse()` methods to provide pretty much colored buttons.
195 |
196 | ```kotlin
197 | Rateme.getInstance(this@App)
198 | .addCondition("touch_me_event", 3)
199 | .delay(1000)
200 | .custom(R.layout.layout_dialog)
201 | .customButton()
202 | ```
203 |
204 | `customButton()` and `customButtonReverse()` methods shouldn't be used together.
205 | They have different type interfaces.
206 |
207 | After `custombutton()` is added appearance is like picture below.
208 |
209 |
210 |
211 |
212 |
213 | You can use the `customButtonReverse()` method with same way.
214 |
215 | # Changing colors, and texts
216 |
217 | You can change all values by creating new color items with same name in your applications.
218 |
219 | ### colors.xml
220 |
221 | ````xml
222 |
223 |
224 |
225 | #fff
226 |
227 |
228 | #fff
229 |
230 |
231 |
232 | #02a8fe
233 |
234 |
235 |
236 | #4bca5e
237 |
238 |
239 | #ff6175
240 |
241 |
242 | ````
243 |
244 | ### strings.xml
245 |
246 | ````xml
247 |
248 |
249 | Rate us
250 |
251 |
252 |
253 | Remind Me Later
254 |
255 |
256 |
257 | Don\'t ask again
258 |
259 |
260 | How was your experience?
261 |
262 |
263 | Recommend us to others by rating us on Play Store
264 |
265 |
266 |
267 | ````
268 |
269 | # Adding Multiple Conditions
270 |
271 | There are two different easy way to add multiple conditions to RateMe library.
272 |
273 | ### Adding one by one
274 |
275 | You can add on by one all condition. You can add event how much you want with this way.
276 |
277 | ````kotlin
278 | Rateme.getInstance(this@App)
279 | // `addCondition(conditionName,repeatTime)`
280 | .addCondition("touch_me_event", 3)
281 | .addCondition("slide_me_event", 2)
282 | .addCondition("rotate_me_event", 4)
283 | .reminderDuration(3)
284 | ````
285 |
286 | ### Adding all as Collection
287 |
288 | Every condition represents with `Condition` object. Condition object has two variables.
289 | `count` and `type`.
290 |
291 | You can create own `Condition` object and you can add this Condition object in a ArrayList.
292 | Finally you can use `setConditionList( conditionList : ArrayList )` method.
293 |
294 | ```kotlin
295 | package com.zingat.rateme.model
296 |
297 | val conditionList = ArrayList
298 | conditionList.add( Condition( 3, "touch_me_event" ) )
299 | conditionList.add( Condition( 2, "slide_me_event" ) )
300 | conditionList.add( Condition( 4, "rotate_me_event" ) )
301 |
302 | Rateme.getInstance(this@App)
303 | .setConditionList(conditionList)
304 | .reminderDuration(3)
305 | ```
306 |
307 | ### How multiple conditions work
308 |
309 | When multiple events are added, RateMe shows dialog when one of conditions are completed and even other events
310 | completed, RateMe won't show a new dialog to user.
311 |
312 | For exameple; if `slide_me_event` condition is completed , RateMe will show a new dialog and if user click `Rate Us` or `Don't show again`
313 | buttons, even user complete the `touch_me_event` new dialog won't show. RateMe waits always the first completed condition rules.
314 | In this way user won't be disturbed multiple times.
315 |
316 |
317 |
320 |
321 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 | apply plugin: 'kotlin-android'
3 | apply plugin: 'kotlin-android-extensions'
4 | apply from: '../dependencies.gradle'
5 |
6 | android {
7 | compileSdkVersion versions.targetSdk
8 | defaultConfig {
9 | applicationId "com.zingat.rateme"
10 | minSdkVersion versions.minSdk
11 | targetSdkVersion versions.targetSdk
12 | versionCode versions.sampleVersionCode
13 | versionName versions.sampleVersionName
14 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
15 | }
16 | buildTypes {
17 | release {
18 | minifyEnabled false
19 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
20 | }
21 | }
22 |
23 | }
24 |
25 | dependencies {
26 | implementation fileTree(dir: 'libs', include: ['*.jar'])
27 | implementation project(path: ':rateme')
28 |
29 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
30 | implementation 'com.android.support:appcompat-v7:27.0.2'
31 |
32 | // Stetho
33 | implementation 'com.facebook.stetho:stetho:1.5.0'
34 | implementation 'com.facebook.stetho:stetho-okhttp3:1.5.0'
35 |
36 | testImplementation 'junit:junit:4.12'
37 | androidTestImplementation 'com.android.support.test:runner:1.0.1'
38 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
39 | }
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/zingat/ratemesample/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.zingat.ratemesample
2 |
3 | import android.support.test.InstrumentationRegistry
4 | import android.support.test.runner.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getTargetContext()
22 | assertEquals("com.zingat.rateme", appContext.packageName)
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zingat/ratemesample/App.kt:
--------------------------------------------------------------------------------
1 | package com.zingat.ratemesample
2 |
3 | import android.app.Application
4 | import android.widget.Toast
5 | import com.facebook.stetho.Stetho
6 | import com.zingat.rateme.Rateme
7 | import com.zingat.rateme.callback.RMCallback
8 | import com.zingat.rateme.callback.RMEventCallback
9 |
10 | /**
11 | * Created by ismailgungor on 26.01.2018.
12 | */
13 | class App : Application() {
14 |
15 |
16 | override fun onCreate() {
17 | super.onCreate()
18 |
19 | Stetho.initializeWithDefaults(this@App)
20 |
21 | Rateme.getInstance(this@App)
22 | .addCondition("touch_me_event", 3)
23 | .reminderDuration(3)
24 | .delay(1000)
25 | .custom(R.layout.layout_dialog)
26 | .customButton()
27 | .onRateCallback(object : RMEventCallback {
28 | override fun onEvent() {
29 | // TODO
30 | }
31 | })
32 | .onDontAskCallback(object : RMEventCallback {
33 | override fun onEvent() {
34 | // TODO
35 | }
36 | })
37 | .onRemindLaterCallback(object : RMEventCallback {
38 | override fun onEvent() {
39 | // TODO
40 | }
41 | })
42 | .onShowCallback(object : RMEventCallback {
43 | override fun onEvent() {
44 | // TODO
45 | }
46 | })
47 | .onRMCallback(object : RMCallback {
48 | override fun onEvent(eventName: String, count: Int, which: Int) {
49 | // TODO
50 | println("RMCallback eventName : $eventName")
51 | println("RMCallback count : $count")
52 | println("RMCallback which : $which")
53 | }
54 | })
55 | }
56 |
57 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/zingat/ratemesample/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.zingat.ratemesample
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.widget.Toast
8 | import com.zingat.rateme.Rateme
9 | import com.zingat.rateme.callback.RMEventCallback
10 |
11 | class MainActivity : AppCompatActivity() {
12 |
13 | var count = 0
14 |
15 | override fun onCreate(savedInstanceState: Bundle?) {
16 | super.onCreate(savedInstanceState)
17 | setContentView(R.layout.activity_main)
18 | }
19 |
20 | fun touchMe(view: View) {
21 | count += 1
22 | Rateme.getInstance(this)
23 | .addEvent("touch_me_event")
24 |
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/img_rateus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zingat/RateMe-Android/4e08e50c75e4c1dfec5167f1bc864dcccfc11f98/app/src/main/res/drawable-hdpi/img_rateus.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/img_rateus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zingat/RateMe-Android/4e08e50c75e4c1dfec5167f1bc864dcccfc11f98/app/src/main/res/drawable-mdpi/img_rateus.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/img_rateus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zingat/RateMe-Android/4e08e50c75e4c1dfec5167f1bc864dcccfc11f98/app/src/main/res/drawable-xhdpi/img_rateus.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/img_rateus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zingat/RateMe-Android/4e08e50c75e4c1dfec5167f1bc864dcccfc11f98/app/src/main/res/drawable-xxhdpi/img_rateus.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxxhdpi/img_rateus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zingat/RateMe-Android/4e08e50c75e4c1dfec5167f1bc864dcccfc11f98/app/src/main/res/drawable-xxxhdpi/img_rateus.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
11 |
16 |
21 |
26 |
31 |
36 |
41 |
46 |
51 |
56 |
61 |
66 |
71 |
76 |
81 |
86 |
91 |
96 |
101 |
106 |
111 |
116 |
121 |
126 |
131 |
136 |
141 |
146 |
151 |
156 |
161 |
166 |
171 |
172 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_dialog.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
14 |
15 |
24 |
25 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zingat/RateMe-Android/4e08e50c75e4c1dfec5167f1bc864dcccfc11f98/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zingat/RateMe-Android/4e08e50c75e4c1dfec5167f1bc864dcccfc11f98/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zingat/RateMe-Android/4e08e50c75e4c1dfec5167f1bc864dcccfc11f98/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zingat/RateMe-Android/4e08e50c75e4c1dfec5167f1bc864dcccfc11f98/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zingat/RateMe-Android/4e08e50c75e4c1dfec5167f1bc864dcccfc11f98/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zingat/RateMe-Android/4e08e50c75e4c1dfec5167f1bc864dcccfc11f98/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zingat/RateMe-Android/4e08e50c75e4c1dfec5167f1bc864dcccfc11f98/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zingat/RateMe-Android/4e08e50c75e4c1dfec5167f1bc864dcccfc11f98/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zingat/RateMe-Android/4e08e50c75e4c1dfec5167f1bc864dcccfc11f98/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zingat/RateMe-Android/4e08e50c75e4c1dfec5167f1bc864dcccfc11f98/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #009ef8
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/test/java/com/zingat/ratemesample/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.zingat.ratemesample
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/art/customButtonDialogWindow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zingat/RateMe-Android/4e08e50c75e4c1dfec5167f1bc864dcccfc11f98/art/customButtonDialogWindow.png
--------------------------------------------------------------------------------
/art/customImageDialogWindow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zingat/RateMe-Android/4e08e50c75e4c1dfec5167f1bc864dcccfc11f98/art/customImageDialogWindow.png
--------------------------------------------------------------------------------
/art/defaultRatemeDialogWindow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zingat/RateMe-Android/4e08e50c75e4c1dfec5167f1bc864dcccfc11f98/art/defaultRatemeDialogWindow.png
--------------------------------------------------------------------------------
/art/ratemelogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zingat/RateMe-Android/4e08e50c75e4c1dfec5167f1bc864dcccfc11f98/art/ratemelogo.png
--------------------------------------------------------------------------------
/art/zingatLogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zingat/RateMe-Android/4e08e50c75e4c1dfec5167f1bc864dcccfc11f98/art/zingatLogo.png
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | ext.kotlin_version = '1.2.10'
5 | repositories {
6 | google()
7 | jcenter()
8 | }
9 | dependencies {
10 | classpath 'com.android.tools.build:gradle:3.1.0'
11 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
12 | classpath "org.jetbrains.kotlin:kotlin-allopen:$kotlin_version"
13 |
14 | classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7.3'
15 | classpath 'com.github.dcendents:android-maven-gradle-plugin:1.4.1'
16 | // NOTE: Do not place your application dependencies here; they belong
17 | // in the individual module build.gradle files
18 | }
19 | }
20 |
21 | allprojects {
22 | repositories {
23 | google()
24 | jcenter()
25 | }
26 | }
27 |
28 | task clean(type: Delete) {
29 | delete rootProject.buildDir
30 | }
31 |
--------------------------------------------------------------------------------
/dependencies.gradle:
--------------------------------------------------------------------------------
1 | ext.versions = [
2 | minSdk : 15,
3 | compileSdk : 27,
4 | targetSdk : 27,
5 | buildTools : '25.0.1',
6 |
7 | publishVersion : '1.3.0',
8 | publishVersionCode: 10,
9 |
10 | sampleVersionCode : 4,
11 | sampleVersionName : '1.1.1',
12 |
13 | supportLib : '25.3.1',
14 | ]
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | org.gradle.jvmargs=-Xmx1536m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zingat/RateMe-Android/4e08e50c75e4c1dfec5167f1bc864dcccfc11f98/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Thu Apr 05 11:10:29 EET 2018
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/rateme/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: 'kotlin-android'
3 | apply plugin: "kotlin-allopen"
4 | apply from: '../dependencies.gradle'
5 |
6 | ext {
7 | bintrayRepo = 'Rateme'
8 | bintrayName = 'rateme'
9 |
10 | publishedGroupId = 'com.zingat'
11 | libraryName = 'Rateme'
12 | artifact = 'rateme'
13 |
14 | libraryDescription = 'Rateme is Android library provides to show dialog users when defined events completed.'
15 |
16 | siteUrl = 'https://github.com/zingat/RateMe-Android'
17 | gitUrl = 'https://github.com/zingat/RateMe-Android.git'
18 |
19 | libraryVersion = versions.publishVersion
20 |
21 | developerId = 'mustafaolkun'
22 | developerName = 'Mustafa Olkun'
23 | developerEmail = 'olkun.mustafa@gmail.com'
24 |
25 | licenseName = 'The Apache Software License, Version 2.0'
26 | licenseUrl = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
27 | allLicenses = ["Apache-2.0"]
28 | }
29 |
30 | android {
31 | compileSdkVersion versions.compileSdk
32 |
33 | defaultConfig {
34 | minSdkVersion versions.minSdk
35 | targetSdkVersion versions.targetSdk
36 | versionCode versions.publishVersionCode
37 | versionName versions.publishVersion
38 |
39 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
40 | }
41 |
42 | buildTypes {
43 | release {
44 | minifyEnabled false
45 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
46 | }
47 | }
48 |
49 | allOpen {
50 | annotation("com.zingat.rateme.annotations.RatemeOpen")
51 | }
52 |
53 | tasks.withType(Javadoc).all {
54 | enabled = false
55 | }
56 | }
57 |
58 | dependencies {
59 | implementation fileTree(dir: 'libs', include: ['*.jar'])
60 |
61 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
62 | implementation 'com.android.support:appcompat-v7:27.0.1'
63 |
64 | // Material Dialogs
65 | implementation 'com.afollestad.material-dialogs:core:0.9.6.0'
66 |
67 | testImplementation 'junit:junit:4.12'
68 | testImplementation 'org.assertj:assertj-core:3.9.0'
69 | testImplementation "org.mockito:mockito-core:2.13.0"
70 | testImplementation 'pl.pragmatists:JUnitParams:1.1.0'
71 |
72 | androidTestImplementation 'com.android.support.test:runner:1.0.1'
73 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
74 | }
75 | repositories {
76 | mavenCentral()
77 | }
78 |
79 | apply from: 'https://raw.githubusercontent.com/nuuneoi/JCenter/master/installv1.gradle'
80 | apply from: 'https://raw.githubusercontent.com/nuuneoi/JCenter/master/bintrayv1.gradle'
81 |
--------------------------------------------------------------------------------
/rateme/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/rateme/src/androidTest/java/com/zingat/rateme/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.zingat.rateme;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumented test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith( AndroidJUnit4.class )
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals( "com.zingat.rateme.test", appContext.getPackageName() );
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/rateme/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/rateme/src/main/java/com/zingat/rateme/CheckCondition.kt:
--------------------------------------------------------------------------------
1 | package com.zingat.rateme
2 |
3 | import com.zingat.rateme.model.Condition
4 | import com.zingat.rateme.model.Event
5 | import java.util.*
6 | import java.util.concurrent.TimeUnit
7 | import java.util.function.Predicate
8 | import kotlin.collections.ArrayList
9 |
10 | /**
11 | * Created by ismailgungor on 24.01.2018.
12 | *
13 | * @since 1.0.0
14 | */
15 | @com.zingat.rateme.annotations.RatemeOpen
16 | class CheckCondition(dataHelper: DataHelper) {
17 |
18 | var mDataHelper: DataHelper = dataHelper
19 | var mProcessName: String? = null
20 |
21 | /**
22 | * Compares the conditions and events
23 | * Conditions are provided by developer in their activity by using [Rateme.addCondition]
24 | * The data got from database by following user's behaviours with [Rateme.addEvent] method
25 | *
26 | * @param conditionList
27 | * @param eventList
28 | *
29 | * @since 1.0.0
30 | * @author ismailgungor
31 | * @return
32 | */
33 | fun isConditionsComplete(conditionList: ArrayList, eventList: ArrayList): Boolean {
34 |
35 | val currentEventMap = HashMap()
36 |
37 | eventList
38 | .map { it.getName() }
39 | .filter { it == this.mProcessName }
40 | .forEach {
41 | if (currentEventMap.containsKey(it)) {
42 | val currentValue = currentEventMap[it]!!
43 |
44 | currentEventMap[it] = currentValue + 1
45 | } else {
46 | currentEventMap[it] = 1
47 | }
48 | }
49 |
50 |
51 | for (condition in conditionList) {
52 |
53 | val currentConditionType = condition.getType()
54 | val currentConditionCount = condition.getCount()
55 |
56 | if (currentEventMap.containsKey(currentConditionType) && currentEventMap[currentConditionType] == currentConditionCount) {
57 | return true
58 | }
59 | }
60 |
61 | return false
62 | }
63 |
64 | /**
65 | * Uses to compare the current time and saved time to database
66 | * that is saved when user click remind me button.
67 | * Compares the datas by converting to day value.
68 | *
69 | * @see Rateme.remindLater
70 | * @see Rateme.reminderDuration
71 | *
72 | * @since 1.0.0
73 | * @author ismailgungor
74 | * @return true if the passed time is bigger than the selected reminder time. So we can show dialog.
75 | */
76 | fun isReminderEnd(reminderDuration: Int, reminderValue: Long): Boolean {
77 |
78 | val currentTime = Calendar.getInstance().timeInMillis
79 |
80 | val diffInMilis = currentTime - reminderValue
81 | val diffInDays = TimeUnit.MILLISECONDS.toDays(diffInMilis)
82 |
83 | return diffInDays > reminderDuration
84 |
85 | }
86 |
87 | /**
88 | * @param eventList
89 | *
90 | * @since 1.0.0
91 | * @author ismailgungor
92 | * @return true given arraylist size bigger than 0
93 | */
94 | fun isThereConditionCompletedValue(eventList: ArrayList): Boolean {
95 | return eventList.size > 0
96 | }
97 |
98 | /**
99 | * @return true if user haven't applied disable protocol.
100 | *
101 | * @since 1.0.0
102 | */
103 | fun isRatemeEnable(): Boolean {
104 | val disableList = this.mDataHelper.findByEventName(Constants.DISABLE)
105 | return disableList.size == 0
106 | }
107 |
108 | internal fun setProcessName(name: String): CheckCondition {
109 | this.mProcessName = name
110 |
111 | return this
112 | }
113 | }
--------------------------------------------------------------------------------
/rateme/src/main/java/com/zingat/rateme/ConditionHelper.kt:
--------------------------------------------------------------------------------
1 | package com.zingat.rateme
2 |
3 | import com.zingat.rateme.model.Condition
4 |
5 | class ConditionHelper {
6 |
7 | fun findGivenConditionCount( conditionList: ArrayList, conditionName : String ): Int {
8 |
9 | return conditionList
10 | .first { it.getType() == conditionName }
11 | .getCount()
12 |
13 | }
14 | }
--------------------------------------------------------------------------------
/rateme/src/main/java/com/zingat/rateme/Constants.kt:
--------------------------------------------------------------------------------
1 | package com.zingat.rateme
2 |
3 | /**
4 | * Created by mustafaolkun on 02/02/2018.
5 | */
6 | class Constants {
7 |
8 | companion object {
9 | val DISABLE : String = "disable"
10 | val CONDITION_COMPLETED = "conditionCompleted"
11 | val REMINDER = "reminder"
12 | }
13 |
14 | }
--------------------------------------------------------------------------------
/rateme/src/main/java/com/zingat/rateme/DataHelper.kt:
--------------------------------------------------------------------------------
1 | package com.zingat.rateme
2 |
3 | import android.content.Context
4 | import com.zingat.rateme.model.Event
5 |
6 | /**
7 | * Created by ismailgungor on 24.01.2018.
8 | *
9 | * Uses as controller between [DataHelper] and [Rateme]
10 | */
11 | @com.zingat.rateme.annotations.RatemeOpen
12 | class DataHelper(context: Context) {
13 |
14 | private val eventsSql: EventsSql = EventsSql(context)
15 |
16 | fun saveEvent(event: String) {
17 | this.eventsSql.save(event)
18 | }
19 |
20 | fun getAllEvents(): ArrayList {
21 | return this.eventsSql.getAll()
22 | }
23 |
24 | fun findByEventName(event: String): ArrayList {
25 | return this.eventsSql.findByName(event)
26 | }
27 |
28 | fun getReminder(): Long {
29 |
30 | val reminderList = eventsSql.findByName(Constants.REMINDER)
31 | if (reminderList.size > 0)
32 | return reminderList.get(0).getTime()
33 |
34 | return 0
35 | }
36 |
37 | fun deleteEvent(eventName: String) {
38 | this.eventsSql.delete(eventName)
39 | }
40 |
41 | fun deleteAll() {
42 | this.eventsSql.deleteAll()
43 | }
44 |
45 | }
--------------------------------------------------------------------------------
/rateme/src/main/java/com/zingat/rateme/EventsDb.kt:
--------------------------------------------------------------------------------
1 | package com.zingat.rateme
2 |
3 | import android.content.Context
4 | import android.database.sqlite.SQLiteDatabase
5 | import android.database.sqlite.SQLiteOpenHelper
6 |
7 | /**
8 | * Created by ismailgungor on 24.01.2018.
9 | *
10 | * Uses to create standart DB operations with KT.
11 | */
12 | class EventsDb(context: Context, name: String, factory: SQLiteDatabase.CursorFactory?, version: Int) : SQLiteOpenHelper(context, name, factory, version) {
13 |
14 | companion object {
15 | val DATABASE_NAME = "events_database"
16 | val DATABASE_VERSION = 1
17 | val TABLE_NAME = "table_events"
18 | val EVENT_ID = "event_id"
19 | val EVENT_NAME = "event_name"
20 | val EVENT_TIME = "event_time"
21 |
22 | }
23 |
24 | private val CREATE_TABLE = ("CREATE TABLE " + TABLE_NAME + "("
25 | + EVENT_ID + " INTEGER PRIMARY KEY AUTOINCREMENT,"
26 | + EVENT_NAME + " TEXT,"
27 | + EVENT_TIME + " LONG" + ")")
28 |
29 | override fun onCreate(db: SQLiteDatabase?) {
30 | db?.execSQL(CREATE_TABLE)
31 |
32 | }
33 |
34 | override fun onUpgrade(db: SQLiteDatabase?, p1: Int, p2: Int) {
35 | // Slient is golden
36 | }
37 |
38 |
39 | }
--------------------------------------------------------------------------------
/rateme/src/main/java/com/zingat/rateme/EventsSql.kt:
--------------------------------------------------------------------------------
1 | package com.zingat.rateme
2 |
3 | import android.content.ContentValues
4 | import android.content.Context
5 | import android.database.Cursor
6 | import android.database.SQLException
7 | import com.zingat.rateme.model.Event
8 | import java.util.*
9 | import kotlin.collections.ArrayList
10 |
11 | /**
12 | * Created by ismailgungor on 24.01.2018.
13 | *
14 | * Completes the CRUD operations for [Rateme] operations.
15 | * @since 1.0.0
16 | */
17 | class EventsSql(context: Context) {
18 |
19 | private val dbEvents: EventsDb = EventsDb(context, EventsDb.DATABASE_NAME, null, EventsDb.DATABASE_VERSION)
20 |
21 | /**
22 | * Inserts a new row with given string value.
23 | *
24 | * @see EventsDb.EVENT_NAME
25 | * @see EventsDb.EVENT_TIME
26 | *
27 | * @since 1.0.0
28 | * @author ismailgungor
29 | */
30 | fun save(event: String) {
31 |
32 | val db = dbEvents.writableDatabase
33 |
34 | val values = ContentValues()
35 | values.put(EventsDb.EVENT_NAME, event)
36 | values.put(EventsDb.EVENT_TIME, Calendar.getInstance().timeInMillis)
37 |
38 | db.insert(EventsDb.TABLE_NAME, null, values)
39 | db.close()
40 |
41 | }
42 |
43 | /**
44 | * @return an event list with given name.
45 | * @since 1.0.0
46 | * @author ismailgungor
47 | */
48 | fun findByName(eventName: String): ArrayList {
49 |
50 | val db = dbEvents.readableDatabase
51 | val eventList = ArrayList()
52 | var eventId: Int
53 | var eventTime: Long
54 | val selectQuery = "SELECT * FROM " + EventsDb.TABLE_NAME + " WHERE " + EventsDb.EVENT_NAME + "='" + eventName + "'"
55 | val cursor: Cursor
56 |
57 | try {
58 |
59 | cursor = db.rawQuery(selectQuery, null)
60 |
61 | } catch (error: SQLException) {
62 | db.close()
63 | return eventList
64 | }
65 |
66 | if (cursor.moveToFirst()) {
67 | do {
68 | eventId = cursor.getInt(0)
69 | eventTime = cursor.getLong(2)
70 |
71 | val event = Event(eventId, eventName, eventTime)
72 | eventList.add(event)
73 |
74 | } while (cursor.moveToNext())
75 | }
76 |
77 | db.close()
78 |
79 | return eventList
80 | }
81 |
82 | /**
83 | * Deletes a single or multiple rows with given name
84 | *
85 | * @since 1.0.0
86 | * @author ismailgungor
87 | */
88 | fun delete(eventName: String) {
89 | val db = dbEvents.writableDatabase
90 | val whereArgs = arrayOf(eventName)
91 | db.delete(EventsDb.TABLE_NAME, EventsDb.EVENT_NAME + " =?", whereArgs)
92 | db.close()
93 | }
94 |
95 | /**
96 | * truncate the table
97 | *
98 | * @since 1.0.0
99 | * @author ismailgungor
100 | */
101 | fun deleteAll() {
102 |
103 | val db = dbEvents.writableDatabase
104 | db.delete(EventsDb.TABLE_NAME, null, null);
105 | db.close();
106 |
107 | }
108 |
109 | /**
110 | * @return all added events
111 | *
112 | * @since 1.0.0
113 | * @author ismailgungor
114 | */
115 | fun getAll(): ArrayList {
116 |
117 | val db = dbEvents.readableDatabase
118 | val eventList = ArrayList()
119 | var eventId: Int
120 | var eventName: String
121 | var eventTime: Long
122 | val selectQuery = "SELECT * FROM " + EventsDb.TABLE_NAME
123 |
124 | val cursor: Cursor
125 |
126 | try {
127 |
128 | cursor = db.rawQuery(selectQuery, null)
129 |
130 | } catch (error: SQLException) {
131 | db.close()
132 | return eventList
133 | }
134 |
135 | if (cursor.moveToFirst()) {
136 | do {
137 |
138 | eventId = cursor.getInt(0)
139 | eventName = cursor.getString(1)
140 | eventTime = cursor.getLong(2)
141 |
142 | val event = Event(eventId, eventName, eventTime)
143 | eventList.add(event)
144 |
145 | } while (cursor.moveToNext())
146 | }
147 |
148 | db.close()
149 |
150 | return eventList
151 | }
152 |
153 |
154 | }
--------------------------------------------------------------------------------
/rateme/src/main/java/com/zingat/rateme/Rateme.kt:
--------------------------------------------------------------------------------
1 | package com.zingat.rateme
2 |
3 | import android.content.Context
4 | import android.support.v4.content.ContextCompat
5 | import com.afollestad.materialdialogs.DialogAction
6 | import com.afollestad.materialdialogs.MaterialDialog
7 | import com.zingat.rateme.model.Condition
8 | import com.zingat.rateme.model.Event
9 | import android.content.pm.PackageManager
10 | import android.content.Intent
11 | import android.net.Uri
12 | import android.os.Build
13 | import android.os.Handler
14 | import android.view.WindowManager
15 | import com.afollestad.materialdialogs.GravityEnum
16 | import com.afollestad.materialdialogs.StackingBehavior
17 | import com.zingat.rateme.callback.RMCallback
18 | import com.zingat.rateme.callback.RMEventCallback
19 |
20 | /**
21 | * Created by mustafaolkun on 24/01/2018.
22 | */
23 | @com.zingat.rateme.annotations.RatemeOpen
24 | class Rateme() {
25 |
26 | internal lateinit var context: Context
27 |
28 | constructor(context: Context) : this() {
29 | this.context = context
30 | init()
31 | }
32 |
33 | private var mConditionList: ArrayList = ArrayList()
34 | private var mDuration = 3
35 | private var packageName = ""
36 | private var mDialog: MaterialDialog? = null
37 |
38 | private var customView: Int = 0
39 | private var rateButtonBackground: Int = 0
40 | private var rateButtonTextColor: Int = R.color.rm_BtnRateTextColor
41 |
42 | private var laterButtonBackground: Int = 0
43 | private var laterButtonTextColor: Int = R.color.rm_BtnLaterTextColor
44 |
45 | private var neverButtonBackground: Int = 0
46 | private var neverButtonTextColor: Int = R.color.rm_BtnNeverTextColor
47 |
48 | private var delay: Long = 0
49 | private var customButtonFlag: Boolean = false
50 | private val conditionHelper: ConditionHelper = ConditionHelper()
51 | private lateinit var eventName: String
52 |
53 | internal lateinit var mDataHelper: DataHelper
54 | internal lateinit var mCheckCondition: CheckCondition
55 |
56 | internal var onShow: RMEventCallback? = null
57 | internal var onPositive: RMEventCallback? = null
58 | internal var onNegative: RMEventCallback? = null
59 | internal var onNeutral: RMEventCallback? = null
60 | internal var onEvent: RMCallback? = null
61 |
62 | private val STARTED: Int = -1
63 | private val POSITIVE: Int = 0
64 | private val NEUTRAL: Int = 1
65 | private val NEGATIVE: Int = 2
66 |
67 | companion object : SingletonHolder(::Rateme)
68 |
69 | // Builder Start methods
70 | fun setConditionList(conditionList: ArrayList): Rateme {
71 | this.mConditionList = conditionList
72 | return this
73 | }
74 |
75 | fun addCondition(type: String, count: Int): Rateme {
76 | val newCondition = Condition(count, type)
77 | this.mConditionList.add(newCondition)
78 | return this
79 | }
80 |
81 | fun remindLater(): Rateme {
82 | this.mDataHelper.saveEvent(Constants.REMINDER)
83 | return this
84 | }
85 |
86 | fun reminderDuration(duration: Int): Rateme {
87 | this.mDuration = duration
88 | return this
89 | }
90 |
91 | fun addEvent(eventName: String): Rateme {
92 |
93 | if (this.mCheckCondition.isRatemeEnable()) {
94 | this.eventName = eventName
95 |
96 | this.mDataHelper.saveEvent(eventName)
97 | this.create()
98 | this.process()
99 | }
100 | return this
101 | }
102 |
103 | fun custom(customView: Int): Rateme {
104 | this.customView = customView
105 |
106 | return this
107 | }
108 |
109 | fun customButton(): Rateme {
110 | this.customButtonFlag = true
111 | this.rateButtonBackground = R.drawable.rm_rate_button_background
112 | this.laterButtonBackground = R.drawable.rm_later_button_background
113 | this.neverButtonBackground = R.drawable.rm_never_button_background
114 |
115 | return this
116 | }
117 |
118 | fun customButtonReverse(): Rateme {
119 | this.customButtonFlag = true
120 | this.rateButtonBackground = R.drawable.rm_rate_button_reverse_background
121 | this.laterButtonBackground = R.drawable.rm_later_button_reverse_background
122 | this.neverButtonBackground = R.drawable.rm_never_button_reverse_background
123 |
124 | this.rateButtonTextColor = R.color.rm_defaultTextColor
125 | this.laterButtonTextColor = R.color.rm_defaultTextColor
126 | this.neverButtonTextColor = R.color.rm_defaultTextColor
127 |
128 | return this
129 | }
130 |
131 | fun delay(miliseconds: Long): Rateme {
132 | this.delay = miliseconds
133 |
134 | return this
135 | }
136 |
137 | fun onRateCallback(callback: RMEventCallback): Rateme {
138 | this.onPositive = callback
139 |
140 | return this
141 | }
142 |
143 | fun onRemindLaterCallback(callback: RMEventCallback): Rateme {
144 | this.onNegative = callback
145 |
146 | return this
147 | }
148 |
149 | fun onDontAskCallback(callback: RMEventCallback): Rateme {
150 | this.onNeutral = callback
151 |
152 | return this
153 | }
154 |
155 | fun onShowCallback(callback: RMEventCallback): Rateme {
156 | this.onShow = callback
157 |
158 | return this
159 | }
160 |
161 | fun onRMCallback(callback: RMCallback): Rateme {
162 | this.onEvent = callback
163 |
164 | return this
165 | }
166 | // Builder End methods
167 |
168 | private fun init() {
169 | this.mDataHelper = DataHelper(this.context)
170 | this.mCheckCondition = CheckCondition(this.mDataHelper)
171 | setPackageName()
172 | }
173 |
174 | internal fun process() {
175 |
176 | val reminderValue = this.mDataHelper.getReminder()
177 | val isReminderEnd = mCheckCondition.isReminderEnd(this.mDuration, reminderValue)
178 | if (isReminderEnd) {
179 |
180 | val completedList: ArrayList = this.mDataHelper.findByEventName(Constants.CONDITION_COMPLETED)
181 | val isConditonCompletedValue = mCheckCondition.isThereConditionCompletedValue(completedList)
182 |
183 | if (!isConditonCompletedValue) {
184 |
185 | val eventList: ArrayList = this.mDataHelper.getAllEvents()
186 | val isConditionComplete = mCheckCondition
187 | .setProcessName(this.eventName)
188 | .isConditionsComplete(this.mConditionList, eventList)
189 |
190 | if (isConditionComplete) {
191 | this.showDialog()
192 | }
193 |
194 | } else {
195 | this.showDialog()
196 | }
197 | }
198 | }
199 |
200 | private fun setPackageName() {
201 |
202 | try {
203 | val packageInfo = this.context.packageManager.getPackageInfo(context.packageName, 0)
204 | this.packageName = packageInfo.packageName
205 |
206 | } catch (e: PackageManager.NameNotFoundException) {
207 | e.printStackTrace()
208 | }
209 |
210 | }
211 |
212 | private fun sendUserToGooglePlay(packageName: String) {
213 | try {
214 | this.context.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + packageName)))
215 | } catch (anfe: android.content.ActivityNotFoundException) {
216 | this.context.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com/store/apps/details?id=" + packageName)))
217 | }
218 |
219 | }
220 |
221 | private fun create() {
222 |
223 | val builder: MaterialDialog.Builder = MaterialDialog.Builder(this.context)
224 | .cancelable(false)
225 |
226 | if (this.customView == 0) {
227 | this.mDialog = builder
228 | .title(context.getString(R.string.rateme_dialog_title))
229 | .content(context.getString(R.string.rateme_dialog_message))
230 | .build()
231 | } else {
232 | this.mDialog = builder.customView(customView, false)
233 | .stackingBehavior(StackingBehavior.ALWAYS).build()
234 |
235 | }
236 |
237 | this.initDialogButtons()
238 | }
239 |
240 | private fun initDialogButtons() {
241 |
242 | this.setDialogButtonsTextAndTextColor()
243 | this.setDialogButtonsClickEvents()
244 |
245 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
246 | this.setCustomSettings()
247 | }
248 |
249 | private fun setCustomSettings() {
250 | if (this.customButtonFlag) {
251 | this.mDialog?.getActionButton(DialogAction.POSITIVE)?.setStackedGravity(GravityEnum.CENTER)
252 | this.mDialog?.getActionButton(DialogAction.POSITIVE)?.setStackedSelector(ContextCompat.getDrawable(context, this.rateButtonBackground))
253 |
254 | this.mDialog?.getActionButton(DialogAction.NEGATIVE)?.setStackedGravity(GravityEnum.CENTER)
255 | this.mDialog?.getActionButton(DialogAction.NEGATIVE)?.setStackedSelector(ContextCompat.getDrawable(context, this.laterButtonBackground))
256 |
257 | this.mDialog?.getActionButton(DialogAction.NEUTRAL)?.setStackedGravity(GravityEnum.CENTER)
258 | this.mDialog?.getActionButton(DialogAction.NEUTRAL)?.setStackedSelector(ContextCompat.getDrawable(context, this.neverButtonBackground))
259 | }
260 | }
261 |
262 | private fun setDialogButtonsTextAndTextColor() {
263 |
264 | this.mDialog?.setActionButton(DialogAction.POSITIVE, context.getString(R.string.rateme_btn_rate_text))
265 | this.mDialog?.setActionButton(DialogAction.NEGATIVE, context.getString(R.string.rateme_btn_later_text))
266 | this.mDialog?.setActionButton(DialogAction.NEUTRAL, context.getString(R.string.rateme_btn_never_text))
267 |
268 | this.mDialog?.getActionButton(DialogAction.POSITIVE)?.setTextColor(ContextCompat.getColor(this.context, this.rateButtonTextColor))
269 | this.mDialog?.getActionButton(DialogAction.NEGATIVE)?.setTextColor(ContextCompat.getColor(this.context, this.laterButtonTextColor))
270 | this.mDialog?.getActionButton(DialogAction.NEUTRAL)?.setTextColor(ContextCompat.getColor(this.context, this.neverButtonTextColor))
271 | }
272 |
273 | private fun setDialogButtonsClickEvents() {
274 |
275 | this.mDialog?.getActionButton(DialogAction.POSITIVE)?.setOnClickListener {
276 | this.mDataHelper.saveEvent(Constants.DISABLE)
277 | this.onPositive?.onEvent()
278 | this.mDialog!!.dismiss()
279 | sendUserToGooglePlay(this.packageName)
280 | this.onEvent?.onEvent(
281 | this.eventName,
282 | this.conditionHelper.findGivenConditionCount(this.mConditionList, this.eventName),
283 | POSITIVE
284 | )
285 | }
286 |
287 | this.mDialog?.getActionButton(DialogAction.NEGATIVE)?.setOnClickListener {
288 | this.mDataHelper.deleteEvent(Constants.REMINDER)
289 | this.mDataHelper.deleteEvent(Constants.CONDITION_COMPLETED)
290 | this.mDataHelper.saveEvent(Constants.CONDITION_COMPLETED)
291 | remindLater()
292 | this.mDialog?.dismiss()
293 | this.onNegative?.onEvent()
294 | this.onEvent?.onEvent(
295 | this.eventName,
296 | this.conditionHelper.findGivenConditionCount(this.mConditionList, this.eventName),
297 | NEGATIVE
298 | )
299 | }
300 |
301 | // TODO seperate the disable protocol.
302 | this.mDialog?.getActionButton(DialogAction.NEUTRAL)?.setOnClickListener {
303 |
304 | this.mDataHelper.deleteAll()
305 | this.mDataHelper.saveEvent(Constants.DISABLE)
306 | this.mDialog?.dismiss()
307 | this.onNeutral?.onEvent()
308 | this.onEvent?.onEvent(
309 | this.eventName,
310 | this.conditionHelper.findGivenConditionCount(this.mConditionList, this.eventName),
311 | NEUTRAL
312 | )
313 | }
314 |
315 | }
316 |
317 | internal fun showDialog() {
318 | Handler().postDelayed(Runnable {
319 | try {
320 | this.onShow?.onEvent()
321 | this.mDialog?.show()
322 | this.onEvent?.onEvent(this.eventName, conditionHelper.findGivenConditionCount(this.mConditionList, eventName), STARTED)
323 | } catch (exception: WindowManager.BadTokenException) {
324 | exception.printStackTrace()
325 | }
326 |
327 | }, this.delay)
328 | }
329 | }
--------------------------------------------------------------------------------
/rateme/src/main/java/com/zingat/rateme/SingletonHolder.kt:
--------------------------------------------------------------------------------
1 | package com.zingat.rateme
2 |
3 | import android.content.Context
4 |
5 | /**
6 | * Created by mustafaolkun on 14/02/2018.
7 | */
8 | open class SingletonHolder(creator: (A) -> T) {
9 |
10 | private var creator: ((A) -> T)? = creator
11 | @Volatile
12 | private var instance: T? = null
13 |
14 | fun getInstance(arg: A): T {
15 | val i = instance
16 | if (i != null) {
17 | i.context = arg
18 | return i
19 | }
20 | return synchronized(this) {
21 | val i2 = instance
22 | if (i2 != null) {
23 | i2
24 | } else {
25 | val created = creator!!(arg)
26 | instance = created
27 | creator = null
28 | created
29 | }
30 | }
31 | }
32 | }
--------------------------------------------------------------------------------
/rateme/src/main/java/com/zingat/rateme/annotations/RatemeOpen.kt:
--------------------------------------------------------------------------------
1 | package com.zingat.rateme.annotations
2 |
3 | /**
4 | * Created by mustafaolkun on 29/01/2018.
5 | */
6 | @Target(AnnotationTarget.CLASS)
7 | annotation class RatemeOpen
--------------------------------------------------------------------------------
/rateme/src/main/java/com/zingat/rateme/callback/RMCallback.kt:
--------------------------------------------------------------------------------
1 | package com.zingat.rateme.callback
2 |
3 | interface RMCallback {
4 |
5 | fun onEvent( eventName : String, count : Int, which : Int )
6 |
7 | }
--------------------------------------------------------------------------------
/rateme/src/main/java/com/zingat/rateme/callback/RMEventCallback.kt:
--------------------------------------------------------------------------------
1 | package com.zingat.rateme.callback
2 |
3 | /**
4 | * Created by mustafaolkun on 15/02/2018.
5 | *
6 | * Uses to get events for special events. It can be used sepereatly for each event.
7 | * @since v1.1.5
8 | */
9 | interface RMEventCallback {
10 |
11 | fun onEvent()
12 |
13 | }
--------------------------------------------------------------------------------
/rateme/src/main/java/com/zingat/rateme/model/Condition.kt:
--------------------------------------------------------------------------------
1 | package com.zingat.rateme.model
2 |
3 | /**
4 | * Created by ismailgungor on 24.01.2018.
5 | */
6 | class Condition(count: Int, type: String) {
7 |
8 | private var mCount = count
9 | private var mType = type
10 |
11 | fun setCount(count: Int) {
12 | this.mCount = count
13 | }
14 |
15 | fun getCount(): Int {
16 |
17 | return this.mCount
18 | }
19 |
20 | fun setType(type: String) {
21 | this.mType = type
22 | }
23 |
24 | fun getType(): String {
25 | return this.mType
26 | }
27 |
28 | }
--------------------------------------------------------------------------------
/rateme/src/main/java/com/zingat/rateme/model/Event.kt:
--------------------------------------------------------------------------------
1 | package com.zingat.rateme.model
2 |
3 | /**
4 | * Created by ismailgungor on 24.01.2018.
5 | */
6 | class Event(id: Int, name: String, time: Long) {
7 |
8 | private var id: Int
9 | private var name: String
10 | private var time: Long
11 |
12 | init {
13 |
14 | this.id = id
15 | this.name = name
16 | this.time = time
17 |
18 | }
19 |
20 | fun setId(id: Int) {
21 | this.id = id
22 | }
23 |
24 | fun getId(): Int {
25 | return this.id
26 | }
27 |
28 | fun setName(name: String) {
29 | this.name = name
30 | }
31 |
32 | fun getName(): String {
33 | return this.name
34 | }
35 |
36 | fun setTime(time: Long) {
37 | this.time = time
38 | }
39 |
40 | fun getTime(): Long {
41 | return this.time
42 | }
43 |
44 | }
--------------------------------------------------------------------------------
/rateme/src/main/res/drawable/rm_later_button_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
11 |
12 |
17 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/rateme/src/main/res/drawable/rm_later_button_reverse_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
11 |
12 |
17 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/rateme/src/main/res/drawable/rm_never_button_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
11 |
12 |
17 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/rateme/src/main/res/drawable/rm_never_button_reverse_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
11 |
12 |
17 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/rateme/src/main/res/drawable/rm_rate_button_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
11 |
12 |
17 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/rateme/src/main/res/drawable/rm_rate_button_reverse_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
11 |
12 |
17 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/rateme/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | #fff
7 |
8 |
9 | #fff
10 |
11 |
12 | #02a8fe
13 |
14 |
15 | #4bca5e
16 |
17 |
18 | #ff6175
19 |
20 |
--------------------------------------------------------------------------------
/rateme/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 8dp
4 | 20dp
5 | 3dp
6 | 1dp
7 |
--------------------------------------------------------------------------------
/rateme/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | RateMe
3 |
4 |
5 | Rate us
6 |
7 |
8 | Remind Me Later
9 |
10 |
11 | Don\'t ask again
12 |
13 |
14 | How was your experience?
15 |
16 |
17 | Recommend us to others by rating us on Play Store
18 |
19 |
20 |
--------------------------------------------------------------------------------
/rateme/src/test/java/com/zingat/rateme/CheckConditionTest.kt:
--------------------------------------------------------------------------------
1 | package com.zingat.rateme
2 |
3 | import com.zingat.rateme.model.Condition
4 | import com.zingat.rateme.model.Event
5 | import org.assertj.core.api.Assertions
6 | import org.junit.Assert
7 | import org.junit.Before
8 | import org.junit.Test
9 | import org.mockito.Mock
10 | import org.mockito.Mockito
11 | import org.mockito.MockitoAnnotations
12 | import org.mockito.Spy
13 |
14 |
15 | /**
16 | * Created by mustafaolkun on 26/01/2018.
17 | */
18 | class CheckConditionTest {
19 |
20 | private val TEST_CONDITION_CONS = "testCondition"
21 | private val TEST_CONDITION_2_CONS = "testCondition2"
22 |
23 | private val TEST_REMINDER_TIME = 1516395600000 // 20/01/2018
24 | private val TEST_CURRENT_TIME = 1516654800000 // 23/01/2018
25 |
26 | @Mock
27 | private lateinit var mockDataHelper: DataHelper
28 |
29 | private lateinit var checkCondition: CheckCondition
30 |
31 | // Fakes
32 | private val fakeConditionList: ArrayList = ArrayList()
33 | private val fakeEventList: ArrayList = ArrayList()
34 |
35 | @Before
36 | fun setUp() {
37 | MockitoAnnotations.initMocks(this)
38 |
39 | this.fakeEventList.clear()
40 | this.checkCondition = CheckCondition(this.mockDataHelper)
41 | this.fakeConditionList.add(Condition(3, TEST_CONDITION_CONS))
42 | this.fakeConditionList.add(Condition(2, TEST_CONDITION_2_CONS))
43 |
44 | this.fakeEventList.add(Event(1, TEST_CONDITION_CONS, 0))
45 | this.fakeEventList.add(Event(2, TEST_CONDITION_CONS, 0))
46 | this.fakeEventList.add(Event(3, TEST_CONDITION_CONS, 0))
47 |
48 | this.fakeEventList.add(Event(4, TEST_CONDITION_2_CONS, 0))
49 | }
50 |
51 |
52 | @Test
53 | fun isConditionsComplete_ShouldReturnTrue_WhenProcessNameIsCorrect() {
54 |
55 | val result: Boolean = checkCondition
56 | .setProcessName(TEST_CONDITION_CONS)
57 | .isConditionsComplete(this.fakeConditionList, this.fakeEventList)
58 |
59 | Assertions.assertThat(result).isTrue()
60 |
61 | }
62 |
63 | @Test
64 | fun isConditionsComplete_ShouldReturnFalse_WhenGivenProcessNameConditionCountIsNotEnugh() {
65 |
66 | val result: Boolean = checkCondition
67 | .setProcessName(TEST_CONDITION_2_CONS)
68 | .isConditionsComplete(this.fakeConditionList, this.fakeEventList)
69 |
70 | Assertions.assertThat(result).isFalse()
71 |
72 | }
73 |
74 | @Test
75 | fun isConditionsComplete_ShouldReturnFalse_IfProcessNameIsEmpty() {
76 |
77 | val result: Boolean = checkCondition
78 | .setProcessName("")
79 | .isConditionsComplete(this.fakeConditionList, this.fakeEventList)
80 |
81 | Assertions.assertThat(result).isFalse()
82 |
83 | }
84 |
85 |
86 | @Test
87 | fun isConditionsComplete_ShouldReturnFalse_IfEventListCountIsMissing() {
88 |
89 | this.fakeEventList.removeAt(0)
90 |
91 | val result: Boolean = checkCondition.isConditionsComplete(this.fakeConditionList, this.fakeEventList)
92 | Assertions.assertThat(result).isFalse()
93 |
94 | }
95 |
96 | @Test
97 | fun isConditionsComplete_ShouldReturnFalse_IfEventListCountTrueButNamesAreDifferent() {
98 |
99 | this.fakeEventList.removeAt(0)
100 | this.fakeEventList.add(Event(4, TEST_CONDITION_2_CONS, 0))
101 |
102 | val result: Boolean = checkCondition.isConditionsComplete(this.fakeConditionList, this.fakeEventList)
103 | Assertions.assertThat(result).isFalse()
104 |
105 | }
106 |
107 | @Test
108 | fun isReminderEnd_ShouldReturnTrue() {
109 |
110 | val isReminderEnd: Boolean = this.checkCondition.isReminderEnd(3, TEST_REMINDER_TIME)
111 | Assertions.assertThat(isReminderEnd).isTrue()
112 | }
113 |
114 | @Test
115 | fun isRatemeEnable_ShouldReturnTrue_IfListSizeEqualToZero() {
116 |
117 | this.fakeEventList.clear()
118 | Mockito.doReturn(this.fakeEventList).`when`(this.mockDataHelper).findByEventName(Constants.DISABLE)
119 | val ratemeEnable: Boolean = this.checkCondition.isRatemeEnable()
120 | Assertions.assertThat(ratemeEnable).isTrue()
121 |
122 | }
123 | }
--------------------------------------------------------------------------------
/rateme/src/test/java/com/zingat/rateme/ConditionHelperTest.kt:
--------------------------------------------------------------------------------
1 | package com.zingat.rateme
2 |
3 | import com.zingat.rateme.model.Condition
4 | import junitparams.JUnitParamsRunner
5 | import org.assertj.core.api.Assertions
6 | import org.junit.Before
7 | import org.junit.Test
8 | import org.junit.runner.RunWith
9 | import junitparams.Parameters
10 |
11 | @RunWith(JUnitParamsRunner::class)
12 | class ConditionHelperTest {
13 |
14 | private lateinit var conditionHelper: ConditionHelper
15 | private val fakeConditionList: ArrayList = ArrayList()
16 |
17 | @Before
18 | fun setUp() {
19 | this.conditionHelper = ConditionHelper()
20 |
21 | this.fakeConditionList.add(Condition(3, "type1"))
22 | this.fakeConditionList.add(Condition(4, "type2"))
23 | this.fakeConditionList.add(Condition(5, "type3"))
24 | // type1 given twice to validate whether the count returns correct or not.
25 | this.fakeConditionList.add(Condition(5, "type1"))
26 | }
27 |
28 | @Test
29 | @Parameters("type1, 3", "type2, 4", "type3, 5")
30 | fun findGivenConditionCount_ShouldGiveCorrectCount(typeName: String, expected: Int) {
31 | val actual = this.conditionHelper.findGivenConditionCount(this.fakeConditionList, typeName)
32 |
33 | Assertions.assertThat(actual)
34 | .isEqualTo(expected)
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/rateme/src/test/java/com/zingat/rateme/RatemeTest.kt:
--------------------------------------------------------------------------------
1 | package com.zingat.rateme
2 |
3 | import com.zingat.rateme.model.Condition
4 | import com.zingat.rateme.model.Event
5 | import org.assertj.core.api.Assertions
6 | import org.junit.Before
7 | import org.junit.Test
8 | import org.mockito.ArgumentMatchers.anyList
9 | import org.mockito.Mock
10 | import org.mockito.Mockito
11 | import org.mockito.MockitoAnnotations
12 | import org.mockito.Spy
13 |
14 | /**
15 | * Created by mustafaolkun on 26/01/2018.
16 | */
17 | class RatemeTest {
18 |
19 | @Spy
20 | lateinit var rateMe: Rateme
21 |
22 | @Mock
23 | lateinit var mockDataHelper: DataHelper
24 |
25 | @Mock
26 | lateinit var mockEventList: ArrayList
27 |
28 | @Mock
29 | lateinit var mockCheckCondition: CheckCondition
30 |
31 | @Before
32 | fun setUp() {
33 | MockitoAnnotations.initMocks(this)
34 |
35 | this.rateMe.mDataHelper = this.mockDataHelper
36 | this.rateMe.mCheckCondition = this.mockCheckCondition
37 | }
38 |
39 | @Test
40 | fun startShowProcess_ShouldNotTrigger_IfIsReminderEndReturnFalse() {
41 |
42 | // When
43 | Mockito.doReturn(false).`when`(this.mockCheckCondition).isReminderEnd(Mockito.anyInt(), Mockito.anyLong())
44 |
45 | this.rateMe.process()
46 |
47 | Mockito.verify(this.mockDataHelper, Mockito.times(1)).getReminder()
48 | Mockito.verify(this.mockCheckCondition, Mockito.times(1)).isReminderEnd(Mockito.anyInt(), Mockito.anyLong())
49 | Mockito.verify(this.rateMe, Mockito.never()).showDialog()
50 | Mockito.verify(this.mockDataHelper, Mockito.never()).findByEventName( Constants.CONDITION_COMPLETED )
51 | Mockito.verify(this.mockCheckCondition, Mockito.never()).isThereConditionCompletedValue(
52 | anyList() as ArrayList
53 | )
54 | }
55 |
56 | @Test
57 | fun startShowProcess_ShouldTrigger_IfIsReminderEndReturnTrue() {
58 |
59 | // When
60 | Mockito.doReturn(true).`when`(this.mockCheckCondition).isReminderEnd(Mockito.anyInt(), Mockito.anyLong())
61 | Mockito.doReturn(this.mockEventList).`when`(this.mockDataHelper).findByEventName(Constants.CONDITION_COMPLETED)
62 | Mockito.doReturn(true).`when`(this.mockCheckCondition).isThereConditionCompletedValue( this.mockEventList )
63 | Mockito.doNothing().`when`(this.rateMe).showDialog()
64 |
65 | // Then
66 | this.rateMe.process()
67 |
68 | // Result
69 | Mockito.verify(this.rateMe, Mockito.times(1)).showDialog()
70 | Mockito.verify(this.mockDataHelper, Mockito.never()).getAllEvents()
71 | Mockito.verify(this.mockCheckCondition, Mockito.never()).isConditionsComplete(
72 | anyList() as ArrayList,
73 | anyList() as ArrayList
74 | )
75 |
76 | }
77 |
78 | }
--------------------------------------------------------------------------------
/rateme/src/test/java/com/zingat/rateme/SuiteTest.kt:
--------------------------------------------------------------------------------
1 | package com.zingat.rateme
2 |
3 | import org.junit.runner.RunWith
4 | import org.junit.runners.Suite
5 |
6 | @RunWith(Suite::class)
7 | @Suite.SuiteClasses(
8 | CheckConditionTest::class,
9 | ConditionHelperTest::class,
10 | RatemeTest::class
11 | )
12 | class SuiteTest {
13 | }
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':rateme'
2 |
--------------------------------------------------------------------------------