@@ -30,185 +30,185 @@ import kotlin.io.path.pathString
3030
3131@HiltViewModel
3232class NotesViewModel
33- @Inject
34- constructor (
35- @Named(IO_DISPATCHER ) private val iODispatcher: CoroutineDispatcher ,
36- private val textNotesRepo: NotesRepo <TextNote >,
37- private val graphicNotesRepo: NotesRepo <GraphicNote >,
38- private val voiceNotesRepo: NotesRepo <VoiceNote >,
39- ) : ViewModel () {
40- private val notes = MutableStateFlow (listOf<Note >())
41- private val mSaveNoteResultLiveData = MutableLiveData <SaveNoteResult >()
42- private var searchJob: Job ? = null
43-
44- @set:Inject
45- internal lateinit var memoPreferences: MemoPreferences
46-
47- companion object {
48- private const val TAG = " NotesViewModel"
49- }
50-
51- fun init (extraBlock : () -> Unit ) {
52- Log .d(TAG , " init" )
53- val root = memoPreferences.getPath()
54- val initJob =
55- viewModelScope.launch(iODispatcher) {
56- textNotesRepo.init (root)
57- graphicNotesRepo.init (root)
58- voiceNotesRepo.init (root)
59- }
60- viewModelScope.launch {
61- initJob.join()
62- extraBlock()
33+ @Inject
34+ constructor (
35+ @Named(IO_DISPATCHER ) private val iODispatcher: CoroutineDispatcher ,
36+ private val textNotesRepo: NotesRepo <TextNote >,
37+ private val graphicNotesRepo: NotesRepo <GraphicNote >,
38+ private val voiceNotesRepo: NotesRepo <VoiceNote >,
39+ ) : ViewModel () {
40+ private val notes = MutableStateFlow (listOf<Note >())
41+ private val mSaveNoteResultLiveData = MutableLiveData <SaveNoteResult >()
42+ private var searchJob: Job ? = null
43+
44+ @set:Inject
45+ internal lateinit var memoPreferences: MemoPreferences
46+
47+ companion object {
48+ private const val TAG = " NotesViewModel"
6349 }
64- }
6550
66- fun readAllNotes ( onSuccess : (notes: List < Note > ) -> Unit ) {
67- Log .d(TAG , " readAllNotes " )
68- viewModelScope.launch(iODispatcher) {
69- notes.value = textNotesRepo.read() + graphicNotesRepo.read() + voiceNotesRepo.read()
70- notes.value. let {
71- withContext( Dispatchers . Main ) {
72- notes.value = it.sortedByDescending { note -> note.resource?.modified }
73- onSuccess(notes.value )
51+ fun init ( extraBlock : () -> Unit ) {
52+ Log .d(TAG , " init " )
53+ val root = memoPreferences.getPath()
54+ val initJob =
55+ viewModelScope.launch(iODispatcher) {
56+ textNotesRepo. init (root)
57+ graphicNotesRepo. init (root)
58+ voiceNotesRepo. init (root )
7459 }
60+ viewModelScope.launch {
61+ initJob.join()
62+ extraBlock()
7563 }
7664 }
77- }
7865
79- fun searchNote (
80- keyword : String ,
81- onSuccess : (notes: List <Note >) -> Unit ,
82- ) {
83- Log .d(TAG , " searchNote" )
84- searchJob?.cancel()
85- searchJob =
66+ fun readAllNotes (onSuccess : (notes: List <Note >) -> Unit ) {
67+ Log .d(TAG , " readAllNotes" )
8668 viewModelScope.launch(iODispatcher) {
87- // Add a delay to restart the search job if there are 2 consecutive search events
88- // triggered within 0.5 second window.
89- delay(500 )
90- notes.collectLatest {
91- val filteredNotes =
92- it
93- .filter { note ->
94- note.title.contains(keyword, true )
95- }
96- // Keep the search result ordered chronologically
97- .sortedByDescending { note -> note.resource?.modified }
69+ notes.value = textNotesRepo.read() + graphicNotesRepo.read() + voiceNotesRepo.read()
70+ notes.value.let {
9871 withContext(Dispatchers .Main ) {
99- onSuccess(filteredNotes)
72+ notes.value = it.sortedByDescending { note -> note.resource?.modified }
73+ onSuccess(notes.value)
10074 }
10175 }
10276 }
103- }
104-
105- fun onSaveClick (
106- note : Note ,
107- parentNote : Note ? = null,
108- showProgress : (Boolean ) -> Unit ,
109- ) {
110- val noteResId = note.resource?.id
111- viewModelScope.launch(iODispatcher) {
112- withContext(Dispatchers .Main ) {
113- showProgress(true )
114- }
77+ }
11578
116- fun handleResult (result : SaveNoteResult ) {
117- Log .d(TAG , " handleResult: ${result.name} " )
118- if (result == SaveNoteResult .SUCCESS_NEW ||
119- result == SaveNoteResult .SUCCESS_UPDATED
120- ) {
121- if (result == SaveNoteResult .SUCCESS_NEW ) {
122- parentNote?.let { onDeleteConfirmed(listOf (parentNote)) {} }
79+ fun searchNote (
80+ keyword : String ,
81+ onSuccess : (notes: List <Note >) -> Unit ,
82+ ) {
83+ Log .d(TAG , " searchNote" )
84+ searchJob?.cancel()
85+ searchJob =
86+ viewModelScope.launch(iODispatcher) {
87+ // Add a delay to restart the search job if there are 2 consecutive search events
88+ // triggered within 0.5 second window.
89+ delay(500 )
90+ notes.collectLatest {
91+ val filteredNotes =
92+ it
93+ .filter { note ->
94+ note.title.contains(keyword, true )
95+ }
96+ // Keep the search result ordered chronologically
97+ .sortedByDescending { note -> note.resource?.modified }
98+ withContext(Dispatchers .Main ) {
99+ onSuccess(filteredNotes)
100+ }
123101 }
124- add(note, noteResId)
125102 }
126- mSaveNoteResultLiveData.postValue(result)
127- }
128- when (note) {
129- is TextNote -> {
130- textNotesRepo.save(note) { result ->
131- handleResult(result)
132- }
103+ }
104+
105+ fun onSaveClick (
106+ note : Note ,
107+ parentNote : Note ? = null,
108+ showProgress : (Boolean ) -> Unit ,
109+ ) {
110+ val noteResId = note.resource?.id
111+ viewModelScope.launch(iODispatcher) {
112+ withContext(Dispatchers .Main ) {
113+ showProgress(true )
133114 }
134115
135- is GraphicNote -> {
136- graphicNotesRepo.save(note) { result ->
137- handleResult(result)
116+ fun handleResult (result : SaveNoteResult ) {
117+ Log .d(TAG , " handleResult: ${result.name} " )
118+ if (result == SaveNoteResult .SUCCESS_NEW ||
119+ result == SaveNoteResult .SUCCESS_UPDATED
120+ ) {
121+ if (result == SaveNoteResult .SUCCESS_NEW ) {
122+ parentNote?.let { onDeleteConfirmed(listOf (parentNote)) {} }
123+ }
124+ add(note, noteResId)
138125 }
126+ mSaveNoteResultLiveData.postValue(result)
139127 }
128+ when (note) {
129+ is TextNote -> {
130+ textNotesRepo.save(note) { result ->
131+ handleResult(result)
132+ }
133+ }
134+
135+ is GraphicNote -> {
136+ graphicNotesRepo.save(note) { result ->
137+ handleResult(result)
138+ }
139+ }
140140
141- is VoiceNote -> {
142- voiceNotesRepo.save(note) { result ->
143- handleResult(result)
141+ is VoiceNote -> {
142+ voiceNotesRepo.save(note) { result ->
143+ handleResult(result)
144+ }
144145 }
145146 }
146- }
147- withContext( Dispatchers . Main ) {
148- showProgress( false )
147+ withContext( Dispatchers . Main ) {
148+ showProgress( false )
149+ }
149150 }
150151 }
151- }
152152
153- fun onDeleteConfirmed (
154- notes : List <Note >,
155- onSuccess : () -> Unit ,
156- ) {
157- viewModelScope.launch(iODispatcher) {
158- notes.forEach { note ->
159- when (note) {
160- is TextNote -> textNotesRepo.delete(note)
161- is GraphicNote -> graphicNotesRepo.delete(note)
162- is VoiceNote -> voiceNotesRepo.delete(note)
153+ fun onDeleteConfirmed (
154+ notes : List <Note >,
155+ onSuccess : () -> Unit ,
156+ ) {
157+ viewModelScope.launch(iODispatcher) {
158+ notes.forEach { note ->
159+ when (note) {
160+ is TextNote -> textNotesRepo.delete(note)
161+ is GraphicNote -> graphicNotesRepo.delete(note)
162+ is VoiceNote -> voiceNotesRepo.delete(note)
163+ }
164+ }
165+ this @NotesViewModel.notes.value =
166+ this @NotesViewModel.notes.value.toMutableList()
167+ .apply { removeAll(notes) }
168+ withContext(Dispatchers .Main ) {
169+ onSuccess.invoke()
163170 }
164- }
165- this @NotesViewModel.notes.value =
166- this @NotesViewModel.notes.value.toMutableList()
167- .apply { removeAll(notes) }
168- withContext(Dispatchers .Main ) {
169- onSuccess.invoke()
170171 }
171172 }
172- }
173173
174- private fun add (
175- note : Note ,
176- parentResId : ResourceId ? = null,
177- ) {
178- Log .d(
179- TAG ,
180- " add note with title: ${note.title} resId: ${note.resource?.id} resName: ${note.resource?.name} " ,
181- )
182- val notes = this .notes.value.toMutableList()
183- note.resource?.let {
184- notes.removeIf { it.resource?.id == (parentResId ? : note.resource?.id) }
185- }
186- if (note is VoiceNote ) {
187- note.duration = extractDuration(note.path.pathString)
174+ private fun add (
175+ note : Note ,
176+ parentResId : ResourceId ? = null,
177+ ) {
178+ Log .d(
179+ TAG ,
180+ " add note with title: ${note.title} resId: ${note.resource?.id} resName: ${note.resource?.name} " ,
181+ )
182+ val notes = this .notes.value.toMutableList()
183+ note.resource?.let {
184+ notes.removeIf { it.resource?.id == (parentResId ? : note.resource?.id) }
185+ }
186+ if (note is VoiceNote ) {
187+ note.duration = extractDuration(note.path.pathString)
188+ }
189+ notes.add(note)
190+ this .notes.value = notes
188191 }
189- notes.add(note)
190- this .notes.value = notes
191- }
192192
193- private fun remove (note : Note ) {
194- val notes = this .notes.value.toMutableList()
195- notes.remove(note)
196- this .notes.value = notes
197- }
193+ private fun remove (note : Note ) {
194+ val notes = this .notes.value.toMutableList()
195+ notes.remove(note)
196+ this .notes.value = notes
197+ }
198198
199- fun getSaveNoteResultLiveData (): LiveData <SaveNoteResult > {
200- return mSaveNoteResultLiveData
201- }
199+ fun getSaveNoteResultLiveData (): LiveData <SaveNoteResult > {
200+ return mSaveNoteResultLiveData
201+ }
202202
203- fun storageFolderNotAvailable (): Boolean {
204- return memoPreferences.storageNotAvailable()
205- }
203+ fun storageFolderNotAvailable (): Boolean {
204+ return memoPreferences.storageNotAvailable()
205+ }
206206
207- fun getStorageFolderPath (): String {
208- return memoPreferences.getPath()
209- }
207+ fun getStorageFolderPath (): String {
208+ return memoPreferences.getPath()
209+ }
210210
211- fun setLastLaunchSuccess (success : Boolean ) {
212- memoPreferences.setLastLaunchSuccess(success)
211+ fun setLastLaunchSuccess (success : Boolean ) {
212+ memoPreferences.setLastLaunchSuccess(success)
213+ }
213214 }
214- }
0 commit comments