-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathextensions.scala
292 lines (269 loc) · 8.35 KB
/
extensions.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
package de.tomhoefer.jogga.extensions
import android.app.{Activity, AlertDialog, ProgressDialog}
import android.util.Log
import android.content.DialogInterface
import android.view.{View, MotionEvent, ViewGroup}
import android.view.animation.{Animation, AnimationUtils, LayoutAnimationController}
import android.view.{Window, WindowManager}
import android.os.Bundle
import android.media.{SoundPool, AudioManager}
import android.content.{Context}
import android.util.AttributeSet
import android.widget.{LinearLayout, TextView}
import android.view.{View, LayoutInflater}
import de.tomhoefer.jogga.R
import android.util.Log
import android.media.MediaPlayer
/**
* Trait der Extensions fuer ViewGroup-Komponenten bereitstellt.
*
* @author tom
*
*/
trait ViewGroupExt {
this: ViewGroup =>
/**
* Methode die die View mit der id `id` laedt, an den Block `block` uebergibt und diese ebenfalls zurueckgibt
*
* @param id Id der zu ladenden View
* @param block Callback an den die View mit der id `id` uebergeben wird
* @return View mit der id `id`
*/
def withView[A <: View](id:Int)(block:A => Unit) = {
val view = findViewById(id).asInstanceOf[A]
block(view)
view
}
/**
* Methode die die View mit der id `id` laedt, intern castet und zurueck gibt
*
* @param id Id der zu ladenden View
* @return Gefundene View
*/
def findView[A <: View](id:Int) = findViewById(id).asInstanceOf[A]
/**
* Laedt eine Animatons-Ressource
*
* @param id Id der zu ladenden Animation
* @return Gefundene Animation
*/
def findAnim(id:Int) = AnimationUtils.loadAnimation(getContext, id)
/**
* Laedt die Animation mit der id `id`, gibt diesen an den block `block` weiter.
*
* @param id Zu ladende Animation
* @param block Auszufuehrender Block
* @return Gefundene Animation
*/
def withAnim(id:Int)(block: Animation => Unit) = {
val anim = findAnim(id)
block(anim)
anim
}
/**
* Laedt Layout-Animation mit der id `id`
*
* @param id Zu ladende Layoutanimations-Ressource
* @return Gefundene LayoutAnimation
*/
def findLayoutAnim(id:Int) = AnimationUtils.loadLayoutAnimation(getContext, id)
}
trait ActivityExt {
this: Activity =>
def withView[A <: View](id:Int)(block:A => Unit) = {
val view = findViewById(id).asInstanceOf[A]
block(view)
view
}
def findView[A <: View](id:Int) = findViewById(id).asInstanceOf[A]
def findAnim(id:Int) = AnimationUtils.loadAnimation(this, id)
def withAnim(id:Int)(block: Animation => Unit) = {
val anim = findAnim(id)
block(anim)
anim
}
def findLayoutAnim(id:Int) = AnimationUtils.loadLayoutAnimation(this, id)
/**
* Methode fuer Alert-Anzeige
*
* @param title Titel des Alerts
* @param message Nachricht im Alert-Fenster
* @return AlertDialog.Builder-Instanz
*/
def simpleAlert(title:String, message:CharSequence) = {
val alert = new AlertDialog.Builder(this)
alert setTitle title
alert setMessage message
alert.setPositiveButton("OK", new DialogInterface.OnClickListener() {
def onClick(dialog:DialogInterface, arg:Int) = ""
})
alert.show
alert
}
/**
* Methode fuer die Anzeige einer Fortschrittsanzeige
*
* @param message Nachricht zur Fortschrittsanzeige
* @return ProgressDialog-Instanz
*/
def simpleProgress(message:CharSequence) = {
val progress = new ProgressDialog(this)
progress setMessage message
progress setIndeterminate true
progress setProgressStyle ProgressDialog.STYLE_SPINNER
progress.show
progress
}
/**
* Helfer-Methode um die EventQueue zu befuellen
* @param Block der im Kontext des EventQueue-Thread ausgefuert werden soll
*/
def runOnGuiThread(block: => Unit) = this runOnUiThread new Runnable {
override def run() = block
}
}
/**
* Extension die die View-Klasse um Methoden erweitert.
*
* @author tom
*
*/
trait ViewExt {
val that:View
private def touchResponse(value:AnyVal) = value match {
case false => false
case _ => true
}
/**
* Methoden die den uebergebenen Block bei einem TouchEvent ausfuehrt
*
* @param callback Auszufuerender Block
*/
def touch(callback: => AnyVal) = that setOnTouchListener new View.OnTouchListener {
def onTouch(v:View, e:MotionEvent) = {
var result = false
if(e.getAction == MotionEvent.ACTION_DOWN) {
result = touchResponse(callback)
}
result
}
}
/**
* Ueberladene Methode, die die Original-Parameter View und MotionEvent zusaetzlich an den Block
* uebergeben
* @param callback Auszufuehrender Block
*/
def touch(callback:(View, MotionEvent) => AnyVal) = that setOnTouchListener new View.OnTouchListener {
def onTouch(v:View, e:MotionEvent) = touchResponse(callback(v,e))
}
}
/**
* Definiert Implizite Konvertierungen.
*
* @author tom
*
*/
object implicits {
/**
* Wrapper-Klasse fuer Animations-Objekte
*
* @param animation Original-Animation
*/
protected class RichAnimation(val animation:Animation) {
/**
* Intern wird ein gewoehnlicher AnimationListener verwendet, um die uebergebenen Bloecke
* bei deren zugehoerigen Ereignissen auszufuehren.
*
* @param start Block, der beim Start der Animation ausgefuehrt werden soll
* @param end Block, der beim Beenden der Animation ausgefuert werden soll
* @param repeat Block, der beim Wiederholen einer Animation ausgefuehrt werden soll
*/
def apply(start: => Unit = null, end: => Unit = null, repeat: => Unit = null) = {
animation.setAnimationListener(new Animation.AnimationListener {
def onAnimationStart(a:Animation) = start
def onAnimationEnd(a:Animation) = end
def onAnimationRepeat(a:Animation) = repeat
})
}
}
/**
* Wrapper-Klasse fuer View-Instanzen - Methoden aus `ViewExt` sind damit verfuegbar
*/
protected class RichView(val v:View) extends ViewExt {
val that:View = v
}
/*
* Konvertierung fuer Animationen
*/
implicit def animation2RichAnimation(a:Animation):RichAnimation = new RichAnimation(a)
/*
* Konvertierung fuer Views
*/
implicit def view2RichView(v:View):RichView = new RichView(v)
}
/**
* Basisklasse aller Jogga-Activities, die um ActivityExtensions erweitert wurde und per default Fullscreen-Format besitzt.
*
* @author tom
*
*/
class AppDefaultActivity extends Activity with ActivityExt {
/**
* Ueberschriebener onCreate-Hook
*
* @param b Bundle mit Werten der letzten Sitzung
*/
override def onCreate(b:Bundle) = {
super.onCreate(b)
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
}
def soundEffect(name:Symbol):Unit = soundPool(name)
}
/**
* Ueber den Soundpool werden Sounds geladen und mit einem Symbol assoziiert
*
* @author tom
*
*/
object soundPool {
type PairType = Pair[Symbol, Int]
protected var _context:Context = _
protected val _pool = new SoundPool(10, AudioManager.STREAM_MUSIC, 100)
protected var _sounds:Map[Symbol, Int] = _
protected var _count = 0
protected var _audioManager:AudioManager = _
/**
* Initialisierungsmethode, ueber welche die Sounds geladen und der Audio-Service gestartet wird
*
* @param context ActivityContext
* @param pairs Argument variabler Laenge mit Symbol/Werte-Paaren
* @param block Callback, der nach der Initialisierung des soundPool aufgerufen wird
*/
def onFinishedLoading(context:Context, pairs:PairType*)(block: => Unit):Unit = {
if(_sounds != null)
return block
_context = context
_audioManager = _context.getSystemService(Context.AUDIO_SERVICE).asInstanceOf[AudioManager]
val pairList = pairs.toList
_pool.setOnLoadCompleteListener(new SoundPool.OnLoadCompleteListener {
def onLoadComplete(p:SoundPool, sampled:Int, status:Int) = {
_count += 1
if(_count == pairList.size)
block
}
})
_sounds = pairList.foldLeft(Map.empty[Symbol, Int]) { (acc, it) => acc + (it._1 -> _pool.load(_context, it._2, 1)) }
}
/**
* Spiel den Sound, welcher mit *name* assoziiert ist
*
* @param name Key des abzuspielenden Sounds
* @param loop Zeigt an wie oft der Sound abgespielt werden soll. Optionaler Parameter.
*/
def apply(name:Symbol, loop:Int = 0) = {
var streamVolume = _audioManager.getStreamVolume(AudioManager.STREAM_MUSIC)
streamVolume = streamVolume / _audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC)
_pool.play(_sounds(name), 1, 1, 1, loop, 1f)
}
}