diff --git a/app/build.gradle b/app/build.gradle index bc874ec57..7f9fd7ed3 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -200,8 +200,15 @@ dependencies { implementation "androidx.core:core-splashscreen:1.0.0-beta02" implementation project(':geeksville-androidlib') + + // App intro + implementation 'com.github.AppIntro:AppIntro:6.2.0' } kapt { correctErrorTypes true } + +repositories { + maven { url "https://jitpack.io" } +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 29866cd65..ec7b96c60 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,196 +1,186 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/com/geeksville/mesh/AppIntroduction.kt b/app/src/main/java/com/geeksville/mesh/AppIntroduction.kt new file mode 100644 index 000000000..134de78b7 --- /dev/null +++ b/app/src/main/java/com/geeksville/mesh/AppIntroduction.kt @@ -0,0 +1,68 @@ +package com.geeksville.mesh + +import android.content.Context +import android.content.Intent +import android.content.SharedPreferences +import android.os.Bundle +import androidx.fragment.app.Fragment +import com.github.appintro.AppIntro +import com.github.appintro.AppIntroFragment + +class AppIntroduction : AppIntro() { + + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + // Make sure you don't call setContentView! + + // Call addSlide passing your Fragments. + // You can use AppIntroFragment to use a pre-built fragment + addSlide( + AppIntroFragment.createInstance( + title = resources.getString(R.string.intro_welcome_title), + description = resources.getString(R.string.intro_meshtastic_desc), + imageDrawable = R.mipmap.ic_launcher2_round, + backgroundColorRes = R.color.colourGrey, + descriptionColorRes = R.color.colorOnPrimary + )) + addSlide(AppIntroFragment.createInstance( + title = resources.getString(R.string.intro_get_started), + description = resources.getString(R.string.intro_started_text), + imageDrawable = R.drawable.icon_meanings, + backgroundColorRes = R.color.colourGrey, + descriptionColorRes = R.color.colorOnPrimary + )) + addSlide(AppIntroFragment.createInstance( + title = resources.getString(R.string.intro_ecryption_title), + description = resources.getString(R.string.intro_encryption_text), + imageDrawable = R.drawable.channel_name_image, + backgroundColorRes = R.color.colourGrey, + descriptionColorRes = R.color.colorOnPrimary + )) + //addSlide(SlideTwoFragment()) + } + + override fun onSkipPressed(currentFragment: Fragment?) { + super.onSkipPressed(currentFragment) + // Decide what to do when the user clicks on "Skip" + finish() + val preferences = getSharedPreferences("PREFERENCES", Context.MODE_PRIVATE) + var editor = preferences.edit() + editor.putBoolean("app_intro_completed", true) + editor.apply() + + startActivity(Intent(this, MainActivity::class.java)) + } + + override fun onDonePressed(currentFragment: Fragment?) { + super.onDonePressed(currentFragment) + // Decide what to do when the user clicks on "Done" + finish() + val preferences = getSharedPreferences("PREFERENCES", Context.MODE_PRIVATE) + var editor = preferences.edit() + editor.putBoolean("app_intro_completed", true) + editor.apply() + + startActivity(Intent(this, MainActivity::class.java)) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/geeksville/mesh/MainActivity.kt b/app/src/main/java/com/geeksville/mesh/MainActivity.kt index 14420a6bb..f0a899a7b 100644 --- a/app/src/main/java/com/geeksville/mesh/MainActivity.kt +++ b/app/src/main/java/com/geeksville/mesh/MainActivity.kt @@ -404,9 +404,16 @@ class MainActivity : BaseActivity(), Logging, } override fun onCreate(savedInstanceState: Bundle?) { + val preferences = getSharedPreferences("PREFERENCES", Context.MODE_PRIVATE) + installSplashScreen() super.onCreate(savedInstanceState) + if (preferences.getBoolean("app_intro_completed", false) == false) { + startActivity(Intent(this, AppIntroduction::class.java)) + } + + binding = ActivityMainBinding.inflate(layoutInflater) val prefs = UIViewModel.getPreferences(this) @@ -1070,6 +1077,10 @@ class MainActivity : BaseActivity(), Logging, chooseMapStyle() return true } + R.id.show_intro -> { + startActivity(Intent(this, AppIntroduction::class.java)) + return true + } else -> super.onOptionsItemSelected(item) } } diff --git a/app/src/main/java/com/geeksville/mesh/android/ContextServices.kt b/app/src/main/java/com/geeksville/mesh/android/ContextServices.kt index 8a9edf947..d9b9caa0a 100644 --- a/app/src/main/java/com/geeksville/mesh/android/ContextServices.kt +++ b/app/src/main/java/com/geeksville/mesh/android/ContextServices.kt @@ -21,9 +21,11 @@ val Context.bluetoothManager: BluetoothManager? get() = getSystemService(Context val Context.deviceManager: CompanionDeviceManager? @SuppressLint("InlinedApi") get() { - val activity: MainActivity? = GeeksvilleApplication.currentActivity as MainActivity? - return if (hasCompanionDeviceApi()) activity?.getSystemService(Context.COMPANION_DEVICE_SERVICE) as? CompanionDeviceManager? - else null + if (GeeksvilleApplication.currentActivity is MainActivity) { + val activity = GeeksvilleApplication.currentActivity + if (hasCompanionDeviceApi()) return activity?.getSystemService(Context.COMPANION_DEVICE_SERVICE) as? CompanionDeviceManager? + } + return null } val Context.usbManager: UsbManager get() = requireNotNull(getSystemService(Context.USB_SERVICE) as? UsbManager?) { "USB_SERVICE is not available"} diff --git a/app/src/main/res/drawable-nodpi/channel_name_image.jpg b/app/src/main/res/drawable-nodpi/channel_name_image.jpg new file mode 100644 index 000000000..271bc5241 Binary files /dev/null and b/app/src/main/res/drawable-nodpi/channel_name_image.jpg differ diff --git a/app/src/main/res/drawable-nodpi/icon_meanings.png b/app/src/main/res/drawable-nodpi/icon_meanings.png new file mode 100644 index 000000000..3635df2e8 Binary files /dev/null and b/app/src/main/res/drawable-nodpi/icon_meanings.png differ diff --git a/app/src/main/res/layout/activity_app_introduction.xml b/app/src/main/res/layout/activity_app_introduction.xml new file mode 100644 index 000000000..b25cb7758 --- /dev/null +++ b/app/src/main/res/layout/activity_app_introduction.xml @@ -0,0 +1,8 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/menu/menu_main.xml b/app/src/main/res/menu/menu_main.xml index 748e1b9bf..10879e10e 100644 --- a/app/src/main/res/menu/menu_main.xml +++ b/app/src/main/res/menu/menu_main.xml @@ -36,6 +36,10 @@ android:id="@+id/preferences_map_style" android:title="@string/preferences_map_style" app:showAsAction="withText" /> + #67EA94 #212121 #67EA94 + #535353 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 5788505eb..14253fccd 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -144,4 +144,13 @@ Resend Shutdown Reboot + + Hello blank fragment + Show Introduction + Welcome to Meshtastic + Meshtastic is an open-source, off-grid, encrypted communication platform. The meshtastic radios form a mesh network and communicate using the LoRa protocol to send text messages + ...Let\'s get started! + Connect your meshtastic device by using either bluetooth or serial. \n\nYou may need to wake your node if they are battery powered. \n\nYou can see which devices are compatible at www.meshtastic.org/docs/hardware + "Setting up encryption" + To enable encryption, go to the channel tab and change the channel name. This will set a random key and enable AES256 encryption. \n\nTo communicate with other devices they will need to scan your QR code or follow the shared link to configure the channel settings.