11package com.kemalatli.bubbleonboarding
22
33import android.app.Activity
4+ import android.content.Context
45import android.graphics.Color
56import android.view.LayoutInflater
67import android.view.View
78import android.view.ViewGroup
89import androidx.annotation.ColorInt
910import androidx.annotation.LayoutRes
11+ import androidx.annotation.StyleRes
12+ import androidx.core.view.doOnLayout
1013import androidx.lifecycle.Lifecycle
1114import androidx.lifecycle.LifecycleObserver
1215import androidx.lifecycle.OnLifecycleEvent
16+ import com.google.android.material.button.MaterialButton
17+ import com.google.android.material.textview.MaterialTextView
1318import com.kemalatli.bubbleonboarding.background.BubbleBackgroundView
1419import com.kemalatli.bubbleonboarding.content.bubble.ArrowLocation
1520import com.kemalatli.bubbleonboarding.content.bubble.BubbleDrawable
@@ -34,13 +39,39 @@ class BubbleOnboarding internal constructor():LifecycleObserver, View.OnClickLis
3439 private var arrowLocation: ArrowLocation = ArrowLocation .Bottom ()
3540 private var bubbleType: BubbleType = BubbleType .SolidColor (Color .YELLOW )
3641 private var bubbleMargin: Int = 20
42+ private var bubbleId: String = " key"
43+
44+ private var title: String = " "
45+ @StyleRes
46+ private var titleTextAppearance: Int = R .style.TextAppearance_AppCompat_SearchResult_Title
47+ private var subtitle: String = " "
48+ @StyleRes
49+ private var subtitleTextAppearance: Int = R .style.TextAppearance_AppCompat_SearchResult_Subtitle
50+ private var okLabel: String = " "
51+ @StyleRes
52+ private var okLabelTextAppearance: Int = R .style.TextAppearance_AppCompat_Caption
53+ private var cancelLabel: String = " "
54+ @StyleRes
55+ private var cancelLabelTextAppearance: Int = R .style.TextAppearance_AppCompat_Caption
56+
57+ private var customViewUsed: Boolean = false
58+ private var showOnce: Boolean = false
3759
3860 companion object {
61+
62+ internal var isShowing: Boolean = false
63+
3964 fun with (activity : Activity ): BubbleOnboarding {
4065 val bubbleOnboarding = BubbleOnboarding ()
4166 bubbleOnboarding.activity= activity
4267 return bubbleOnboarding
4368 }
69+
70+ fun wasShownBefore (context : Context , bubbleId : String ): Boolean {
71+ val sharedPreference = context.getSharedPreferences(" bubbles" , Context .MODE_PRIVATE )
72+ return sharedPreference.getBoolean(bubbleId, false )
73+ }
74+
4475 }
4576
4677 fun focusInCircle (target : View ): BubbleOnboarding {
@@ -64,6 +95,7 @@ class BubbleOnboarding internal constructor():LifecycleObserver, View.OnClickLis
6495 }
6596
6697 fun customViewRes (@LayoutRes customViewRes : Int ): BubbleOnboarding {
98+ customViewUsed = true
6799 this .customViewRes = customViewRes
68100 return this
69101 }
@@ -103,27 +135,111 @@ class BubbleOnboarding internal constructor():LifecycleObserver, View.OnClickLis
103135 return this
104136 }
105137
138+ fun title (title : String ): BubbleOnboarding {
139+ this .title = title
140+ return this
141+ }
142+
143+ fun subtitle (subtitle : String ): BubbleOnboarding {
144+ this .subtitle = subtitle
145+ return this
146+ }
147+
148+ fun okLabel (okLabel : String ): BubbleOnboarding {
149+ this .okLabel = okLabel
150+ return this
151+ }
152+
153+ fun cancelLabel (cancelLabel : String ): BubbleOnboarding {
154+ this .cancelLabel = cancelLabel
155+ return this
156+ }
157+
158+ fun titleTextAppearance (titleTextAppearance : Int ): BubbleOnboarding {
159+ this .titleTextAppearance= titleTextAppearance
160+ return this
161+ }
162+
163+ fun subtitleTextAppearance (subtitleTextAppearance : Int ): BubbleOnboarding {
164+ this .subtitleTextAppearance = subtitleTextAppearance
165+ return this
166+ }
167+
168+ fun okLabelTextAppearance (okLabelTextAppearance : Int ): BubbleOnboarding {
169+ this .okLabelTextAppearance = okLabelTextAppearance
170+ return this
171+ }
172+
173+ fun cancelLabelTextAppearance (cancelLabelTextAppearance : Int ): BubbleOnboarding {
174+ this .cancelLabelTextAppearance = cancelLabelTextAppearance
175+ return this
176+ }
177+
178+ fun showOnce (bubbleId : String ): BubbleOnboarding {
179+ this .showOnce = true
180+ this .bubbleId = bubbleId
181+ return this
182+ }
183+
106184 fun show ():BubbleOnboarding {
107185 activity.let {
108- if (it== null ) return @let
109- // Lifecycle
110- this .lifecycle?.addObserver(this )
111- // Background View
112- backgroundView = BubbleBackgroundView (it)
113- backgroundView?.focalShape = focalShape
114- backgroundView?.maskColor = backColor
115- backgroundView?.setOnClickListener(this )
116- (it.window.decorView as ViewGroup ? )?.addView(backgroundView)
117- // Informative view
118- val bubble = LayoutInflater .from(it).inflate(customViewRes, null )
119- val builder = BubbleDrawable .Builder ()
120- .angle(angle)
121- .arrowWidth(arrowWidth)
122- .arrowHeight(arrowHeight)
123- .arrowLocation(arrowLocation)
124- .bubbleMargin(bubbleMargin)
125- .bubbleType(bubbleType)
126- backgroundView?.addBubble(bubble, builder)
186+
187+ // Check
188+ if (isShowing) return @let
189+ requireNotNull(it)
190+ requireNotNull(focalShape)
191+
192+ // Check if the balloon was shown before
193+ val sharedPreference = it.getSharedPreferences(" bubbles" , Context .MODE_PRIVATE )
194+ if (showOnce && sharedPreference.getBoolean(bubbleId, false )){
195+ return @let
196+ }
197+
198+ // Wait for view layout
199+ focalShape?.prepare {
200+ // Lifecycle
201+ this .lifecycle?.addObserver(this )
202+ // Background View
203+ backgroundView = BubbleBackgroundView (it)
204+ backgroundView?.focalShape = focalShape
205+ backgroundView?.maskColor = backColor
206+ backgroundView?.setOnClickListener(this )
207+ (it.window.decorView as ViewGroup ? )?.addView(backgroundView)
208+ // Informative view
209+ val bubble = LayoutInflater .from(it).inflate(customViewRes, null )
210+ // Set texts and styles
211+ if (! customViewUsed){
212+ bubble.findViewById<MaterialTextView >(R .id.title).apply {
213+ text = title
214+ setTextAppearance(context, titleTextAppearance)
215+ }
216+ bubble.findViewById<MaterialTextView >(R .id.subtitle).apply {
217+ text = subtitle
218+ setTextAppearance(context, subtitleTextAppearance)
219+ }
220+ bubble.findViewById<MaterialButton >(R .id.ok).apply {
221+ text = okLabel
222+ setTextAppearance(context, okLabelTextAppearance)
223+ setOnClickListener { clear() }
224+ }
225+ bubble.findViewById<MaterialButton >(R .id.cancel).apply {
226+ text = cancelLabel
227+ setTextAppearance(context, cancelLabelTextAppearance)
228+ setOnClickListener { clear() }
229+ }
230+ }
231+ // Build
232+ val builder = BubbleDrawable .Builder ()
233+ .angle(angle)
234+ .arrowWidth(arrowWidth)
235+ .arrowHeight(arrowHeight)
236+ .arrowLocation(arrowLocation)
237+ .bubbleMargin(bubbleMargin)
238+ .bubbleType(bubbleType)
239+ backgroundView?.addBubble(bubble, builder)
240+ isShowing = true
241+ sharedPreference.edit().putBoolean(bubbleId, true ).apply ()
242+ }
127243 }
128244 return this
129245 }
@@ -133,6 +249,7 @@ class BubbleOnboarding internal constructor():LifecycleObserver, View.OnClickLis
133249 (activity?.window?.decorView as ViewGroup ? )?.removeView(backgroundView)
134250 activity = null
135251 focalShape = null
252+ isShowing = false
136253 }
137254
138255 override fun onClick (v : View ? ) {
0 commit comments