Skip to content

Commit bbbd613

Browse files
authored
Update Settings (#27)
- Update Settings - Add Login (Add Server) Dialog - Fix Transitions on File List - Fix Navigation w/ Preview Open
1 parent 6be05dc commit bbbd613

File tree

15 files changed

+428
-280
lines changed

15 files changed

+428
-280
lines changed

app/src/main/java/com/djangofiles/djangofiles/MainActivity.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import androidx.activity.result.ActivityResultLauncher
1818
import androidx.activity.result.contract.ActivityResultContracts
1919
import androidx.activity.viewModels
2020
import androidx.appcompat.app.AppCompatActivity
21+
import androidx.core.view.GravityCompat
2122
import androidx.drawerlayout.widget.DrawerLayout
2223
import androidx.navigation.NavController
2324
import androidx.navigation.NavOptions
@@ -106,6 +107,15 @@ class MainActivity : AppCompatActivity() {
106107
}
107108
}
108109

110+
// TODO: Better handle navigation when preview/login fragments are open
111+
navController.addOnDestinationChangedListener { _, destination, _ ->
112+
Log.d("DestinationChanged", "destination: $destination")
113+
when (destination.id) {
114+
R.id.nav_item_file_preview -> binding.drawerLayout.closeDrawer(GravityCompat.START)
115+
R.id.nav_item_login -> binding.drawerLayout.closeDrawer(GravityCompat.START)
116+
}
117+
}
118+
109119
filePickerLauncher =
110120
registerForActivityResult(ActivityResultContracts.OpenDocument()) { uri ->
111121
Log.d("filePickerLauncher", "uri: $uri")

app/src/main/java/com/djangofiles/djangofiles/ui/SetupFragment.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import kotlinx.coroutines.Dispatchers
2929
import kotlinx.coroutines.launch
3030
import kotlinx.coroutines.withContext
3131

32+
// TODO: Remove This and Use LoginFragment...
3233
class SetupFragment : Fragment() {
3334

3435
private var _binding: FragmentSetupBinding? = null

app/src/main/java/com/djangofiles/djangofiles/ui/files/FilesFragment.kt

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,27 @@ import android.content.Context.MODE_PRIVATE
55
import android.net.ConnectivityManager
66
import android.os.Bundle
77
import android.util.Log
8+
import android.view.Gravity
89
import android.view.LayoutInflater
910
import android.view.View
1011
import android.view.ViewGroup
12+
import android.view.ViewTreeObserver
1113
import android.widget.Toast
1214
import androidx.fragment.app.Fragment
1315
import androidx.fragment.app.viewModels
1416
import androidx.lifecycle.lifecycleScope
1517
import androidx.recyclerview.widget.LinearLayoutManager
1618
import androidx.recyclerview.widget.RecyclerView
19+
import androidx.transition.Slide
1720
import com.djangofiles.djangofiles.ServerApi
1821
import com.djangofiles.djangofiles.databinding.FragmentFilesBinding
1922
import kotlinx.coroutines.Dispatchers
2023
import kotlinx.coroutines.launch
2124
import kotlinx.coroutines.withContext
2225

23-
// TODO: Literally fucking retarded
2426
//import android.view.Gravity
2527
//import android.view.ViewTreeObserver
28+
//import androidx.core.view.doOnPreDraw
2629
//import androidx.transition.Slide
2730
//import androidx.transition.TransitionInflater
2831

@@ -48,15 +51,11 @@ class FilesFragment : Fragment() {
4851
): View {
4952
Log.d("File[onCreateView]", "savedInstanceState: ${savedInstanceState?.size()}")
5053

51-
// TODO: Literally fucking retarded
52-
//sharedElementEnterTransition = TransitionInflater.from(requireContext()).inflateTransition(android.R.transition.move)
53-
//returnTransition = Slide(Gravity.END)
54+
//enterTransition = Slide(Gravity.END)
55+
returnTransition = Slide(Gravity.END)
5456

5557
_binding = FragmentFilesBinding.inflate(inflater, container, false)
5658
val root: View = binding.root
57-
58-
//postponeEnterTransition()
59-
6059
return root
6160
}
6261

@@ -69,17 +68,18 @@ class FilesFragment : Fragment() {
6968
super.onViewCreated(view, savedInstanceState)
7069
Log.d("File[onViewCreated]", "savedInstanceState: ${savedInstanceState?.size()}")
7170

72-
// TODO: Literally fucking retarded
73-
////postponeEnterTransition()
74-
//binding.filesRecyclerView.viewTreeObserver.addOnPreDrawListener(
75-
// object : ViewTreeObserver.OnPreDrawListener {
76-
// override fun onPreDraw(): Boolean {
77-
// binding.filesRecyclerView.viewTreeObserver.removeOnPreDrawListener(this)
78-
// startPostponedEnterTransition()
79-
// return true
80-
// }
81-
// }
82-
//)
71+
Log.d("File[onViewCreated]", "DELAY: postponeEnterTransition")
72+
postponeEnterTransition()
73+
binding.filesRecyclerView.viewTreeObserver.addOnPreDrawListener(
74+
object : ViewTreeObserver.OnPreDrawListener {
75+
override fun onPreDraw(): Boolean {
76+
binding.filesRecyclerView.viewTreeObserver.removeOnPreDrawListener(this)
77+
Log.d("File[onViewCreated]", "BEGIN: startPostponedEnterTransition")
78+
startPostponedEnterTransition()
79+
return true
80+
}
81+
}
82+
)
8383

8484
val sharedPreferences =
8585
requireContext().getSharedPreferences("AppPreferences", MODE_PRIVATE)
@@ -133,6 +133,11 @@ class FilesFragment : Fragment() {
133133
Log.i("filesData[observe]", "FETCH NEW DATA")
134134
lifecycleScope.launch { getFiles(perPage) }
135135
}
136+
137+
//(view.parent as? ViewGroup)?.doOnPreDraw {
138+
// Log.i("File[onViewCreated]", "startPostponedEnterTransition")
139+
// startPostponedEnterTransition()
140+
//}
136141
}
137142

138143
viewModel.atEnd.observe(viewLifecycleOwner) {

app/src/main/java/com/djangofiles/djangofiles/ui/files/FilesPreviewFragment.kt

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,12 @@ package com.djangofiles.djangofiles.ui.files
33
import android.graphics.drawable.Drawable
44
import android.os.Bundle
55
import android.util.Log
6-
import android.view.Gravity
76
import android.view.LayoutInflater
87
import android.view.View
98
import android.view.ViewGroup
109
import android.widget.ImageView
1110
import androidx.fragment.app.Fragment
1211
import androidx.navigation.fragment.findNavController
13-
import androidx.transition.Slide
1412
import androidx.transition.TransitionInflater
1513
import com.bumptech.glide.Glide
1614
import com.bumptech.glide.load.DataSource
@@ -20,6 +18,8 @@ import com.bumptech.glide.request.target.Target
2018
import com.djangofiles.djangofiles.R
2119
import com.djangofiles.djangofiles.databinding.FragmentFilesPreviewBinding
2220

21+
//import android.view.Gravity
22+
//import androidx.transition.Slide
2323
//import androidx.navigation.fragment.navArgs
2424

2525
class FilesPreviewFragment : Fragment() {
@@ -42,12 +42,6 @@ class FilesPreviewFragment : Fragment() {
4242
savedInstanceState: Bundle?
4343
): View {
4444
Log.d("FilesPre[onCreateView]", "savedInstanceState: ${savedInstanceState?.size()}")
45-
46-
sharedElementEnterTransition =
47-
TransitionInflater.from(requireContext()).inflateTransition(android.R.transition.move)
48-
//enterTransition = Slide(Gravity.END)
49-
returnTransition = Slide(Gravity.END)
50-
5145
_binding = FragmentFilesPreviewBinding.inflate(inflater, container, false)
5246
val root: View = binding.root
5347
return root
@@ -57,7 +51,7 @@ class FilesPreviewFragment : Fragment() {
5751
super.onViewCreated(view, savedInstanceState)
5852
Log.d("FilesPre[onViewCreated]", "savedInstanceState: ${savedInstanceState?.size()}")
5953

60-
val imageView = view.findViewById<ImageView>(R.id.previewImageView)
54+
val imageView = view.findViewById<ImageView>(R.id.preview_image_view)
6155

6256
val fileId = arguments?.getInt("fileId")
6357
Log.d("FilesPreviewFragment", "fileId: $fileId")
@@ -101,7 +95,6 @@ class FilesPreviewFragment : Fragment() {
10195
.into(imageView)
10296

10397
imageView.setOnClickListener {
104-
// TODO: Literally fucking retarded
10598
//findNavController().popBackStack()
10699
findNavController().navigateUp()
107100
}
Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
package com.djangofiles.djangofiles.ui.settings
2+
3+
import android.content.Context.MODE_PRIVATE
4+
import android.os.Bundle
5+
import android.text.Html
6+
import android.text.method.LinkMovementMethod
7+
import android.util.Log
8+
import android.view.LayoutInflater
9+
import android.view.View
10+
import android.view.ViewGroup
11+
import android.widget.TextView
12+
import android.widget.Toast
13+
import androidx.core.content.edit
14+
import androidx.fragment.app.Fragment
15+
import androidx.lifecycle.lifecycleScope
16+
import androidx.navigation.NavOptions
17+
import androidx.navigation.fragment.findNavController
18+
import com.djangofiles.djangofiles.R
19+
import com.djangofiles.djangofiles.Server
20+
import com.djangofiles.djangofiles.ServerApi
21+
import com.djangofiles.djangofiles.ServerDao
22+
import com.djangofiles.djangofiles.ServerDatabase
23+
import com.djangofiles.djangofiles.databinding.FragmentLoginBinding
24+
import com.djangofiles.djangofiles.isURL
25+
import kotlinx.coroutines.Dispatchers
26+
import kotlinx.coroutines.launch
27+
import kotlinx.coroutines.withContext
28+
29+
class LoginFragment : Fragment() {
30+
private var _binding: FragmentLoginBinding? = null
31+
private val binding get() = _binding!!
32+
33+
override fun onCreate(savedInstanceState: Bundle?) {
34+
super.onCreate(savedInstanceState)
35+
Log.d("Login[onCreate]", "savedInstanceState: ${savedInstanceState?.size()}")
36+
}
37+
38+
override fun onCreateView(
39+
inflater: LayoutInflater,
40+
container: ViewGroup?,
41+
savedInstanceState: Bundle?
42+
): View {
43+
Log.d("Login[onCreateView]", "savedInstanceState: ${savedInstanceState?.size()}")
44+
_binding = FragmentLoginBinding.inflate(inflater, container, false)
45+
val root: View = binding.root
46+
return root
47+
}
48+
49+
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
50+
super.onViewCreated(view, savedInstanceState)
51+
Log.d("Login[onViewCreated]", "savedInstanceState: ${savedInstanceState?.size()}")
52+
53+
val packageInfo =
54+
requireContext().packageManager.getPackageInfo(requireContext().packageName, 0)
55+
val versionName = packageInfo.versionName
56+
Log.d("Main[onCreate]", "versionName: $versionName")
57+
58+
val link: TextView = binding.githubLink
59+
link.text = Html.fromHtml(getString(R.string.github_link), Html.FROM_HTML_MODE_LEGACY)
60+
link.movementMethod = LinkMovementMethod.getInstance()
61+
62+
// TODO: DUPLICATION: SetupFragment
63+
64+
//binding.loginHostname.setText("https://")
65+
binding.loginHostname.requestFocus()
66+
67+
val loginFunction = View.OnClickListener {
68+
Log.d("OnClickListener", "it: ${it.id}")
69+
if (it.id == R.id.add_server_login) {
70+
Log.d("OnClickListener", "LOGIN BUTTON")
71+
}
72+
val inputHost = binding.loginHostname.text.toString().trim()
73+
Log.d("setOnClickListener", "inputHost: $inputHost")
74+
val host = parseHost(inputHost)
75+
if (inputHost != host) {
76+
binding.loginHostname.setText(host)
77+
}
78+
Log.d("setOnClickListener", "host: $host")
79+
//val user = binding.loginUsername.text.toString().trim()
80+
//Log.d("setOnClickListener", "User: $user")
81+
//val pass = binding.loginPassword.text.toString().trim()
82+
//Log.d("setOnClickListener", "Pass: $pass")
83+
84+
var valid = true
85+
//if (host.isEmpty() || host == "https://") {
86+
// binding.loginHostname.error = "Required"
87+
// valid = false
88+
//}
89+
if (!isURL(host)) {
90+
binding.loginHostname.error = "Invalid Hostname"
91+
valid = false
92+
}
93+
//if (user.isEmpty()) {
94+
// binding.loginUsername.error = "Required"
95+
// valid = false
96+
//}
97+
//if (pass.isEmpty()) {
98+
// binding.loginPassword.error = "Required"
99+
// valid = false
100+
//}
101+
if (!valid) return@OnClickListener
102+
103+
val sharedPreferences =
104+
requireContext().getSharedPreferences("AppPreferences", MODE_PRIVATE)
105+
//sharedPreferences?.edit { putString("saved_url", host) }
106+
//Log.d("getSharedPreferences", "saved_url: $host")
107+
//findNavController().navigate(R.id.nav_item_home, null, NavOptions.Builder()
108+
// .setPopUpTo(R.id.nav_item_setup, true)
109+
// .build())
110+
111+
Log.d("setOnClickListener", "lifecycleScope.launch")
112+
113+
Log.d("showSettingsDialog", "Processing URL: $host")
114+
val api = ServerApi(requireContext(), host)
115+
lifecycleScope.launch {
116+
try {
117+
Log.d("showSettingsDialog", "versionName: $versionName")
118+
val response = api.version(versionName.toString())
119+
Log.d("showSettingsDialog", "response: $response")
120+
withContext(Dispatchers.Main) {
121+
if (response.isSuccessful) {
122+
Log.d("showSettingsDialog", "SUCCESS")
123+
// Save Server
124+
val dao: ServerDao =
125+
ServerDatabase.getInstance(requireContext())
126+
.serverDao()
127+
Log.d("showSettingsDialog", "dao.add Server url = $host")
128+
withContext(Dispatchers.IO) {
129+
dao.add(Server(url = host))
130+
}
131+
// Activate Server
132+
sharedPreferences.edit { putString("saved_url", host) }
133+
// Show WebView to Login
134+
if (it.id == R.id.add_server_login) {
135+
Log.d("showSettingsDialog", "Login - navigate: nav_item_home")
136+
findNavController().navigate(
137+
R.id.nav_item_home, null, NavOptions.Builder()
138+
.setPopUpTo(R.id.nav_item_login, true)
139+
.build()
140+
)
141+
} else {
142+
Log.d("showSettingsDialog", "Return - navigateUp")
143+
findNavController().navigateUp()
144+
}
145+
} else {
146+
Log.d("showSettingsDialog", "FAILURE")
147+
//input.error = "Invalid URL"
148+
binding.loginHostname.error = "Validation Error"
149+
Toast.makeText(context, "Invalid URL!", Toast.LENGTH_SHORT).show()
150+
}
151+
}
152+
} catch (e: Exception) {
153+
Log.d("showSettingsDialog", "EXCEPTION")
154+
e.printStackTrace()
155+
val msg = e.message ?: "Unknown Error Validating Server."
156+
Log.i("processUpload", "msg: $msg")
157+
binding.loginHostname.error = "Validation Error"
158+
withContext(Dispatchers.Main) {
159+
Toast.makeText(requireContext(), msg, Toast.LENGTH_LONG).show()
160+
}
161+
}
162+
}
163+
Log.d("setOnClickListener", "DONE")
164+
}
165+
166+
binding.addServerLogin.setOnClickListener(loginFunction)
167+
binding.addServerReturn.setOnClickListener(loginFunction)
168+
binding.goBack.setOnClickListener {
169+
findNavController().navigateUp()
170+
}
171+
172+
}
173+
174+
private fun parseHost(urlString: String): String {
175+
var url = urlString.trim()
176+
if (url.isEmpty()) {
177+
return ""
178+
}
179+
if (!url.lowercase().startsWith("http")) {
180+
url = "https://$url"
181+
}
182+
if (url.length < 9) {
183+
return "https://"
184+
}
185+
if (url.endsWith("/")) {
186+
url = url.substring(0, url.length - 1)
187+
}
188+
//if (!Patterns.WEB_URL.matcher(url).matches()) {
189+
// Log.d("parseHost", "Patterns.WEB_URL.matcher Failed")
190+
// return ""
191+
//}
192+
return url
193+
}
194+
}

0 commit comments

Comments
 (0)