Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
[![GitHub Downloads](https://img.shields.io/github/downloads/django-files/android-client/total?logo=android)](https://github.com/django-files/android-client/releases/latest/download/app-release.apk)
[![GitHub Release Version](https://img.shields.io/github/v/release/django-files/android-client?logo=github)](https://github.com/django-files/android-client/releases/latest)
[![GitHub Last Commit](https://img.shields.io/github/last-commit/django-files/android-client?logo=github&label=updated)](https://github.com/django-files/android-client/pulse)
[![Lint](https://img.shields.io/github/actions/workflow/status/django-files/android-client/lint.yaml?logo=github&logoColor=white&label=lint)](https://github.com/django-files/android-client/actions/workflows/lint.yaml)
[![GitHub Last Commit](https://img.shields.io/github/last-commit/django-files/android-client?logo=github&label=updated)](https://github.com/django-files/android-client/graphs/commit-activity)
[![Release](https://img.shields.io/github/actions/workflow/status/django-files/android-client/release.yaml?logo=github&logoColor=white&label=release)](https://github.com/django-files/android-client/actions/workflows/release.yaml)
[![AGP Version](https://img.shields.io/badge/dynamic/toml?url=https%3A%2F%2Fraw.githubusercontent.com%2Fdjango-files%2Fandroid-client%2Frefs%2Fheads%2Fmaster%2Fgradle%2Flibs.versions.toml&query=%24.versions.agp&logo=gradle&label=AGP)](https://github.com/django-files/android-client/blob/master/gradle/libs.versions.toml#L2)
[![GitHub Repo Size](https://img.shields.io/github/repo-size/django-files/android-client?logo=bookstack&logoColor=white&label=repo%20size)](https://github.com/django-files/android-client)
[![GitHub Top Language](https://img.shields.io/github/languages/top/django-files/android-client?logo=htmx)](https://github.com/django-files/android-client)
[![GitHub Discussions](https://img.shields.io/github/discussions/django-files/android-client)](https://github.com/django-files/android-client/discussions)
[![GitHub Discussions](https://img.shields.io/github/discussions/django-files/android-client?logo=github)](https://github.com/django-files/android-client/discussions)
[![GitHub Forks](https://img.shields.io/github/forks/django-files/android-client?style=flat&logo=github)](https://github.com/django-files/android-client/forks)
[![GitHub Repo Stars](https://img.shields.io/github/stars/django-files/android-client?style=flat&logo=github)](https://github.com/django-files/android-client/stargazers)
[![GitHub Org Stars](https://img.shields.io/github/stars/django-files?style=flat&logo=github&label=org%20stars)](https://django-files.github.io/)
[![Discord](https://img.shields.io/discord/899171661457293343?logo=discord&logoColor=white&label=discord&color=7289da)](https://discord.gg/wXy6m2X8wY)

# Django Files Android App

[![GitHub Release](https://img.shields.io/github/v/release/django-files/android-client?style=for-the-badge&logo=android&label=Download%20Android%20APK&color=A4C639)](https://github.com/django-files/android-client/releases/latest/download/app-release.apk)
[![GitHub Release](https://img.shields.io/github/v/release/django-files/android-client?style=for-the-badge&logo=android&label=Download%20Android%20APK&color=3ddc84)](https://github.com/django-files/android-client/releases/latest/download/app-release.apk)

- [Install](#Install)
- [Setup](#Setup)
Expand Down Expand Up @@ -51,7 +53,7 @@ _If you are unsure how to install, [Obtainium](https://github.com/ImranR98/Obtai
[![Get on GitHub](https://raw.githubusercontent.com/smashedr/repo-images/refs/heads/master/android/get80/github.png)](https://github.com/django-files/android-client/releases/latest/download/app-release.apk)
[![Get on Obtainium](https://raw.githubusercontent.com/smashedr/repo-images/refs/heads/master/android/get80/obtainium.png)](https://apps.obtainium.imranr.dev/redirect?r=obtainium://add/https://github.com/django-files/android-client)

<details><summary>📲 Click to View QR Codes 📸</summary>
<details><summary>📲 Click to View QR Codes 📸 Supports Android 8 (API 26) 2017 +</summary>

[![QR Code GitHub](https://raw.githubusercontent.com/smashedr/repo-images/refs/heads/master/django-files/android/qr-code-github.png)](https://github.com/django-files/android-client/releases/latest/download/app-release.apk)

Expand Down
8 changes: 4 additions & 4 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -60,15 +60,15 @@ android {
}

compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
//kotlinOptions {
// jvmTarget = "11"
// jvmTarget = "17"
//}
tasks.withType<KotlinJvmCompile>().configureEach {
compilerOptions {
jvmTarget.set(JvmTarget.JVM_11)
jvmTarget.set(JvmTarget.JVM_17)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ class AuthorizeFragment : Fragment() {
super.onViewCreated(view, savedInstanceState)
Log.d("Authorize[onViewCreated]", "savedInstanceState: ${savedInstanceState?.size()}")

ViewCompat.setOnApplyWindowInsetsListener(binding.scrollViewLayout) { v, insets ->
ViewCompat.setOnApplyWindowInsetsListener(binding.root) { v, insets ->
val bars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.updatePadding(top = bars.top, bottom = bars.bottom)
insets
Expand Down Expand Up @@ -107,6 +107,7 @@ class AuthorizeFragment : Fragment() {

val api = ServerApi(ctx, authUrl)

// TODO: Cache methodsResponse in viewModel
lifecycleScope.launch {
val methodsResponse = api.methods()
Log.d("Authorize[onViewCreated]", "methodsResponse: $methodsResponse")
Expand All @@ -115,10 +116,10 @@ class AuthorizeFragment : Fragment() {
Log.d("Authorize[onViewCreated]", "methodsData: $methodsData")
if (methodsData != null) {
Log.d("Authorize[onViewCreated]", "siteName: ${methodsData.siteName}")
binding.siteName.text = methodsData.siteName
binding.loadingLayout.visibility = View.GONE
binding.gotoLoginBtn.visibility = View.VISIBLE
binding.addServerBtn.visibility = View.VISIBLE
_binding?.siteName?.text = methodsData.siteName
_binding?.loadingLayout?.visibility = View.GONE
_binding?.gotoLoginBtn?.visibility = View.VISIBLE
_binding?.addServerBtn?.visibility = View.VISIBLE
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,16 +65,25 @@ class LoginFragment : Fragment() {
super.onViewCreated(view, savedInstanceState)
Log.d("Login[onViewCreated]", "savedInstanceState: ${savedInstanceState?.size()}")

ViewCompat.setOnApplyWindowInsetsListener(binding.scrollViewLayout) { v, insets ->
ViewCompat.setOnApplyWindowInsetsListener(binding.root) { v, insets ->
val bars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.updatePadding(top = bars.top, bottom = bars.bottom)
insets
}

val packageInfo =
requireContext().packageManager.getPackageInfo(requireContext().packageName, 0)
val versionName = packageInfo.versionName
Log.d("Login[onViewCreated]", "versionName: $versionName")
val ctx = requireContext()

//val packageInfo = ctx.packageManager.getPackageInfo(ctx.packageName, 0)
//val formattedVersion = getString(
// R.string.version_code_string,
// packageInfo.versionName,
// packageInfo.versionCode.toString()
//)
//Log.d("showAppInfoDialog", "formattedVersion: $formattedVersion")
//binding.versionName.text = formattedVersion

val packageInfo = ctx.packageManager.getPackageInfo(ctx.packageName, 0)
binding.versionName.text = packageInfo.versionName

val authUrl = arguments?.getString("authUrl")
Log.d("Login[onViewCreated]", "authUrl: $authUrl")
Expand Down Expand Up @@ -107,7 +116,7 @@ class LoginFragment : Fragment() {
//sharedPreferences?.edit { putString("saved_url", host) }

Log.d("loginFunction", "Processing URL: $host")
val api = ServerApi(requireContext(), host)
val api = ServerApi(ctx, host)
lifecycleScope.launch {
try {
// TODO: When a session expires the server will be a duplicate...
Expand Down Expand Up @@ -160,7 +169,7 @@ class LoginFragment : Fragment() {
e.printStackTrace()
val msg = e.message ?: "Unknown Error Validating Server."
Log.i("loginFunction", "msg: $msg")
binding.hostnameText.error = "Validation Error"
_binding?.hostnameText?.error = "Validation Error"
withContext(Dispatchers.Main) {
Toast.makeText(requireContext(), msg, Toast.LENGTH_LONG).show()
}
Expand All @@ -176,11 +185,10 @@ class LoginFragment : Fragment() {
requireActivity().finishAffinity()
}
}
binding.websiteLink.setOnClickListener {
val url = binding.websiteLink.text.toString()
Log.d("websiteLink", "url: $url")
val intent = Intent(Intent.ACTION_VIEW, url.toUri())
startActivity(intent)

binding.websiteLink.paint?.isUnderlineText = true
binding.websiteLink.setOnClickListener { v ->
startActivity(Intent(Intent.ACTION_VIEW, v.tag.toString().toUri()))
}

if (authUrl != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ class LoginTwoFragment : Fragment() {
super.onViewCreated(view, savedInstanceState)
Log.d("Login[onViewCreated]", "savedInstanceState: ${savedInstanceState?.size()}")

ViewCompat.setOnApplyWindowInsetsListener(binding.scrollViewLayout) { v, insets ->
ViewCompat.setOnApplyWindowInsetsListener(binding.root) { v, insets ->
val bars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.updatePadding(top = bars.top, bottom = bars.bottom)
insets
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -385,10 +385,22 @@ class SettingsFragment : PreferenceFragmentCompat() {
.show()
}

fun Context.showFeedbackDialog() {
private fun Context.showFeedbackDialog() {
val inflater = LayoutInflater.from(this)
val view = inflater.inflate(R.layout.dialog_feedback, null)

val input = view.findViewById<EditText>(R.id.feedback_input)
val websiteLink = view.findViewById<TextView>(R.id.website_link)
val githubLink = view.findViewById<TextView>(R.id.github_link)

websiteLink.paint?.isUnderlineText = true
websiteLink.setOnClickListener {
startActivity(Intent(Intent.ACTION_VIEW, websiteLink.tag.toString().toUri()))
}
githubLink.paint?.isUnderlineText = true
githubLink.setOnClickListener {
startActivity(Intent(Intent.ACTION_VIEW, githubLink.tag.toString().toUri()))
}

val dialog = MaterialAlertDialogBuilder(this)
.setView(view)
Expand Down Expand Up @@ -417,7 +429,7 @@ class SettingsFragment : PreferenceFragmentCompat() {
putString("message", response.message())
putString("code", response.code().toString())
}
Firebase.analytics.logEvent("send_feedback_failed", params)
Firebase.analytics.logEvent("feedback_failed", params)
"Error: ${response.code()}"
}
Log.d("showFeedbackDialog", "msg: $msg")
Expand All @@ -428,67 +440,45 @@ class SettingsFragment : PreferenceFragmentCompat() {
input.error = "Feedback is Required"
}
}

input.requestFocus()

val link = view.findViewById<TextView>(R.id.github_link)
val linkText = getString(R.string.github_link, link.tag)
link.text = Html.fromHtml(linkText, Html.FROM_HTML_MODE_LEGACY)
link.movementMethod = LinkMovementMethod.getInstance()

//val imm = this.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
//imm.showSoftInput(input, InputMethodManager.SHOW_IMPLICIT)
}

dialog.setButton(AlertDialog.BUTTON_POSITIVE, "Send") { _, _ -> }
dialog.show()
}

fun Context.showAppInfoDialog() {
private fun Context.showAppInfoDialog() {
val inflater = LayoutInflater.from(this)
val view = inflater.inflate(R.layout.dialog_app_info, null)

val appId = view.findViewById<TextView>(R.id.app_identifier)
val appVersion = view.findViewById<TextView>(R.id.app_version)
val sourceLink = view.findViewById<TextView>(R.id.source_link)
val versionName = view.findViewById<TextView>(R.id.version_name)
val githubLink = view.findViewById<TextView>(R.id.github_link)
val websiteLink = view.findViewById<TextView>(R.id.website_link)
//val appInfo = view.findViewById<TextView>(R.id.open_app_info)

val sourceText = getString(R.string.github_link, sourceLink.tag)
Log.d("showAppInfoDialog", "sourceText: $sourceText")

val websiteText = getString(R.string.website_link, websiteLink.tag)
Log.d("showAppInfoDialog", "websiteText: $websiteText")
githubLink.paint?.isUnderlineText = true
githubLink.setOnClickListener {
startActivity(Intent(Intent.ACTION_VIEW, githubLink.tag.toString().toUri()))
}
websiteLink.paint?.isUnderlineText = true
websiteLink.setOnClickListener {
startActivity(Intent(Intent.ACTION_VIEW, websiteLink.tag.toString().toUri()))
}

val packageInfo = this.packageManager.getPackageInfo(this.packageName, 0)
val versionName = packageInfo.versionName
Log.d("showAppInfoDialog", "versionName: $versionName")

val formattedVersion = getString(R.string.version_string, versionName)
val formattedVersion = getString(
R.string.version_code_string,
packageInfo.versionName,
packageInfo.versionCode.toString()
)
Log.d("showAppInfoDialog", "formattedVersion: $formattedVersion")

val dialog = MaterialAlertDialogBuilder(this)
appId.text = this.packageName
versionName.text = formattedVersion

MaterialAlertDialogBuilder(this)
.setView(view)
.setNegativeButton("Close", null)
.create()

dialog.setOnShowListener {
appId.text = this.packageName
appVersion.text = formattedVersion

sourceLink.text = Html.fromHtml(sourceText, Html.FROM_HTML_MODE_LEGACY)
sourceLink.movementMethod = LinkMovementMethod.getInstance()
websiteLink.text = Html.fromHtml(websiteText, Html.FROM_HTML_MODE_LEGACY)
websiteLink.movementMethod = LinkMovementMethod.getInstance()

//appInfo.setOnClickListener {
// Log.d("appInfo", "setOnClickListener")
// val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
// data = Uri.fromParts("package", packageName, null)
// }
// startActivity(intent)
//}
}
dialog.show()
.show()
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,14 @@ import com.djangofiles.djangofiles.R
import com.djangofiles.djangofiles.db.ServerDao
import com.djangofiles.djangofiles.db.ServerDatabase
import com.djangofiles.djangofiles.work.updateStats
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.launch
import java.util.Date

class WidgetProvider : AppWidgetProvider() {

@OptIn(DelicateCoroutinesApi::class)
override fun onReceive(context: Context, intent: Intent) {
super.onReceive(context, intent)
Log.i("Widget[onReceive]", "intent: $intent")
Expand All @@ -46,8 +45,8 @@ class WidgetProvider : AppWidgetProvider() {
if (appWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) {
return
}
Log.d("Widget[onReceive]", "GlobalScope.launch: START")
GlobalScope.launch(Dispatchers.IO) {
Log.d("Widget[onReceive]", "CoroutineScope.launch: START")
CoroutineScope(SupervisorJob() + Dispatchers.IO).launch {
context.updateStats()
val appWidgetManager = AppWidgetManager.getInstance(context)
onUpdate(context, appWidgetManager, intArrayOf(appWidgetId))
Expand All @@ -56,7 +55,6 @@ class WidgetProvider : AppWidgetProvider() {
}
}

@OptIn(DelicateCoroutinesApi::class)
override fun onUpdate(
context: Context,
appWidgetManager: AppWidgetManager,
Expand Down Expand Up @@ -158,7 +156,7 @@ class WidgetProvider : AppWidgetProvider() {
//views.setOnClickPendingIntent(R.id.file_list_button, pendingIntent3)

// Room Data
GlobalScope.launch(Dispatchers.IO) {
CoroutineScope(SupervisorJob() + Dispatchers.IO).launch {
val dao: ServerDao = ServerDatabase.Companion.getInstance(context).serverDao()
Log.d("Widget[onUpdate]", "dao: $dao")
val server = dao.getByUrl(savedUrl)
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/res/drawable/fa_github.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@
android:viewportWidth="496"
android:viewportHeight="512">
<path
android:fillColor="@android:color/white"
android:fillColor="?attr/colorControlNormal"
android:pathData="M165.9,397.4c0,2 -2.3,3.6 -5.2,3.6 -3.3,0.3 -5.6,-1.3 -5.6,-3.6 0,-2 2.3,-3.6 5.2,-3.6 3,-0.3 5.6,1.3 5.6,3.6zM134.8,392.9c-0.7,2 1.3,4.3 4.3,4.9 2.6,1 5.6,0 6.2,-2s-1.3,-4.3 -4.3,-5.2c-2.6,-0.7 -5.5,0.3 -6.2,2.3zM179,391.2c-2.9,0.7 -4.9,2.6 -4.6,4.9 0.3,2 2.9,3.3 5.9,2.6 2.9,-0.7 4.9,-2.6 4.6,-4.6 -0.3,-1.9 -3,-3.2 -5.9,-2.9zM244.8,8C106.1,8 0,113.3 0,252c0,110.9 69.8,205.8 169.5,239.2 12.8,2.3 17.3,-5.6 17.3,-12.1 0,-6.2 -0.3,-40.4 -0.3,-61.4 0,0 -70,15 -84.7,-29.8 0,0 -11.4,-29.1 -27.8,-36.6 0,0 -22.9,-15.7 1.6,-15.4 0,0 24.9,2 38.6,25.8 21.9,38.6 58.6,27.5 72.9,20.9 2.3,-16 8.8,-27.1 16,-33.7 -55.9,-6.2 -112.3,-14.3 -112.3,-110.5 0,-27.5 7.6,-41.3 23.6,-58.9 -2.6,-6.5 -11.1,-33.3 2.6,-67.9 20.9,-6.5 69,27 69,27 20,-5.6 41.5,-8.5 62.8,-8.5s42.8,2.9 62.8,8.5c0,0 48.1,-33.6 69,-27 13.7,34.7 5.2,61.4 2.6,67.9 16,17.7 25.8,31.5 25.8,58.9 0,96.5 -58.9,104.2 -114.8,110.5 9.2,7.9 17,22.9 17,46.4 0,33.7 -0.3,75.4 -0.3,83.6 0,6.5 4.6,14.4 17.3,12.1C428.2,457.8 496,362.9 496,252 496,113.3 383.5,8 244.8,8zM97.2,352.9c-1.3,1 -1,3.3 0.7,5.2 1.6,1.6 3.9,2.3 5.2,1 1.3,-1 1,-3.3 -0.7,-5.2 -1.6,-1.6 -3.9,-2.3 -5.2,-1zM86.4,344.8c-0.7,1.3 0.3,2.9 2.3,3.9 1.6,1 3.6,0.7 4.3,-0.7 0.7,-1.3 -0.3,-2.9 -2.3,-3.9 -2,-0.6 -3.6,-0.3 -4.3,0.7zM118.8,380.4c-1.6,1.3 -1,4.3 1.3,6.2 2.3,2.3 5.2,2.6 6.5,1 1.3,-1.3 0.7,-4.3 -1.3,-6.2 -2.2,-2.3 -5.2,-2.6 -6.5,-1zM107.4,365.7c-1.6,1 -1.6,3.6 0,5.9 1.6,2.3 4.3,3.3 5.6,2.3 1.6,-1.3 1.6,-3.9 0,-6.2 -1.4,-2.3 -4,-3.3 -5.6,-2z"/>
</vector>
Loading
Loading