diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..724b3d2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,50 @@ +# Built application files +*.apk +*.aar +*.ap_ +*.aab + +# Files for the ART/Dalvik VM +*.dex + +# Java class files +*.class + +# Generated files +bin/ +gen/ +out/ + +# Gradle files +.gradle/ +build/ + +# Local configuration file (sdk path, etc) +local.properties + +# Log Files +*.log + +# Android Studio Navigation editor temp files +.navigation/ + +# Android Studio captures folder +captures/ + +# IntelliJ +*.iml +.idea/workspace.xml +.idea/tasks.xml +.idea/gradle.xml +.idea/assetWizardSettings.xml +.idea/libraries +# Android Studio 3 in .gitignore file. +.idea/caches +.idea/modules.xml +.idea/*markdown*.xml + +# Keystore files +*.jks +*.keystore + +.DS_Store diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..d7f66e7 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +NextDNS Console \ No newline at end of file diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 0000000..88ea3aa --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,122 @@ + + + + + + + + + +
+ + + + xmlns:android + + ^$ + + + +
+
+ + + + xmlns:.* + + ^$ + + + BY_NAME + +
+
+ + + + .*:id + + http://schemas.android.com/apk/res/android + + + +
+
+ + + + .*:name + + http://schemas.android.com/apk/res/android + + + +
+
+ + + + name + + ^$ + + + +
+
+ + + + style + + ^$ + + + +
+
+ + + + .* + + ^$ + + + BY_NAME + +
+
+ + + + .* + + http://schemas.android.com/apk/res/android + + + ANDROID_ATTRIBUTE_ORDER + +
+
+ + + + .* + + .* + + + BY_NAME + +
+
+
+
+ + +
+
\ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..79ee123 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/dictionaries/vansh.xml b/.idea/dictionaries/vansh.xml new file mode 100644 index 0000000..ae35b3e --- /dev/null +++ b/.idea/dictionaries/vansh.xml @@ -0,0 +1,15 @@ + + + + blocklist + blocklists + cryptojacking + csam + gafam + parentalcontrol + restrictable + tlds + typosquatting + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..7bfef59 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,9 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/navEditor.xml b/.idea/navEditor.xml new file mode 100644 index 0000000..60d0d84 --- /dev/null +++ b/.idea/navEditor.xml @@ -0,0 +1,127 @@ + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml new file mode 100644 index 0000000..7f68460 --- /dev/null +++ b/.idea/runConfigurations.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..b254509 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +NextDNSConsole diff --git a/api/build.gradle b/api/build.gradle new file mode 100644 index 0000000..64aa1fa --- /dev/null +++ b/api/build.gradle @@ -0,0 +1,13 @@ +apply plugin: 'java-library' +apply plugin: 'kotlin' + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + implementation "com.squareup.retrofit2:retrofit:2.8.1" + implementation "com.squareup.retrofit2:converter-moshi:2.8.1" + implementation "com.squareup.retrofit2:converter-scalars:2.8.1" + implementation project(":model") +} + +sourceCompatibility = "8" +targetCompatibility = "8" diff --git a/api/src/main/java/sh/van/nextdns/api/NextDNSService.kt b/api/src/main/java/sh/van/nextdns/api/NextDNSService.kt new file mode 100644 index 0000000..8e6251c --- /dev/null +++ b/api/src/main/java/sh/van/nextdns/api/NextDNSService.kt @@ -0,0 +1,298 @@ +package sh.van.nextdns.api + +import okhttp3.CookieJar +import okhttp3.OkHttpClient +import retrofit2.Retrofit +import retrofit2.converter.moshi.MoshiConverterFactory +import retrofit2.converter.scalars.ScalarsConverterFactory +import retrofit2.http.* +import sh.van.nextdns.model.* + +interface NextDNSService { + companion object { + private lateinit var service: NextDNSService + fun get(cookieJar: CookieJar): NextDNSService { + if (!::service.isInitialized) { + service = Retrofit.Builder() + .client(OkHttpClient.Builder().cookieJar(cookieJar).build()) + .baseUrl("https://api.nextdns.io") + .addConverterFactory(MoshiConverterFactory.create()) + .addConverterFactory(ScalarsConverterFactory.create()) + .build() + .create(NextDNSService::class.java) + + } + return service + } + } + + @POST("/accounts/@login") + suspend fun login(@Body loginRequest: LoginRequest) // TODO: error? + + @GET("/accounts/@me") + suspend fun getProfile( + @Query("withConfigurations") withConfigurations: Boolean = true + ): Profile + + @GET("/account") + suspend fun getAccount(): Account + + @GET("/configurations/{configId}/setup") + suspend fun getSetup(@Path("configId") configId: String): Setup + + @PATCH("/configurations/{configId}/setup") + suspend fun addDDNS( + @Path("configId") configId: String, + @Body addDDNSRequest: AddDDNSRequest + ): Setup + + @GET("/configurations/{configId}/security") + suspend fun getSecurity(@Path("configId") configId: String): Security + + @PATCH("/configurations/{configId}/security") + suspend fun updateSecurity( + @Path("configId") configId: String, + @Body updatedSecurity: Security + ): String + + @GET("/configurations/{configId}/security/blocked_tlds/@all") + suspend fun getBlockableTLDs(@Path("configId") configId: String): BlockableTLDs + + @GET("/configurations/{configId}/privacy") + suspend fun getPrivacy(@Path("configId") configId: String): Privacy + + @GET("/configurations/{configId}/privacy/blocklists/@all") + suspend fun getAllAvailableBlocklists(@Path("configId") configId: String): List + + @PUT("/configurations/{configId}/privacy/blocklists/hex:{hexEncodedId}") + suspend fun addBlocklist( + @Path("configId") configId: String, + @Path("hexEncodedId") hexEncodedId: String + ): String + + @DELETE("/configurations/{configId}/privacy/blocklists/hex:{hexEncodedId}") + suspend fun removeBlocklist( + @Path("configId") configId: String, + @Path("hexEncodedId") hexEncodedId: String + ): String + + @GET("/configurations/{configId}/parentalcontrol") + suspend fun getParentalControl(@Path("configId") configId: String): ParentalControl + + @PATCH("/configurations/{configId}/parentalcontrol") + suspend fun updateParentalControl(@Path("configId") configId: String): ParentalControl + + @GET("/configurations/{configId}/parentalcontrol/services/@all") + suspend fun getRestrictableServices( + @Path("configId") configId: String + ): List + + @PUT("/configurations/{configId}/parentalcontrol/services/hex:{hexEncodedId}") + suspend fun addRestrictedService( + @Path("configId") configId: String, + @Path("hexEncodedId") hexEncodedId: String + ): String + + @DELETE("/configurations/{configId}/parentalcontrol/services/hex:{hexEncodedId}") + suspend fun removeRestrictedService( + @Path("configId") configId: String, + @Path("hexEncodedId") hexEncodedId: String + ): String + + @PATCH("/configurations/{configId}/parentalcontrol/services/hex:{hexEncodedId}") + suspend fun setRestrictedServiceActive( + @Path("configId") configId: String, + @Path("hexEncodedId") hexEncodedId: String, + @Body active: Active + ): String + + @PUT("/configurations/{configId}/parentalcontrol/categories/hex:{hexEncodedId}") + suspend fun addRestrictedServiceCategory( + @Path("configId") configId: String, + @Path("hexEncodedId") hexEncodedId: String + ): String + + @DELETE("/configurations/{configId}/parentalcontrol/categories/hex:{hexEncodedId}") + suspend fun removeRestrictedServiceCategory( + @Path("configId") configId: String, + @Path("hexEncodedId") hexEncodedId: String + ): String + + @PATCH("/configurations/{configId}/parentalcontrol/categories/hex:{hexEncodedId}") + suspend fun setRestrictedServiceCategoryActive( + @Path("configId") configId: String, + @Path("hexEncodedId") hexEncodedId: String, + @Body active: Active + ): String + + @GET("/configurations/{configId}/blacklist") + suspend fun getBlacklist(@Path("configId") configId: String): List + + @PUT("/configurations/{configId}/blacklist/hex:{hexEncodedId}") + suspend fun addBlacklistItem( + @Path("configId") configId: String, + @Path("hexEncodedId") hexEncodedId: String + ): AccessControlListItem + + @PATCH("/configurations/{configId}/blacklist/hex:{hexEncodedId}") + suspend fun setBlacklistItemActive( + @Path("configId") configId: String, + @Path("hexEncodedId") hexEncodedId: String, + @Body active: Active + ): String + + @DELETE("/configurations/{configId}/blacklist/hex:{hexEncodedId}") + suspend fun removeBlacklistItem( + @Path("configId") configId: String, + @Path("hexEncodedId") hexEncodedId: String + ): String + + @GET("/configurations/{configId}/whitelist") + suspend fun getWhitelist(@Path("configId") configId: String): List + + @PUT("/configurations/{configId}/whitelist/hex:{hexEncodedId}") + suspend fun addWhitelistItem( + @Path("configId") configId: String, + @Path("hexEncodedId") hexEncodedId: String + ): AccessControlListItem + + @PATCH("/configurations/{configId}/whitelist/hex:{hexEncodedId}") + suspend fun setWhitelistItemActive( + @Path("configId") configId: String, + @Path("hexEncodedId") hexEncodedId: String, + @Body active: Active + ): String + + @DELETE("/configurations/{configId}/whitelist/hex:{hexEncodedId}") + suspend fun removeWhitelistItem( + @Path("configId") configId: String, + @Path("hexEncodedId") hexEncodedId: String + ): String + + @GET("/configurations/{configId}/analytics/counters") + suspend fun getCounters( + @Path("configId") configId: String, + @Query("from") from: String? = null, + @Query("timezoneOffset") timezoneOffset: Int? = null + ): Counters + + @GET("/configurations/{configId}/analytics/resolved") + suspend fun getTopResolvedDomains( + @Path("configId") configId: String, + @Query("from") from: String? = null, + @Query("timezoneOffset") timezoneOffset: Int? = null + ): List + + @GET("/configurations/{configId}/analytics/blocked") + suspend fun getTopBlockedDomains( + @Path("configId") configId: String, + @Query("from") from: String? = null, + @Query("timezoneOffset") timezoneOffset: Int? = null + ): List + + @GET("/configurations/{configId}/analytics/top_lists") + suspend fun getTopBlockedReasons( + @Path("configId") configId: String, + @Query("from") from: String? = null, + @Query("timezoneOffset") timezoneOffset: Int? = null + ): List + + @GET("/configurations/{configId}/analytics/top_devices") + suspend fun getTopDevices( + @Path("configId") configId: String, + @Query("from") from: String? = null, + @Query("timezoneOffset") timezoneOffset: Int? = null + ): List + + @GET("/configurations/{configId}/analytics/top_client_ips") + suspend fun getClientIPAnalytics( + @Path("configId") configId: String, + @Query("from") from: String? = null, + @Query("timezoneOffset") timezoneOffset: Int? = null + ): List + + @GET("/configurations/{configId}/analytics/top_root_domains") + suspend fun getTopRootDomains( + @Path("configId") configId: String, + @Query("from") from: String? = null, + @Query("timezoneOffset") timezoneOffset: Int? = null + ): List + + @GET("/configurations/{configId}/analytics/secure_dns") + suspend fun getSecureDNSStats( + @Path("configId") configId: String, + @Query("from") from: String? = null, + @Query("timezoneOffset") timezoneOffset: Int? = null + ): SecureDNSStats + + @GET("/configurations/{configId}/analytics/dnssec") + suspend fun getDNSSECStats( + @Path("configId") configId: String, + @Query("from") from: String? = null, + @Query("timezoneOffset") timezoneOffset: Int? = null + ): DNSSECStats + + @GET("/configurations/{configId}/analytics/queries_chart") + suspend fun getQueriesChart( + @Path("configId") configId: String, + @Query("from") from: String? = null, + @Query("timezoneOffset") timezoneOffset: Int? = null + ): List + + @GET("/configurations/{configId}/analytics/gafam") + suspend fun getGAFAM( + @Path("configId") configId: String, + @Query("from") from: String? = null, + @Query("timezoneOffset") timezoneOffset: Int? = null + ): List + + @GET("/configurations/{configId}/analytics/traffic_destination_countries") + suspend fun getTrafficDestinationCountries( + @Path("configId") configId: String, + @Query("from") from: String? = null, + @Query("timezoneOffset") timezoneOffset: Int? = null + ): Map + + @GET("/configurations/{configId}/logs") + suspend fun getLogs( + @Path("configId") configId: String, + @Query("search") search: String? = null, + @Query("before") before: Long? = null, + @Query("after") after: Long? = null, + @Query("blockedQueriesOnly") blockedQueriesOnly: Boolean? = null + ): Logs + + @DELETE("/configurations/{configId}/logs") + suspend fun clearLogs( + @Path("configId") configId: String + ): String + + @GET("/configurations/{configId}/settings") + suspend fun getSettings(@Path("configId") configId: String): Settings + + @PATCH("/configurations/{configId}/settings") + suspend fun updateSettings( + @Path("configId") configId: String, + @Body settings: Settings + ): String + + @POST("/configurations/{configId}/settings/rewrites") + suspend fun addRewrite( + @Path("configId") configId: String, + @Body rewrite: Rewrite + ): Rewrite + + @DELETE("/configurations/{configId}/settings/rewrites/{rewriteId}") + suspend fun removeRewrite( + @Path("configId") configId: String, + @Path("rewriteId") rewriteId: String + ): String + + @DELETE("/configurations/{configId}") + suspend fun deleteConfiguration(@Path("configId") configId: String): String + + + // This should be handled within the app by an image loading lib +// @GET("https://favicons.nextdns.io/hex:{hexEncodedId}@2x.png") +// suspend fun getFaviconForService(@Path("hexEncodedId") hexEncodedId: String) +} diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..ab186f0 --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,54 @@ +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply plugin: 'kotlin-android-extensions' + +android { + compileSdkVersion 29 + defaultConfig { + applicationId "sh.van.nextdnsconsole" + minSdkVersion 26 + targetSdkVersion 29 + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = "1.8" + } + viewBinding { + enabled = true + } +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + implementation "androidx.core:core-ktx:1.2.0" + implementation "androidx.appcompat:appcompat:1.1.0" + implementation "androidx.legacy:legacy-support-v4:1.0.0" + implementation "androidx.constraintlayout:constraintlayout:1.1.3" + implementation "androidx.navigation:navigation-fragment:2.2.2" + implementation "androidx.navigation:navigation-ui:2.2.2" + implementation "androidx.lifecycle:lifecycle-extensions:2.2.0" + implementation "androidx.navigation:navigation-fragment-ktx:2.2.2" + implementation "androidx.navigation:navigation-ui-ktx:2.2.2" + implementation "androidx.security:security-crypto:1.0.0-rc01" + implementation "com.google.android.material:material:1.1.0" + implementation "com.jakewharton.timber:timber:4.7.1" + implementation "com.github.franmontiel:PersistentCookieJar:v1.0.1" + implementation project(":model") + implementation project(":api") + testImplementation "junit:junit:4.12" + androidTestImplementation "androidx.test.ext:junit:1.1.1" + androidTestImplementation "androidx.test.espresso:espresso-core:3.2.0" +} diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..f1b4245 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/app/src/androidTest/java/sh/van/nextdnsconsole/ExampleInstrumentedTest.kt b/app/src/androidTest/java/sh/van/nextdnsconsole/ExampleInstrumentedTest.kt new file mode 100644 index 0000000..d22f053 --- /dev/null +++ b/app/src/androidTest/java/sh/van/nextdnsconsole/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package sh.van.nextdnsconsole + +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.ext.junit.runners.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("sh.van.nextdnsconsole", appContext.packageName) + } +} diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..afa529a --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + diff --git a/app/src/main/java/sh/van/nextdnsconsole/App.kt b/app/src/main/java/sh/van/nextdnsconsole/App.kt new file mode 100644 index 0000000..c0efe5f --- /dev/null +++ b/app/src/main/java/sh/van/nextdnsconsole/App.kt @@ -0,0 +1,13 @@ +package sh.van.nextdnsconsole + +import android.app.Application +import timber.log.Timber + +class App: Application() { + override fun onCreate() { + super.onCreate() + if (BuildConfig.DEBUG) { + Timber.plant(Timber.DebugTree()) + } + } +} diff --git a/app/src/main/java/sh/van/nextdnsconsole/MainActivity.kt b/app/src/main/java/sh/van/nextdnsconsole/MainActivity.kt new file mode 100644 index 0000000..0738b69 --- /dev/null +++ b/app/src/main/java/sh/van/nextdnsconsole/MainActivity.kt @@ -0,0 +1,37 @@ +package sh.van.nextdnsconsole + +import android.os.Bundle +import android.view.Menu +import androidx.appcompat.app.AppCompatActivity +import androidx.appcompat.widget.Toolbar +import androidx.drawerlayout.widget.DrawerLayout +import androidx.navigation.Navigation +import androidx.navigation.findNavController +import androidx.navigation.ui.AppBarConfiguration +import androidx.navigation.ui.navigateUp +import androidx.navigation.ui.setupActionBarWithNavController +import androidx.navigation.ui.setupWithNavController +import com.google.android.material.navigation.NavigationView +import sh.van.nextdnsconsole.databinding.ActivityMainBinding +import timber.log.Timber + +class MainActivity : AppCompatActivity() { + + private lateinit var appBarConfiguration: AppBarConfiguration + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + val binding = ActivityMainBinding.inflate(layoutInflater) + setContentView(binding.root) + setSupportActionBar(binding.appBar.toolbar) + appBarConfiguration = AppBarConfiguration(binding.navView.menu, binding.drawerLayout) + val navController = findNavController(R.id.nav_host_fragment) + setupActionBarWithNavController(navController, appBarConfiguration) + binding.navView.setupWithNavController(navController) + } + + override fun onSupportNavigateUp(): Boolean { + val navController = findNavController(R.id.nav_host_fragment) + return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp() + } +} diff --git a/app/src/main/java/sh/van/nextdnsconsole/ui/analytics/AnalyticsFragment.kt b/app/src/main/java/sh/van/nextdnsconsole/ui/analytics/AnalyticsFragment.kt new file mode 100644 index 0000000..18322c3 --- /dev/null +++ b/app/src/main/java/sh/van/nextdnsconsole/ui/analytics/AnalyticsFragment.kt @@ -0,0 +1,22 @@ +package sh.van.nextdnsconsole.ui.analytics + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import androidx.fragment.app.viewModels +import androidx.lifecycle.Observer +import sh.van.nextdnsconsole.databinding.FragmentAnalyticsBinding + +class AnalyticsFragment : Fragment() { + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + val analyticsViewModel: AnalyticsViewModel by viewModels() + val binding = FragmentAnalyticsBinding.inflate(inflater, container, false) + return binding.root + } +} diff --git a/app/src/main/java/sh/van/nextdnsconsole/ui/analytics/AnalyticsViewModel.kt b/app/src/main/java/sh/van/nextdnsconsole/ui/analytics/AnalyticsViewModel.kt new file mode 100644 index 0000000..867e523 --- /dev/null +++ b/app/src/main/java/sh/van/nextdnsconsole/ui/analytics/AnalyticsViewModel.kt @@ -0,0 +1,13 @@ +package sh.van.nextdnsconsole.ui.analytics + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel + +class AnalyticsViewModel : ViewModel() { + + private val _text = MutableLiveData().apply { + value = "This is Analytics Fragment" + } + val text: LiveData = _text +} diff --git a/app/src/main/java/sh/van/nextdnsconsole/ui/blacklist/BlacklistFragment.kt b/app/src/main/java/sh/van/nextdnsconsole/ui/blacklist/BlacklistFragment.kt new file mode 100644 index 0000000..a8bfc1d --- /dev/null +++ b/app/src/main/java/sh/van/nextdnsconsole/ui/blacklist/BlacklistFragment.kt @@ -0,0 +1,22 @@ +package sh.van.nextdnsconsole.ui.blacklist + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import androidx.fragment.app.viewModels +import androidx.lifecycle.Observer +import sh.van.nextdnsconsole.databinding.FragmentBlacklistBinding + +class BlacklistFragment : Fragment() { + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + val blacklistViewModel: BlacklistViewModel by viewModels() + val binding = FragmentBlacklistBinding.inflate(inflater, container, false) + return binding.root + } +} diff --git a/app/src/main/java/sh/van/nextdnsconsole/ui/blacklist/BlacklistViewModel.kt b/app/src/main/java/sh/van/nextdnsconsole/ui/blacklist/BlacklistViewModel.kt new file mode 100644 index 0000000..22650b6 --- /dev/null +++ b/app/src/main/java/sh/van/nextdnsconsole/ui/blacklist/BlacklistViewModel.kt @@ -0,0 +1,13 @@ +package sh.van.nextdnsconsole.ui.blacklist + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel + +class BlacklistViewModel : ViewModel() { + + private val _text = MutableLiveData().apply { + value = "This is Blacklist Fragment" + } + val text: LiveData = _text +} diff --git a/app/src/main/java/sh/van/nextdnsconsole/ui/logs/LogsFragment.kt b/app/src/main/java/sh/van/nextdnsconsole/ui/logs/LogsFragment.kt new file mode 100644 index 0000000..4d73a37 --- /dev/null +++ b/app/src/main/java/sh/van/nextdnsconsole/ui/logs/LogsFragment.kt @@ -0,0 +1,22 @@ +package sh.van.nextdnsconsole.ui.logs + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import androidx.fragment.app.viewModels +import androidx.lifecycle.Observer +import sh.van.nextdnsconsole.databinding.FragmentLogsBinding + +class LogsFragment : Fragment() { + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + val logsViewModel: LogsViewModel by viewModels() + val binding = FragmentLogsBinding.inflate(inflater, container, false) + return binding.root + } +} diff --git a/app/src/main/java/sh/van/nextdnsconsole/ui/logs/LogsViewModel.kt b/app/src/main/java/sh/van/nextdnsconsole/ui/logs/LogsViewModel.kt new file mode 100644 index 0000000..49952d1 --- /dev/null +++ b/app/src/main/java/sh/van/nextdnsconsole/ui/logs/LogsViewModel.kt @@ -0,0 +1,13 @@ +package sh.van.nextdnsconsole.ui.logs + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel + +class LogsViewModel : ViewModel() { + + private val _text = MutableLiveData().apply { + value = "This is Logs Fragment" + } + val text: LiveData = _text +} diff --git a/app/src/main/java/sh/van/nextdnsconsole/ui/parentalcontrol/ParentalControlFragment.kt b/app/src/main/java/sh/van/nextdnsconsole/ui/parentalcontrol/ParentalControlFragment.kt new file mode 100644 index 0000000..86d9339 --- /dev/null +++ b/app/src/main/java/sh/van/nextdnsconsole/ui/parentalcontrol/ParentalControlFragment.kt @@ -0,0 +1,22 @@ +package sh.van.nextdnsconsole.ui.parentalcontrol + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import androidx.fragment.app.viewModels +import androidx.lifecycle.Observer +import sh.van.nextdnsconsole.databinding.FragmentParentalControlBinding + +class ParentalControlFragment : Fragment() { + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + val parentalControlViewModel: ParentalControlViewModel by viewModels() + val binding = FragmentParentalControlBinding.inflate(inflater, container, false) + return binding.root + } +} diff --git a/app/src/main/java/sh/van/nextdnsconsole/ui/parentalcontrol/ParentalControlViewModel.kt b/app/src/main/java/sh/van/nextdnsconsole/ui/parentalcontrol/ParentalControlViewModel.kt new file mode 100644 index 0000000..b8df090 --- /dev/null +++ b/app/src/main/java/sh/van/nextdnsconsole/ui/parentalcontrol/ParentalControlViewModel.kt @@ -0,0 +1,13 @@ +package sh.van.nextdnsconsole.ui.parentalcontrol + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel + +class ParentalControlViewModel : ViewModel() { + + private val _text = MutableLiveData().apply { + value = "This is Parental Control Fragment" + } + val text: LiveData = _text +} diff --git a/app/src/main/java/sh/van/nextdnsconsole/ui/privacy/PrivacyFragment.kt b/app/src/main/java/sh/van/nextdnsconsole/ui/privacy/PrivacyFragment.kt new file mode 100644 index 0000000..9feab47 --- /dev/null +++ b/app/src/main/java/sh/van/nextdnsconsole/ui/privacy/PrivacyFragment.kt @@ -0,0 +1,22 @@ +package sh.van.nextdnsconsole.ui.privacy + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import androidx.fragment.app.viewModels +import androidx.lifecycle.Observer +import sh.van.nextdnsconsole.databinding.FragmentPrivacyBinding + +class PrivacyFragment : Fragment() { + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + val privacyViewModel: PrivacyViewModel by viewModels() + val binding = FragmentPrivacyBinding.inflate(inflater, container, false) + return binding.root + } +} diff --git a/app/src/main/java/sh/van/nextdnsconsole/ui/privacy/PrivacyViewModel.kt b/app/src/main/java/sh/van/nextdnsconsole/ui/privacy/PrivacyViewModel.kt new file mode 100644 index 0000000..f194d2b --- /dev/null +++ b/app/src/main/java/sh/van/nextdnsconsole/ui/privacy/PrivacyViewModel.kt @@ -0,0 +1,13 @@ +package sh.van.nextdnsconsole.ui.privacy + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel + +class PrivacyViewModel : ViewModel() { + + private val _text = MutableLiveData().apply { + value = "This is Privacy Fragment" + } + val text: LiveData = _text +} diff --git a/app/src/main/java/sh/van/nextdnsconsole/ui/security/SecurityFragment.kt b/app/src/main/java/sh/van/nextdnsconsole/ui/security/SecurityFragment.kt new file mode 100644 index 0000000..cb397e2 --- /dev/null +++ b/app/src/main/java/sh/van/nextdnsconsole/ui/security/SecurityFragment.kt @@ -0,0 +1,22 @@ +package sh.van.nextdnsconsole.ui.security + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import androidx.fragment.app.viewModels +import androidx.lifecycle.Observer +import sh.van.nextdnsconsole.databinding.FragmentSecurityBinding + +class SecurityFragment : Fragment() { + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + val securityViewModel: SecurityViewModel by viewModels() + val binding = FragmentSecurityBinding.inflate(inflater, container, false) + return binding.root + } +} diff --git a/app/src/main/java/sh/van/nextdnsconsole/ui/security/SecurityViewModel.kt b/app/src/main/java/sh/van/nextdnsconsole/ui/security/SecurityViewModel.kt new file mode 100644 index 0000000..4eab6dc --- /dev/null +++ b/app/src/main/java/sh/van/nextdnsconsole/ui/security/SecurityViewModel.kt @@ -0,0 +1,13 @@ +package sh.van.nextdnsconsole.ui.security + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel + +class SecurityViewModel : ViewModel() { + + private val _text = MutableLiveData().apply { + value = "This is Security Fragment" + } + val text: LiveData = _text +} diff --git a/app/src/main/java/sh/van/nextdnsconsole/ui/settings/SettingsFragment.kt b/app/src/main/java/sh/van/nextdnsconsole/ui/settings/SettingsFragment.kt new file mode 100644 index 0000000..0c7c6f9 --- /dev/null +++ b/app/src/main/java/sh/van/nextdnsconsole/ui/settings/SettingsFragment.kt @@ -0,0 +1,22 @@ +package sh.van.nextdnsconsole.ui.settings + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import androidx.fragment.app.viewModels +import androidx.lifecycle.Observer +import sh.van.nextdnsconsole.databinding.FragmentSettingsBinding + +class SettingsFragment : Fragment() { + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + val settingsViewModel: SettingsViewModel by viewModels() + val binding = FragmentSettingsBinding.inflate(inflater, container, false) + return binding.root + } +} diff --git a/app/src/main/java/sh/van/nextdnsconsole/ui/settings/SettingsViewModel.kt b/app/src/main/java/sh/van/nextdnsconsole/ui/settings/SettingsViewModel.kt new file mode 100644 index 0000000..30ce5bc --- /dev/null +++ b/app/src/main/java/sh/van/nextdnsconsole/ui/settings/SettingsViewModel.kt @@ -0,0 +1,13 @@ +package sh.van.nextdnsconsole.ui.settings + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel + +class SettingsViewModel : ViewModel() { + + private val _text = MutableLiveData().apply { + value = "This is Settings Fragment" + } + val text: LiveData = _text +} diff --git a/app/src/main/java/sh/van/nextdnsconsole/ui/setup/SetupFragment.kt b/app/src/main/java/sh/van/nextdnsconsole/ui/setup/SetupFragment.kt new file mode 100644 index 0000000..b0b6b72 --- /dev/null +++ b/app/src/main/java/sh/van/nextdnsconsole/ui/setup/SetupFragment.kt @@ -0,0 +1,48 @@ +package sh.van.nextdnsconsole.ui.setup + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import androidx.fragment.app.viewModels +import androidx.lifecycle.Observer +import androidx.security.crypto.EncryptedSharedPreferences +import androidx.security.crypto.MasterKeys +import com.franmontiel.persistentcookiejar.PersistentCookieJar +import com.franmontiel.persistentcookiejar.cache.SetCookieCache +import com.franmontiel.persistentcookiejar.persistence.SharedPrefsCookiePersistor +import sh.van.nextdns.api.NextDNSService +import sh.van.nextdnsconsole.databinding.FragmentSetupBinding +import timber.log.Timber + + +class SetupFragment : Fragment() { + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + val setupViewModel: SetupViewModel by viewModels() + val binding = FragmentSetupBinding.inflate(inflater, container, false) + val masterKeyAlias: String = MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC) + + val sharedPreferences = EncryptedSharedPreferences.create( + "secret_shared_prefs", + masterKeyAlias, + requireContext(), + EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV, + EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM + ) + + setupViewModel.setup.observe(viewLifecycleOwner, Observer { setup -> + binding.id.text = setup.id + Timber.d("Got %s", setup) + }) + + val cookieJar = PersistentCookieJar(SetCookieCache(), SharedPrefsCookiePersistor(sharedPreferences)) + val service = NextDNSService.get(cookieJar) + setupViewModel.getSetup(service) + return binding.root + } +} diff --git a/app/src/main/java/sh/van/nextdnsconsole/ui/setup/SetupViewModel.kt b/app/src/main/java/sh/van/nextdnsconsole/ui/setup/SetupViewModel.kt new file mode 100644 index 0000000..0bbdb29 --- /dev/null +++ b/app/src/main/java/sh/van/nextdnsconsole/ui/setup/SetupViewModel.kt @@ -0,0 +1,30 @@ +package sh.van.nextdnsconsole.ui.setup + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import kotlinx.coroutines.launch +import sh.van.nextdns.api.NextDNSService +import sh.van.nextdns.model.Setup +import timber.log.Timber + +class SetupViewModel : ViewModel() { + + private val _setup = MutableLiveData() + val setup: LiveData = _setup + + fun getSetup(service: NextDNSService) { + viewModelScope.launch { + val configId = "13d18c" + try { + _setup.value = service.getSetup(configId) + Timber.d("Got: %s", service.getAccount()) + Timber.d("Got: %s", service.getLogs(configId)) + Timber.d("Got: %s", service.getCounters(configId)) + } catch (e: Exception) { + Timber.e(e) + } + } + } +} diff --git a/app/src/main/java/sh/van/nextdnsconsole/ui/whitelist/WhitelistFragment.kt b/app/src/main/java/sh/van/nextdnsconsole/ui/whitelist/WhitelistFragment.kt new file mode 100644 index 0000000..0fe4753 --- /dev/null +++ b/app/src/main/java/sh/van/nextdnsconsole/ui/whitelist/WhitelistFragment.kt @@ -0,0 +1,22 @@ +package sh.van.nextdnsconsole.ui.whitelist + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import androidx.fragment.app.viewModels +import androidx.lifecycle.Observer +import sh.van.nextdnsconsole.databinding.FragmentWhitelistBinding + +class WhitelistFragment : Fragment() { + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + val whitelistViewModel: WhitelistViewModel by viewModels() + val binding = FragmentWhitelistBinding.inflate(inflater, container, false) + return binding.root + } +} diff --git a/app/src/main/java/sh/van/nextdnsconsole/ui/whitelist/WhitelistViewModel.kt b/app/src/main/java/sh/van/nextdnsconsole/ui/whitelist/WhitelistViewModel.kt new file mode 100644 index 0000000..dc9a777 --- /dev/null +++ b/app/src/main/java/sh/van/nextdnsconsole/ui/whitelist/WhitelistViewModel.kt @@ -0,0 +1,13 @@ +package sh.van.nextdnsconsole.ui.whitelist + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel + +class WhitelistViewModel : ViewModel() { + + private val _text = MutableLiveData().apply { + value = "This is Whitelist Fragment" + } + val text: LiveData = _text +} diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 0000000..7706ab9 --- /dev/null +++ b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..07d5da9 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_menu_analytics.xml b/app/src/main/res/drawable/ic_menu_analytics.xml new file mode 100644 index 0000000..75d0dde --- /dev/null +++ b/app/src/main/res/drawable/ic_menu_analytics.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_menu_blacklist.xml b/app/src/main/res/drawable/ic_menu_blacklist.xml new file mode 100644 index 0000000..d511379 --- /dev/null +++ b/app/src/main/res/drawable/ic_menu_blacklist.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_menu_logs.xml b/app/src/main/res/drawable/ic_menu_logs.xml new file mode 100644 index 0000000..4714dde --- /dev/null +++ b/app/src/main/res/drawable/ic_menu_logs.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_menu_parental_control.xml b/app/src/main/res/drawable/ic_menu_parental_control.xml new file mode 100644 index 0000000..8aa9c18 --- /dev/null +++ b/app/src/main/res/drawable/ic_menu_parental_control.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_menu_privacy.xml b/app/src/main/res/drawable/ic_menu_privacy.xml new file mode 100644 index 0000000..e02f1d1 --- /dev/null +++ b/app/src/main/res/drawable/ic_menu_privacy.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_menu_security.xml b/app/src/main/res/drawable/ic_menu_security.xml new file mode 100644 index 0000000..9186423 --- /dev/null +++ b/app/src/main/res/drawable/ic_menu_security.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_menu_settings.xml b/app/src/main/res/drawable/ic_menu_settings.xml new file mode 100644 index 0000000..24a5623 --- /dev/null +++ b/app/src/main/res/drawable/ic_menu_settings.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_menu_setup.xml b/app/src/main/res/drawable/ic_menu_setup.xml new file mode 100644 index 0000000..1a8528c --- /dev/null +++ b/app/src/main/res/drawable/ic_menu_setup.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_menu_whitelist.xml b/app/src/main/res/drawable/ic_menu_whitelist.xml new file mode 100644 index 0000000..43d5552 --- /dev/null +++ b/app/src/main/res/drawable/ic_menu_whitelist.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/side_nav_bar.xml b/app/src/main/res/drawable/side_nav_bar.xml new file mode 100644 index 0000000..6d81870 --- /dev/null +++ b/app/src/main/res/drawable/side_nav_bar.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..21acd7b --- /dev/null +++ b/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,26 @@ + + + + + + + + diff --git a/app/src/main/res/layout/app_bar_main.xml b/app/src/main/res/layout/app_bar_main.xml new file mode 100644 index 0000000..35c7d4f --- /dev/null +++ b/app/src/main/res/layout/app_bar_main.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + diff --git a/app/src/main/res/layout/content_main.xml b/app/src/main/res/layout/content_main.xml new file mode 100644 index 0000000..fa1e09b --- /dev/null +++ b/app/src/main/res/layout/content_main.xml @@ -0,0 +1,20 @@ + + + + + diff --git a/app/src/main/res/layout/fragment_analytics.xml b/app/src/main/res/layout/fragment_analytics.xml new file mode 100644 index 0000000..6d471b1 --- /dev/null +++ b/app/src/main/res/layout/fragment_analytics.xml @@ -0,0 +1,22 @@ + + + + + diff --git a/app/src/main/res/layout/fragment_blacklist.xml b/app/src/main/res/layout/fragment_blacklist.xml new file mode 100644 index 0000000..302ad84 --- /dev/null +++ b/app/src/main/res/layout/fragment_blacklist.xml @@ -0,0 +1,22 @@ + + + + + diff --git a/app/src/main/res/layout/fragment_logs.xml b/app/src/main/res/layout/fragment_logs.xml new file mode 100644 index 0000000..f5e3a54 --- /dev/null +++ b/app/src/main/res/layout/fragment_logs.xml @@ -0,0 +1,22 @@ + + + + + diff --git a/app/src/main/res/layout/fragment_parental_control.xml b/app/src/main/res/layout/fragment_parental_control.xml new file mode 100644 index 0000000..734f28b --- /dev/null +++ b/app/src/main/res/layout/fragment_parental_control.xml @@ -0,0 +1,22 @@ + + + + + diff --git a/app/src/main/res/layout/fragment_privacy.xml b/app/src/main/res/layout/fragment_privacy.xml new file mode 100644 index 0000000..af3de89 --- /dev/null +++ b/app/src/main/res/layout/fragment_privacy.xml @@ -0,0 +1,22 @@ + + + + + diff --git a/app/src/main/res/layout/fragment_security.xml b/app/src/main/res/layout/fragment_security.xml new file mode 100644 index 0000000..798890d --- /dev/null +++ b/app/src/main/res/layout/fragment_security.xml @@ -0,0 +1,22 @@ + + + + + diff --git a/app/src/main/res/layout/fragment_settings.xml b/app/src/main/res/layout/fragment_settings.xml new file mode 100644 index 0000000..042710d --- /dev/null +++ b/app/src/main/res/layout/fragment_settings.xml @@ -0,0 +1,22 @@ + + + + + diff --git a/app/src/main/res/layout/fragment_setup.xml b/app/src/main/res/layout/fragment_setup.xml new file mode 100644 index 0000000..5069388 --- /dev/null +++ b/app/src/main/res/layout/fragment_setup.xml @@ -0,0 +1,62 @@ + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/fragment_whitelist.xml b/app/src/main/res/layout/fragment_whitelist.xml new file mode 100644 index 0000000..6ce238f --- /dev/null +++ b/app/src/main/res/layout/fragment_whitelist.xml @@ -0,0 +1,22 @@ + + + + + diff --git a/app/src/main/res/layout/nav_header_main.xml b/app/src/main/res/layout/nav_header_main.xml new file mode 100644 index 0000000..4c3439a --- /dev/null +++ b/app/src/main/res/layout/nav_header_main.xml @@ -0,0 +1,36 @@ + + + + + + + + + + diff --git a/app/src/main/res/menu/activity_main_drawer.xml b/app/src/main/res/menu/activity_main_drawer.xml new file mode 100644 index 0000000..2576097 --- /dev/null +++ b/app/src/main/res/menu/activity_main_drawer.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000..6b78462 --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 0000000..6b78462 --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000..a571e60 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 0000000..61da551 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000..c41dd28 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png new file mode 100644 index 0000000..db5080a Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000..6dba46d Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 0000000..da31a87 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000..15ac681 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 0000000..b216f2d Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000..f25a419 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 0000000..e96783c Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/navigation/mobile_navigation.xml b/app/src/main/res/navigation/mobile_navigation.xml new file mode 100644 index 0000000..e51c151 --- /dev/null +++ b/app/src/main/res/navigation/mobile_navigation.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + diff --git a/app/src/main/res/values-v21/styles.xml b/app/src/main/res/values-v21/styles.xml new file mode 100644 index 0000000..fd7a058 --- /dev/null +++ b/app/src/main/res/values-v21/styles.xml @@ -0,0 +1,8 @@ + + + + diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml new file mode 100644 index 0000000..ebc665f --- /dev/null +++ b/app/src/main/res/values/colors.xml @@ -0,0 +1,6 @@ + + + #0A61FF + #003CFF + #1758F2 + diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml new file mode 100644 index 0000000..a5be179 --- /dev/null +++ b/app/src/main/res/values/dimens.xml @@ -0,0 +1,8 @@ + + + 16dp + 16dp + 8dp + 176dp + 16dp + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..71f33b7 --- /dev/null +++ b/app/src/main/res/values/strings.xml @@ -0,0 +1,23 @@ + + NextDNS Console + Open navigation drawer + Close navigation drawer + Android Studio + android.studio@android.com + Navigation header + + Home Second + Setup + Security + Privacy + Parental Control + Blacklist + Whitelist + Analytics + Logs + Settings + ID + DNS-over-TLS + DNS-over-HTTPS + IPv6 + diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml new file mode 100644 index 0000000..1df904a --- /dev/null +++ b/app/src/main/res/values/styles.xml @@ -0,0 +1,17 @@ + + + + + + diff --git a/app/src/main/res/xml/network_security_config.xml b/app/src/main/res/xml/network_security_config.xml new file mode 100644 index 0000000..77032a1 --- /dev/null +++ b/app/src/main/res/xml/network_security_config.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/test/java/sh/van/nextdnsconsole/ExampleUnitTest.kt b/app/src/test/java/sh/van/nextdnsconsole/ExampleUnitTest.kt new file mode 100644 index 0000000..6ab0953 --- /dev/null +++ b/app/src/test/java/sh/van/nextdnsconsole/ExampleUnitTest.kt @@ -0,0 +1,17 @@ +package sh.van.nextdnsconsole + +import org.junit.Test + +import org.junit.Assert.* + +/** + * Example local unit test, which will execute on the development machine (host). + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +class ExampleUnitTest { + @Test + fun addition_isCorrect() { + assertEquals(4, 2 + 2) + } +} diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..8f5fc2f --- /dev/null +++ b/build.gradle @@ -0,0 +1,23 @@ +buildscript { + ext.kotlin_version = "1.3.72" + repositories { + google() + jcenter() + } + dependencies { + classpath "com.android.tools.build:gradle:3.6.3" + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + maven { url "https://jitpack.io" } + } +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..d6e0ae0 --- /dev/null +++ b/gradle.properties @@ -0,0 +1,14 @@ +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx1536m +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true +android.useAndroidX=true +android.enableJetifier=true +kotlin.code.style=official diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..f6b961f Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..cd51ec2 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Sat Apr 18 15:47:11 PDT 2020 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip diff --git a/gradlew b/gradlew new file mode 100755 index 0000000..cccdd3d --- /dev/null +++ b/gradlew @@ -0,0 +1,172 @@ +#!/usr/bin/env sh + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..e95643d --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/model/build.gradle b/model/build.gradle new file mode 100644 index 0000000..057655f --- /dev/null +++ b/model/build.gradle @@ -0,0 +1,12 @@ +apply plugin: 'java-library' +apply plugin: 'kotlin' +apply plugin: 'kotlin-kapt' + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + implementation "com.squareup.moshi:moshi-kotlin:1.9.2" + kapt "com.squareup.moshi:moshi-kotlin-codegen:1.9.2" +} + +sourceCompatibility = "8" +targetCompatibility = "8" diff --git a/model/src/main/java/sh/van/nextdns/model/AddDDNSRequest.kt b/model/src/main/java/sh/van/nextdns/model/AddDDNSRequest.kt new file mode 100644 index 0000000..e09c577 --- /dev/null +++ b/model/src/main/java/sh/van/nextdns/model/AddDDNSRequest.kt @@ -0,0 +1,10 @@ +package sh.van.nextdns.model +import com.squareup.moshi.JsonClass + +import com.squareup.moshi.Json + + +@JsonClass(generateAdapter = true) +data class AddDDNSRequest( + @Json(name = "linkedip_ddns") val linkedipDdns: String +) diff --git a/model/src/main/java/sh/van/nextdns/model/Analytics.kt b/model/src/main/java/sh/van/nextdns/model/Analytics.kt new file mode 100644 index 0000000..3523216 --- /dev/null +++ b/model/src/main/java/sh/van/nextdns/model/Analytics.kt @@ -0,0 +1,75 @@ +package sh.van.nextdns.model +import com.squareup.moshi.JsonClass + +import com.squareup.moshi.Json + + +@JsonClass(generateAdapter = true) +data class Counters( + @Json(name = "blockedQueries") val blockedQueries: Int?, + @Json(name = "queries") val queries: Int? +) + +@JsonClass(generateAdapter = true) +data class DeviceStats( + @Json(name = "id") val id: String?, + @Json(name = "name") val name: String?, + @Json(name = "queries") val queries: Int? +) + +@JsonClass(generateAdapter = true) +data class DomainStats( + @Json(name = "name") val name: String?, + @Json(name = "queries") val queries: Int? +) + +@JsonClass(generateAdapter = true) +data class BlocklistStats( + @Json(name = "name") val name: String?, + @Json(name = "queries") val queries: Int? +) + +@JsonClass(generateAdapter = true) +data class ClientIPStats( + @Json(name = "city") val city: String?, + @Json(name = "country") val country: String?, + @Json(name = "countryCode") val countryCode: String?, + @Json(name = "ip") val ip: String?, + @Json(name = "isCellular") val isCellular: Boolean?, + @Json(name = "isp") val isp: String?, + @Json(name = "queries") val queries: Int? +) + +@JsonClass(generateAdapter = true) +data class SecureDNSStats( + @Json(name = "secure") val secure: Int?, + @Json(name = "total") val total: Int? +) + +@JsonClass(generateAdapter = true) +data class DNSSECStats( + @Json(name = "dnssec") val dnssec: Int?, + @Json(name = "total") val total: Int? +) + +@JsonClass(generateAdapter = true) +data class QueriesChartDataPoint( + @Json(name = "blockedQueries") val blockedQueries: Int?, + @Json(name = "dayOnly") val dayOnly: Boolean?, + @Json(name = "name") val dateInEpochSeconds: Int?, + @Json(name = "queries") val queries: Int? +) + +@JsonClass(generateAdapter = true) +data class CompanyStats( + @Json(name = "company") val company: String?, + @Json(name = "percentage") val percentage: Double?, + @Json(name = "queries") val queries: Int? +) + +@JsonClass(generateAdapter = true) +data class CountryStats( + @Json(name = "queries") val queries: Int?, + @Json(name = "topDomains") val topDomains: List? +) + diff --git a/model/src/main/java/sh/van/nextdns/model/Blacklist.kt b/model/src/main/java/sh/van/nextdns/model/Blacklist.kt new file mode 100644 index 0000000..a4ad8d2 --- /dev/null +++ b/model/src/main/java/sh/van/nextdns/model/Blacklist.kt @@ -0,0 +1,11 @@ +package sh.van.nextdns.model +import com.squareup.moshi.JsonClass + +import com.squareup.moshi.Json + + +@JsonClass(generateAdapter = true) +data class AccessControlListItem( + @Json(name = "active") val active: Boolean?, + @Json(name = "domain") val domain: String? +) diff --git a/model/src/main/java/sh/van/nextdns/model/Error.kt b/model/src/main/java/sh/van/nextdns/model/Error.kt new file mode 100644 index 0000000..fc801fc --- /dev/null +++ b/model/src/main/java/sh/van/nextdns/model/Error.kt @@ -0,0 +1,10 @@ +package sh.van.nextdns.model +import com.squareup.moshi.JsonClass + +import com.squareup.moshi.Json + + +@JsonClass(generateAdapter = true) +data class Error( + @Json(name = "error") val error: String? +) diff --git a/model/src/main/java/sh/van/nextdns/model/LoginRequest.kt b/model/src/main/java/sh/van/nextdns/model/LoginRequest.kt new file mode 100644 index 0000000..1e452ea --- /dev/null +++ b/model/src/main/java/sh/van/nextdns/model/LoginRequest.kt @@ -0,0 +1,9 @@ +package sh.van.nextdns.model + +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = true) +data class LoginRequest( + val email: String, + val password: String +) diff --git a/model/src/main/java/sh/van/nextdns/model/Logs.kt b/model/src/main/java/sh/van/nextdns/model/Logs.kt new file mode 100644 index 0000000..32414a4 --- /dev/null +++ b/model/src/main/java/sh/van/nextdns/model/Logs.kt @@ -0,0 +1,45 @@ +package sh.van.nextdns.model +import com.squareup.moshi.JsonClass + +import com.squareup.moshi.Json + + +@JsonClass(generateAdapter = true) +data class Logs( + @Json(name = "hasMore") val hasMore: Boolean?, + @Json(name = "logs") val logs: List? +) + +@JsonClass(generateAdapter = true) +data class Log( + @Json(name = "clientIp") val clientIp: String?, + @Json(name = "clientName") val clientName: String?, + @Json(name = "deviceId") val deviceId: String?, + @Json(name = "deviceName") val deviceName: String?, + @Json(name = "dnssec") val dnssec: Boolean?, + @Json(name = "isSecureDNS") val isSecureDNS: Boolean?, + @Json(name = "lists") val lists: List?, + @Json(name = "name") val name: String?, + @Json(name = "protocol") val protocol: String?, + @Json(name = "rootDomainStartIndex") val rootDomainStartIndex: Int?, + @Json(name = "status") val status: Int?, + @Json(name = "timestamp") val timestamp: Long?, + @Json(name = "tracker") val tracker: Tracker?, + @Json(name = "type") val type: String? +) + +@JsonClass(generateAdapter = true) +data class Tracker( + @Json(name = "category") val category: String?, + @Json(name = "company") val company: Company?, + @Json(name = "name") val name: String?, + @Json(name = "prevalence") val prevalence: Double?, + @Json(name = "website") val website: String? +) + +@JsonClass(generateAdapter = true) +data class Company( + @Json(name = "description") val description: String?, + @Json(name = "name") val name: String?, + @Json(name = "privacyURL") val privacyURL: String? +) diff --git a/model/src/main/java/sh/van/nextdns/model/ParentalControl.kt b/model/src/main/java/sh/van/nextdns/model/ParentalControl.kt new file mode 100644 index 0000000..c628fda --- /dev/null +++ b/model/src/main/java/sh/van/nextdns/model/ParentalControl.kt @@ -0,0 +1,32 @@ +package sh.van.nextdns.model + +import com.squareup.moshi.JsonClass + +import com.squareup.moshi.Json + + +@JsonClass(generateAdapter = true) +data class ParentalControl( + @Json(name = "block_bypass_methods") val blockBypassMethods: Boolean?, + @Json(name = "categories") val categories: List?, + @Json(name = "enforce_safesearch") val enforceSafesearch: Boolean?, + @Json(name = "services") val services: List?, + @Json(name = "youtube_restricted_mode") val youtubeRestrictedMode: Boolean? +) + +@JsonClass(generateAdapter = true) +data class RestrictableService( + @Json(name = "id") val id: String?, + @Json(name = "name") val name: String?, + @Json(name = "website") val website: String? +) + +enum class ServiceCategory(id: String) { + Porn("porn"), + Gambling("gambling"), + Dating("dating"), + Piracy("piracy"), + SocialNetworks("social-networks"), +} + +data class Active(@Json(name = "active") val active: Boolean?) diff --git a/model/src/main/java/sh/van/nextdns/model/Privacy.kt b/model/src/main/java/sh/van/nextdns/model/Privacy.kt new file mode 100644 index 0000000..2eb9bb6 --- /dev/null +++ b/model/src/main/java/sh/van/nextdns/model/Privacy.kt @@ -0,0 +1,22 @@ +package sh.van.nextdns.model +import com.squareup.moshi.JsonClass + +import com.squareup.moshi.Json + + +@JsonClass(generateAdapter = true) +data class Privacy( + @Json(name = "allow_affiliate_links") val allowAffiliateLinks: Boolean?, + @Json(name = "block_disguised_trackers") val blockDisguisedTrackers: Boolean?, + @Json(name = "blocklists") val blocklists: List? +) + +@JsonClass(generateAdapter = true) +data class Blocklist( + @Json(name = "description") val description: String?, + @Json(name = "entries") val entries: Int?, + @Json(name = "id") val id: String?, + @Json(name = "name") val name: String?, + @Json(name = "updated_time") val updatedTime: Int?, + @Json(name = "website") val website: String? +) diff --git a/model/src/main/java/sh/van/nextdns/model/Profile.kt b/model/src/main/java/sh/van/nextdns/model/Profile.kt new file mode 100644 index 0000000..2e24467 --- /dev/null +++ b/model/src/main/java/sh/van/nextdns/model/Profile.kt @@ -0,0 +1,56 @@ +package sh.van.nextdns.model + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + + +data class Profile( + @Json(name = "configurations") val configurations: List?, + @Json(name = "email") val email: String? +) + +data class Configuration( + @Json(name = "id") val id: String?, + @Json(name = "name") val name: String? +) + +@JsonClass(generateAdapter = true) +data class Account( + @Json(name = "business") val business: Business?, + @Json(name = "email") val email: String?, + @Json(name = "invoices") val invoices: List?, + @Json(name = "prices") val prices: Prices?, + @Json(name = "subscription") val subscription: String?, + @Json(name = "subscriptionBeta") val subscriptionBeta: Boolean? +) + +@JsonClass(generateAdapter = true) +data class Business( + @Json(name = "address") val address: String?, + @Json(name = "name") val name: String?, + @Json(name = "vatNumber") val vatNumber: String? +) + +@JsonClass(generateAdapter = true) +data class Prices( + @Json(name = "currency") val currency: String?, + @Json(name = "plans") val plans: Plans? +) + +@JsonClass(generateAdapter = true) +data class Plans( + @Json(name = "business") val business: BusinessX?, + @Json(name = "pro") val pro: Pro? +) + +@JsonClass(generateAdapter = true) +data class BusinessX( + @Json(name = "month") val month: Double?, + @Json(name = "year") val year: Int? +) + +@JsonClass(generateAdapter = true) +data class Pro( + @Json(name = "month") val month: Double?, + @Json(name = "year") val year: Double? +) diff --git a/model/src/main/java/sh/van/nextdns/model/Security.kt b/model/src/main/java/sh/van/nextdns/model/Security.kt new file mode 100644 index 0000000..f85691a --- /dev/null +++ b/model/src/main/java/sh/van/nextdns/model/Security.kt @@ -0,0 +1,33 @@ +package sh.van.nextdns.model +import com.squareup.moshi.JsonClass + +import com.squareup.moshi.Json + + +@JsonClass(generateAdapter = true) +data class Security( + @Json(name = "block_csam") val blockCsam: Boolean?, + @Json(name = "block_nrd") val blockNrd: Boolean?, + @Json(name = "block_parked_domains") val blockParkedDomains: Boolean?, + @Json(name = "blocked_tlds") val blockedTlds: List?, + @Json(name = "cryptojacking_protection") val cryptojackingProtection: Boolean?, + @Json(name = "dga_protection") val dgaProtection: Boolean?, + @Json(name = "dns_rebinding_protection") val dnsRebindingProtection: Boolean?, + @Json(name = "google_safe_browsing") val googleSafeBrowsing: Boolean?, + @Json(name = "idn_homograph_attacks_protection") val idnHomographAttacksProtection: Boolean?, + @Json(name = "ti_feeds") val tiFeeds: Boolean?, + @Json(name = "typosquatting_protection") val typosquattingProtection: Boolean? +) + +@JsonClass(generateAdapter = true) +data class BlockableTLDs( + @Json(name = "all") val all: List?, + @Json(name = "commonlyBlocked") val commonlyBlocked: List? +) + +@JsonClass(generateAdapter = true) +data class TLD( + @Json(name = "description") val description: String?, + @Json(name = "tld") val tld: String?, + @Json(name = "unicode") val unicode: String? +) diff --git a/model/src/main/java/sh/van/nextdns/model/Settings.kt b/model/src/main/java/sh/van/nextdns/model/Settings.kt new file mode 100644 index 0000000..c36b463 --- /dev/null +++ b/model/src/main/java/sh/van/nextdns/model/Settings.kt @@ -0,0 +1,30 @@ +package sh.van.nextdns.model +import com.squareup.moshi.JsonClass + +import com.squareup.moshi.Json + + +@JsonClass(generateAdapter = true) +data class Settings( + @Json(name = "block_page") val blockPage: Boolean?, + @Json(name = "edns_client_subnet") val ednsClientSubnet: Boolean?, + @Json(name = "handshake") val handshake: Boolean?, + @Json(name = "logging") val logging: Boolean?, + @Json(name = "logging_disable_client") val loggingDisableClient: Boolean?, + @Json(name = "logging_disable_query") val loggingDisableQuery: Boolean?, + @Json(name = "logging_location") val loggingLocation: String?, + @Json(name = "logging_retention") val loggingRetention: Long?, + @Json(name = "name") val name: String?, + @Json(name = "rewrites") val rewrites: List? +) + +@JsonClass(generateAdapter = true) +data class Rewrite( + @Json(name = "answer") val answer: String?, + @Json(name = "id") val id: Int?, + @Json(name = "name") val name: String? +) + +enum class LoggingLocation(id: String?) { + EU("eu"), US(null), Switzerland("ch") +} diff --git a/model/src/main/java/sh/van/nextdns/model/Setup.kt b/model/src/main/java/sh/van/nextdns/model/Setup.kt new file mode 100644 index 0000000..7884b25 --- /dev/null +++ b/model/src/main/java/sh/van/nextdns/model/Setup.kt @@ -0,0 +1,18 @@ +package sh.van.nextdns.model + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = true) +data class Setup( + @Json(name = "apiKey") val apiKey: String?, + @Json(name = "ddnsHostname") val ddnsHostname: String?, + @Json(name = "dnsStamp") val dnsStamp: String?, + @Json(name = "fingerprint") val fingerprint: String?, + @Json(name = "id") val id: String?, + @Json(name = "ipv4") val ipv4: List?, + @Json(name = "ipv6") val ipv6: List?, + @Json(name = "ipv6Expanded") val ipv6Expanded: List?, + @Json(name = "linkedIp") val linkedIp: String?, + @Json(name = "linkedIpDNSServers") val linkedIpDNSServers: List? +) diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..75a4eaa --- /dev/null +++ b/settings.gradle @@ -0,0 +1,4 @@ +rootProject.name='NextDNS Console' +include ':app' +include ':api' +include ':model'