Implement introduction screen.

Fixes #1316.
This commit is contained in:
Dennis Guse
2022-07-10 21:44:16 +02:00
parent 8389f9150a
commit 85a73c3c85
13 changed files with 303 additions and 9 deletions
+13 -7
View File
@@ -87,6 +87,17 @@ limitations under the License.
</intent-filter>
</activity>
<activity
android:name=".introduction.IntroductionActivity"
android:exported="true"
android:launchMode="singleTop"
android:theme="@style/SplashTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".AboutActivity" />
<activity
@@ -310,13 +321,8 @@ limitations under the License.
<activity
android:name=".TrackListActivity"
android:exported="true"
android:launchMode="singleTop"
android:theme="@style/SplashTheme">
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<action android:name="android.intent.action.SEARCH" />
</intent-filter>
<meta-data
@@ -354,7 +360,7 @@ limitations under the License.
android:exported="false"
android:finishOnTaskLaunch="true"
android:launchMode="singleInstance"
android:process=":crash"/>
android:process=":crash" />
<provider
android:name=".data.ShareContentProvider"
@@ -33,4 +33,10 @@ public class AboutActivity extends AbstractActivity {
viewBinding = AboutBinding.inflate(getLayoutInflater());
return viewBinding.getRoot();
}
@Override
protected void onDestroy() {
super.onDestroy();
viewBinding = null;
}
}
@@ -159,8 +159,6 @@ public class TrackListActivity extends AbstractTrackDeleteActivity implements Co
@Override
protected void onCreate(Bundle savedInstanceState) {
SplashScreen.installSplashScreen(this);
super.onCreate(savedInstanceState);
setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL);
@@ -0,0 +1,93 @@
package de.dennisguse.opentracks.introduction;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.core.splashscreen.SplashScreen;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.viewpager2.adapter.FragmentStateAdapter;
import java.util.List;
import de.dennisguse.opentracks.AbstractActivity;
import de.dennisguse.opentracks.TrackListActivity;
import de.dennisguse.opentracks.databinding.IntroductionBinding;
import de.dennisguse.opentracks.settings.PreferencesUtils;
import de.dennisguse.opentracks.util.IntentUtils;
public class IntroductionActivity extends AbstractActivity {
private IntroductionBinding viewBinding;
@Override
protected void onCreate(Bundle savedInstanceState) {
SplashScreen.installSplashScreen(this);
super.onCreate(savedInstanceState);
if (!PreferencesUtils.shouldShowIntroduction()) {
startActivity(new Intent(this, TrackListActivity.class));
finish();
}
viewBinding.nextButton.setOnClickListener(v -> {
int nextItemId = viewBinding.introductionViewPager.getCurrentItem() + 1;
if (nextItemId < viewBinding.introductionViewPager.getAdapter().getItemCount()) {
viewBinding.introductionViewPager.setCurrentItem(nextItemId);
} else {
PreferencesUtils.setShowIntroduction(false);
startActivity(IntentUtils.newIntent(this, TrackListActivity.class));
finish();
}
});
viewBinding.introductionViewPager.setAdapter(new CustomFragmentPagerAdapter(this));
viewBinding.introductionViewPager.setUserInputEnabled(false);
}
@Override
protected View getRootView() {
viewBinding = IntroductionBinding.inflate(getLayoutInflater());
return viewBinding.getRoot();
}
@Override
protected void onDestroy() {
super.onDestroy();
viewBinding = null;
}
private static class CustomFragmentPagerAdapter extends FragmentStateAdapter {
private static final List<FragmentCreator> fragmentCreators = List.of(
(FragmentCreator) WelcomeFragment::newInstance,
(FragmentCreator) OSMDashboardFragment::newInstance
);
public CustomFragmentPagerAdapter(@NonNull FragmentActivity fa) {
super(fa);
}
@NonNull
@Override
public Fragment createFragment(int position) {
FragmentCreator fc = fragmentCreators.get(position);
if (fc != null) {
return fc.newInstance();
}
throw new RuntimeException("There isn't Fragment associated with the position: " + position);
}
@Override
public int getItemCount() {
return fragmentCreators.size();
}
}
private interface FragmentCreator {
Fragment newInstance();
}
}
@@ -0,0 +1,32 @@
package de.dennisguse.opentracks.introduction;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import de.dennisguse.opentracks.databinding.OsmDashboardBinding;
public class OSMDashboardFragment extends Fragment {
public static OSMDashboardFragment newInstance() {
return new OSMDashboardFragment();
}
private OsmDashboardBinding viewBinding;
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
viewBinding = OsmDashboardBinding.inflate(inflater, container, false);
return viewBinding.getRoot();
}
@Override
public void onDestroy() {
super.onDestroy();
viewBinding = null;
}
}
@@ -0,0 +1,37 @@
package de.dennisguse.opentracks.introduction;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import de.dennisguse.opentracks.databinding.WelcomeBinding;
public class WelcomeFragment extends Fragment {
public static WelcomeFragment newInstance() {
return new WelcomeFragment();
}
private WelcomeBinding viewBinding;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
viewBinding = WelcomeBinding.inflate(inflater, container, false);
return viewBinding.getRoot();
}
@Override
public void onDestroy() {
super.onDestroy();
viewBinding = null;
}
}
@@ -197,6 +197,14 @@ public class PreferencesUtils {
return getBoolean(R.string.publicapi_dashboard_enabled_key, resources.getBoolean(R.bool.publicapi_dashboard_enabled_default));
}
public static boolean shouldShowIntroduction() {
return getBoolean(R.string.show_introduction_screen_key, resources.getBoolean(R.bool.show_introduction_screen_default));
}
public static void setShowIntroduction(boolean introduction) {
setBoolean(R.string.show_introduction_screen_key, introduction);
}
public static UnitSystem getUnitSystem() {
final String STATS_UNIT_DEFAULT = resources.getString(R.string.stats_units_default);
@@ -0,0 +1,39 @@
<vector android:height="24dp" android:viewportHeight="108"
android:viewportWidth="108" android:width="24dp"
xmlns:aapt="http://schemas.android.com/aapt" xmlns:android="http://schemas.android.com/apk/res/android">
<group>
<path android:fillColor="#808080"
android:pathData="m0,-0c36,0 72,0 108,0 0,36 0,72 0,108 -36,0 -72,0 -108,0 0,-36 0,-72 0,-108z"
android:strokeColor="#00000000"
android:strokeLineJoin="round" android:strokeWidth="1.165"/>
</group>
<group>
<path android:fillColor="#ffffff" android:fillType="nonZero"
android:pathData="m95.219,-10.07c-38.179,14.319 -76.358,28.638 -114.537,42.957 0.964,2.651 1.928,5.301 2.892,7.952 38.179,-14.319 76.358,-28.638 114.537,-42.957 -0.964,-2.651 -1.928,-5.301 -2.892,-7.952z"
android:strokeColor="#00000000" android:strokeLineCap="butt"
android:strokeLineJoin="miter" android:strokeWidth="1.86967"/>
</group>
<group>
<path android:fillColor="#ffffff" android:fillType="nonZero"
android:pathData="m32.694,14.99c-1.335,2.636 -2.671,5.272 -4.006,7.908 35.607,18.661 71.214,37.322 106.82,55.984 1.335,-2.633 2.671,-5.266 4.006,-7.899 -35.607,-18.664 -71.214,-37.328 -106.82,-55.993z"
android:strokeColor="#00000000" android:strokeLineCap="butt"
android:strokeLineJoin="miter" android:strokeWidth="1.96044"/>
</group>
<group>
<path android:fillColor="#ffffff" android:fillType="nonZero"
android:pathData="m92.049,51.041c-22.717,26.392 -45.434,52.784 -68.151,79.176 2.113,1.883 4.227,3.766 6.34,5.65 22.72,-26.395 45.44,-52.79 68.159,-79.185 -2.116,-1.88 -4.233,-3.761 -6.349,-5.641z"
android:strokeColor="#00000000" android:strokeLineCap="butt"
android:strokeLineJoin="miter" android:strokeWidth="1.89063"/>
</group>
<path
android:pathData="M87.636,20.525C88.234,18.481 87.258,17.751 85.467,18.903L26.377,56.902c-1.791,1.152 -1.519,2.224 0.604,2.382L51.522,61.114c2.124,0.159 4.477,1.918 5.229,3.91l8.7,23.021c0.753,1.992 1.857,1.949 2.455,-0.094z"
android:strokeColor="#f69123" android:strokeWidth="1">
<aapt:attr name="android:fillColor">
<gradient android:endX="86.99409" android:endY="19.146372"
android:startX="41.27608" android:startY="80.26603" android:type="linear">
<item android:color="#FFFBB22F" android:offset="0"/>
<item android:color="#FFF58820" android:offset="1"/>
</gradient>
</aapt:attr>
</path>
</vector>
+26
View File
@@ -0,0 +1,26 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/introduction_view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/next_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentBottom="true"
android:layout_marginEnd="20dp"
android:layout_marginBottom="90dp"
app:borderWidth="0dp"
app:srcCompat="@android:drawable/ic_media_play"
app:tint="@android:color/white"
tools:ignore="RedundantDescriptionCheck,ImageContrastCheck" />
</RelativeLayout>
+22
View File
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ImageView
android:layout_width="match_parent"
android:layout_height="200dp"
android:layout_marginTop="75dp"
android:layout_marginBottom="10dp"
android:src="@drawable/osmdashboard_ic_logo_color_24dp" />
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="@string/introduction_osm_dashboard"
android:textSize="30sp"
android:layout_gravity="center"
android:gravity="center_horizontal"/>
</LinearLayout>
+22
View File
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ImageView
android:layout_width="match_parent"
android:layout_height="200dp"
android:layout_marginTop="75dp"
android:layout_marginBottom="10dp"
android:src="@drawable/ic_logo_color_24dp" />
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="@string/about_description"
android:textSize="30sp"
android:layout_gravity="center"
android:gravity="center_horizontal"/>
</LinearLayout>
+3
View File
@@ -322,6 +322,9 @@
<string name="publicapi_dashboard_enabled_key" translatable="false">apiDashboardEnabledKey</string>
<bool name="publicapi_dashboard_enabled_default">false</bool>
<string name="show_introduction_screen_key">showIntroduction</string>
<bool name="show_introduction_screen_default">true</bool>
<!-- androidx.appcompat.app.AppCompatDelegate.setDefaultNightMode() -->
<string name="night_mode_key" translatable="false">nightMode</string>
<string name="night_mode_default" translatable="false">@string/night_mode_system_value</string>
+2
View File
@@ -669,4 +669,6 @@ limitations under the License.
<string name="show_on_dashboard">OpenTracks Dashboard API</string>
<string name="show_on_dashboard_not_installed">No application supporting OpenTracks Dashboard API installed.</string>
<string name="always">Always</string>
<string name="introduction_osm_dashboard">OpenTracks itself does not provide a map. Please install OSMDashboard to view your recordings on a map.</string>
</resources>