GitLab's annual major release is around the corner. Along with a lot of new and exciting features, there will be a few breaking changes. Learn more here.

AddCalendarValidationFragment.kt 5.13 KB
Newer Older
Ricki Hirner's avatar
Ricki Hirner committed
1 2 3 4 5 6 7 8 9 10
/*
 * Copyright (c) Ricki Hirner (bitfire web engineering).
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Public License v3.0
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/gpl.html
 */

package at.bitfire.icsdroid.ui

11
import android.app.Application
Ricki Hirner's avatar
Ricki Hirner committed
12 13 14
import android.app.Dialog
import android.app.ProgressDialog
import android.os.Bundle
15
import android.util.Log
16
import androidx.fragment.app.DialogFragment
Ricki Hirner's avatar
Ricki Hirner committed
17 18
import androidx.fragment.app.activityViewModels
import androidx.fragment.app.viewModels
19
import androidx.lifecycle.AndroidViewModel
20
import androidx.lifecycle.MutableLiveData
21
import androidx.lifecycle.Observer
Ricki Hirner's avatar
Ricki Hirner committed
22
import at.bitfire.ical4android.Event
23
import at.bitfire.ical4android.ICalendar
24
import at.bitfire.icsdroid.CalendarFetcher
25
import at.bitfire.icsdroid.Constants
Ricki Hirner's avatar
Ricki Hirner committed
26
import at.bitfire.icsdroid.HttpClient
Ricki Hirner's avatar
Ricki Hirner committed
27
import at.bitfire.icsdroid.R
28 29
import okhttp3.MediaType
import java.io.InputStream
Ricki Hirner's avatar
Ricki Hirner committed
30 31 32
import java.io.InputStreamReader
import java.net.URL

33
class AddCalendarValidationFragment: DialogFragment() {
Ricki Hirner's avatar
Ricki Hirner committed
34

Ricki Hirner's avatar
Ricki Hirner committed
35 36 37 38 39
    private val titleColorModel by activityViewModels<TitleColorFragment.TitleColorModel>()
    private val credentialsModel by activityViewModels<CredentialsFragment.CredentialsModel>()

    private val validationModel by viewModels<ValidationModel>()

Ricki Hirner's avatar
Ricki Hirner committed
40 41 42

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
43

44
        validationModel.result.observe(this, Observer { info ->
Ricki Hirner's avatar
Ricki Hirner committed
45
            requireDialog().dismiss()
46

47
            val errorMessage = info.exception?.localizedMessage
48
            if (errorMessage == null) {
49
                titleColorModel.url.value = info.url.toString()
50
                if (titleColorModel.color.value == null)
Ricki Hirner's avatar
Ricki Hirner committed
51
                    titleColorModel.color.value = resources.getColor(R.color.lightblue)
52 53 54

                if (titleColorModel.title.value.isNullOrBlank())
                    titleColorModel.title.value = info.calendarName ?: info.url?.file
55

Ricki Hirner's avatar
Ricki Hirner committed
56
                parentFragmentManager
57
                        .beginTransaction()
58
                        .replace(android.R.id.content, AddCalendarDetailsFragment())
59 60 61
                        .addToBackStack(null)
                        .commitAllowingStateLoss()
            } else
Ricki Hirner's avatar
Ricki Hirner committed
62
                AlertFragment.create(errorMessage).show(parentFragmentManager, null)
63
        })
64 65

        val url = URL(titleColorModel.url.value ?: throw IllegalArgumentException("No URL given"))
66 67 68 69
        val authenticate = credentialsModel.requiresAuth.value ?: false
        validationModel.initialize(url,
                if (authenticate) credentialsModel.username.value else null,
                if (authenticate) credentialsModel.password.value else null)
Ricki Hirner's avatar
Ricki Hirner committed
70 71
    }

Ricki Hirner's avatar
Ricki Hirner committed
72
    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
Ricki Hirner's avatar
Ricki Hirner committed
73 74 75 76 77
        val progress = ProgressDialog(activity)
        progress.setMessage(getString(R.string.add_calendar_validating))
        return progress
    }

Ricki Hirner's avatar
Ricki Hirner committed
78 79 80 81 82 83 84 85 86 87
    override fun onPause() {
        super.onPause()
        HttpClient.setForeground(false)
    }

    override fun onResume() {
        super.onResume()
        HttpClient.setForeground(true)
    }

Ricki Hirner's avatar
Ricki Hirner committed
88

89
    /* activityModel and data source */
Ricki Hirner's avatar
Ricki Hirner committed
90

91
    class ValidationModel(
92 93
            application: Application
    ): AndroidViewModel(application) {
Ricki Hirner's avatar
Ricki Hirner committed
94

95
        val result = MutableLiveData<ResourceInfo>()
96
        private var initialized = false
Ricki Hirner's avatar
Ricki Hirner committed
97

98 99 100 101 102 103
        fun initialize(originalUrl: URL, username: String?, password: String?) {
            synchronized(initialized) {
                if (initialized)
                    return
                initialized = true
            }
Ricki Hirner's avatar
Ricki Hirner committed
104

105 106
            Log.i(Constants.TAG, "Validating Webcal feed $originalUrl (authentication: $username)")

107
            val info = ResourceInfo(originalUrl)
108
            val downloader = object: CalendarFetcher(getApplication(), originalUrl) {
109
                override fun onSuccess(data: InputStream, contentType: MediaType?, eTag: String?, lastModified: Long?) {
110 111
                    InputStreamReader(data, contentType?.charset() ?: Charsets.UTF_8).use { reader ->
                        val properties = mutableMapOf<String, String>()
112
                        val events = Event.eventsFromReader(reader, properties)
113

114
                        info.calendarName = properties[ICalendar.CALENDAR_NAME]
115
                        info.eventsFound = events.size
Ricki Hirner's avatar
Ricki Hirner committed
116
                    }
117

118
                    result.postValue(info)
Ricki Hirner's avatar
Ricki Hirner committed
119 120
                }

Ricki Hirner's avatar
Ricki Hirner committed
121 122 123
                override fun onNewPermanentUrl(target: URL) {
                    Log.i(Constants.TAG, "Got permanent redirect when validating, saving new URL: $target")
                    info.url = target
124 125
                }

126
                override fun onError(error: Exception) {
Ricki Hirner's avatar
Ricki Hirner committed
127
                    Log.e(Constants.TAG, "Couldn't validate calendar: $error")
128
                    info.exception = error
129
                    result.postValue(info)
130
                }
131
            }
132

133 134
            downloader.username = username
            downloader.password = password
135

136 137 138
            // directly ask for confirmation of custom certificates
            downloader.inForeground = true

139
            Thread(downloader).start()
Ricki Hirner's avatar
Ricki Hirner committed
140
        }
141

Ricki Hirner's avatar
Ricki Hirner committed
142
    }
143

Ricki Hirner's avatar
Ricki Hirner committed
144
}