Parcourir la source

feat 使用单活动+nivagation架构

RobinTan1024 il y a 4 ans
Parent
commit
d024ff79ee

+ 6 - 0
app/build.gradle

@@ -43,6 +43,7 @@ dependencies {
     implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
     implementation 'androidx.core:core-ktx:1.3.2'
     implementation 'androidx.appcompat:appcompat:1.2.0'
+    // implementation "androidx.fragment:fragment-ktx:1.3.0-beta02"
     implementation 'com.google.android.material:material:1.2.1'
     implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
     implementation 'androidx.preference:preference-ktx:1.1.1'
@@ -50,6 +51,11 @@ dependencies {
     androidTestImplementation 'androidx.test.ext:junit:1.1.2'
     androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
 
+    def nav_version = "2.3.2"
+    implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
+    implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
+    // implementation "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version"
+
     implementation project(':waynelib_')
 
     def retrofitVersion = '2.9.0'

+ 1 - 6
app/src/main/AndroidManifest.xml

@@ -17,18 +17,13 @@
         android:roundIcon="@mipmap/ic_launcher_round"
         android:supportsRtl="true"
         android:theme="@style/Theme.Issp">
-        <activity
-            android:name=".view.SettingsActivity"
-            android:label="@string/preference" />
-        <activity
-            android:name=".view.LoginActivity">
+        <activity android:name=".view.MainActivity">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
 
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
         </activity>
-        <activity android:name=".view.MainActivity" />
 
         <provider
             android:name="androidx.startup.InitializationProvider"

+ 1 - 0
app/src/main/java/com/doverfuelingsolutions/issp/data/DataStore.kt

@@ -3,6 +3,7 @@ package com.doverfuelingsolutions.issp.data
 import com.doverfuelingsolutions.issp.utils.DeviceUtil
 import com.doverfuelingsolutions.issp.utils.sp.SPKeys
 import com.doverfuelingsolutions.issp.utils.sp.SPUtil
+import kotlin.properties.ObservableProperty
 
 object DataStore {
 

+ 1 - 1
app/src/main/java/com/doverfuelingsolutions/issp/utils/PermissionUtil.kt

@@ -16,7 +16,7 @@ class PermissionUtil {
             Manifest.permission.WRITE_EXTERNAL_STORAGE,
         )
 
-        fun hasPermissions(context: Context): Boolean {
+        private fun hasPermissions(context: Context): Boolean {
             return permissions.all {
                 ContextCompat.checkSelfPermission(context, it) == PackageManager.PERMISSION_GRANTED
             }

+ 0 - 99
app/src/main/java/com/doverfuelingsolutions/issp/view/LoginActivity.kt

@@ -1,99 +0,0 @@
-package com.doverfuelingsolutions.issp.view
-
-import android.content.pm.PackageManager
-import android.os.Bundle
-import android.view.View
-import androidx.appcompat.app.AppCompatActivity
-import androidx.databinding.DataBindingUtil
-import androidx.lifecycle.MutableLiveData
-import androidx.lifecycle.ViewModel
-import androidx.lifecycle.lifecycleScope
-import com.doverfuelingsolutions.issp.R
-import com.doverfuelingsolutions.issp.api.CloudApi
-import com.doverfuelingsolutions.issp.data.DataStore
-import com.doverfuelingsolutions.issp.databinding.ActivityLoginBinding
-import com.doverfuelingsolutions.issp.utils.PermissionUtil
-import com.doverfuelingsolutions.issp.utils.StringUtil
-import com.google.android.material.snackbar.Snackbar
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.launch
-
-class LoginActivity : AppCompatActivity(), View.OnClickListener {
-
-    private lateinit var activityLoginBinding: ActivityLoginBinding
-    private val mainViewModel = MainViewModel()
-
-    private val snackbar: Snackbar by lazy {
-        Snackbar.make(activityLoginBinding.loginForm, "", 4000)
-            .apply { anchorView = activityLoginBinding.loginForm }
-    }
-
-    override fun onCreate(savedInstanceState: Bundle?) {
-        super.onCreate(savedInstanceState)
-        activityLoginBinding = DataBindingUtil.setContentView(this, R.layout.activity_login)
-        activityLoginBinding.lifecycleOwner = this
-        initView()
-        autoLogin()
-
-        PermissionUtil.requestPermissions(this)
-    }
-
-    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
-        if (grantResults.contains(PackageManager.PERMISSION_DENIED)) {
-            finish()
-        }
-    }
-
-    override fun onClick(v: View?) {
-        when (v) {
-            activityLoginBinding.buttonLogin -> submit()
-            activityLoginBinding.buttonPreference -> SettingsActivity.start(this)
-        }
-    }
-
-    private fun initView() {
-        activityLoginBinding.mainViewModel = mainViewModel
-        activityLoginBinding.buttonLogin.setOnClickListener(this)
-        activityLoginBinding.buttonPreference.setOnClickListener(this)
-
-        mainViewModel.accountName.value = DataStore.accountName
-        mainViewModel.password.value = DataStore.password
-    }
-
-    private fun autoLogin() {
-        if (DataStore.accountName.isNotEmpty() && DataStore.password.isNotEmpty()) submit()
-    }
-
-    private fun submit() {
-        if (mainViewModel.submitting.value == true) {
-            return
-        }
-
-        lifecycleScope.launch {
-            mainViewModel.submitting.value = true
-            val accountName = mainViewModel.accountName.value?.trim()
-            val password = mainViewModel.password.value?.trim()
-            when {
-                accountName.isNullOrBlank() || password.isNullOrBlank() -> snackbar.setText(R.string.input_not_right).show()
-                else -> {
-                    val result = CloudApi.login(accountName, password)
-                    if (!result.success) snackbar.setText(StringUtil.get(R.string.login_fail, result.message)).show()
-                    else {
-                        MainActivity.start(this@LoginActivity)
-                        finish()
-                        return@launch
-                    }
-                }
-            }
-            mainViewModel.submitting.value = false
-        }
-    }
-
-    class MainViewModel : ViewModel() {
-        val accountName = MutableLiveData<String>()
-        val password = MutableLiveData<String>()
-        
-        val submitting = MutableLiveData<Boolean>()
-    }
-}

+ 8 - 66
app/src/main/java/com/doverfuelingsolutions/issp/view/MainActivity.kt

@@ -2,56 +2,26 @@ package com.doverfuelingsolutions.issp.view
 
 import android.content.Context
 import android.content.Intent
-import android.net.Uri
 import android.os.Bundle
-import android.view.View
 import androidx.appcompat.app.AppCompatActivity
-import androidx.databinding.DataBindingUtil
-import androidx.fragment.app.add
 import androidx.lifecycle.MutableLiveData
 import androidx.lifecycle.ViewModel
-import androidx.lifecycle.lifecycleScope
 import com.doverfuelingsolutions.issp.R
 import com.doverfuelingsolutions.issp.data.DataStore
-import com.doverfuelingsolutions.issp.databinding.ActivityMainBinding
-import com.doverfuelingsolutions.issp.fusion.FusionManager
 import com.doverfuelingsolutions.issp.utils.ActivityUtil
-import com.doverfuelingsolutions.issp.view.fragment.SearchTypeFragment
-import com.doverfuelingsolutions.issp.view.fragment.SettingsFragment
-import com.youth.banner.adapter.BannerImageAdapter
-import com.youth.banner.holder.BannerImageHolder
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Dispatchers
-import java.io.File
+import com.doverfuelingsolutions.issp.utils.PermissionUtil
 
-class MainActivity : AppCompatActivity(), View.OnClickListener {
+class MainActivity : AppCompatActivity() {
 
-    companion object {
-
-        fun start(context: Context) {
-            context.startActivity(Intent(context, MainActivity::class.java))
-        }
-    }
-
-    private lateinit var activityMainBinding: ActivityMainBinding
-    private val mainViewModel = MainViewModel()
+    private val globalViewModel = GlobalViewModel()
 
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
-        activityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main)
-        activityMainBinding.lifecycleOwner = this
-        activityMainBinding.mainViewModel = mainViewModel
-
-        activityMainBinding.stationLogo.setImageURI(Uri.fromFile(File(filesDir, DataStore.stationLogoFile)))
-        mainViewModel.stationName.value = DataStore.buName
+        setContentView(R.layout.activity_main)
 
-        initBanner()
+        PermissionUtil.requestPermissions(this)
 
-        lifecycle.addObserver(FusionManager)
-
-        supportFragmentManager.beginTransaction()
-            .add(R.id.mainFragment, SearchTypeFragment())
-            .commit()
+        // lifecycle.addObserver(FusionManager)
     }
 
     override fun onResume() {
@@ -59,36 +29,8 @@ class MainActivity : AppCompatActivity(), View.OnClickListener {
         ActivityUtil.setFullscreen(this)
     }
 
-    override fun onClick(v: View?) {
-        when (v) {
-            activityMainBinding.textClock -> {
-                supportFragmentManager.beginTransaction()
-                    .add(R.id.mainFragment, SettingsFragment())
-                    .addToBackStack(SettingsFragment::class.java.simpleName)
-                    .commit()
-            }
-        }
-    }
-
-    private fun initBanner() {
-        activityMainBinding.banner.run {
-            addBannerLifecycleObserver(this@MainActivity)
-            scrollTime = 500
-            adapter =
-                object : BannerImageAdapter<Int>(listOf(R.mipmap.banner_1, R.mipmap.banner_2)) {
-                    override fun onBindView(
-                        holder: BannerImageHolder,
-                        data: Int,
-                        position: Int,
-                        size: Int
-                    ) {
-                        holder.imageView.setImageResource(data)
-                    }
-                }
-        }
-    }
+    class GlobalViewModel : ViewModel() {
 
-    class MainViewModel : ViewModel() {
-        val stationName = MutableLiveData<String>()
+        val isLogin = MutableLiveData(System.currentTimeMillis() < DataStore.accessTokenExpire) // TODO 确认TOKEN过期处理办法
     }
 }

+ 82 - 0
app/src/main/java/com/doverfuelingsolutions/issp/view/fragment/FragmentLogin.kt

@@ -0,0 +1,82 @@
+package com.doverfuelingsolutions.issp.view.fragment
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.databinding.DataBindingUtil
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.activityViewModels
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.lifecycleScope
+import androidx.navigation.fragment.findNavController
+import com.doverfuelingsolutions.issp.R
+import com.doverfuelingsolutions.issp.api.CloudApi
+import com.doverfuelingsolutions.issp.data.DataStore
+import com.doverfuelingsolutions.issp.databinding.FragmentLoginBinding
+import com.doverfuelingsolutions.issp.utils.StringUtil
+import com.doverfuelingsolutions.issp.view.MainActivity
+import com.google.android.material.snackbar.Snackbar
+import kotlinx.coroutines.launch
+
+class FragmentLogin : Fragment(), View.OnClickListener {
+
+    private val globalViewModel: MainActivity.GlobalViewModel by activityViewModels()
+    private val loginViewModel = LoginViewModel()
+
+    private lateinit var binding: FragmentLoginBinding
+    private val snackbar: Snackbar by lazy {
+        Snackbar.make(binding.loginForm, "", 4000)
+            .apply { anchorView = binding.loginForm }
+    }
+
+    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
+        binding = DataBindingUtil.inflate(inflater, R.layout.fragment_login, container, false)
+        binding.lifecycleOwner = this
+        binding.viewModel = loginViewModel
+        return binding.root
+    }
+
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        binding.buttonLogin.setOnClickListener(this)
+        binding.buttonPreference.setOnClickListener(this)
+        loginViewModel.accountName.value = DataStore.accountName
+        loginViewModel.password.value = DataStore.password
+    }
+
+    override fun onClick(v: View?) {
+        when (v) {
+            binding.buttonLogin -> submit()
+            binding.buttonPreference -> {}
+        }
+    }
+
+    private fun submit() {
+        if (loginViewModel.submitting.value == true) return
+
+        lifecycleScope.launch {
+            loginViewModel.submitting.value = true
+            val accountName = loginViewModel.accountName.value?.trim()
+            val password = loginViewModel.password.value?.trim()
+            when {
+                accountName.isNullOrBlank() || password.isNullOrBlank() -> snackbar.setText(R.string.input_not_right).show()
+                else -> {
+                    val result = CloudApi.login(accountName, password)
+                    if (!result.success) snackbar.setText(StringUtil.get(R.string.login_fail, result.message)).show()
+                    else {
+                        globalViewModel.isLogin.value = true
+                        findNavController().navigate(R.id.action_login_to_main)
+                    }
+                }
+            }
+            loginViewModel.submitting.value = false
+        }
+    }
+
+    class LoginViewModel : ViewModel() {
+        val accountName = MutableLiveData("")
+        val password = MutableLiveData("")
+        val submitting = MutableLiveData(false)
+    }
+}

+ 65 - 0
app/src/main/java/com/doverfuelingsolutions/issp/view/fragment/FragmentMain.kt

@@ -0,0 +1,65 @@
+package com.doverfuelingsolutions.issp.view.fragment
+
+import android.net.Uri
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.databinding.DataBindingUtil
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.activityViewModels
+import androidx.fragment.app.viewModels
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import androidx.navigation.fragment.findNavController
+import com.doverfuelingsolutions.issp.R
+import com.doverfuelingsolutions.issp.data.DataStore
+import com.doverfuelingsolutions.issp.databinding.FragmentMainBinding
+import com.doverfuelingsolutions.issp.view.MainActivity
+import com.youth.banner.adapter.BannerImageAdapter
+import com.youth.banner.holder.BannerImageHolder
+import java.io.File
+
+class FragmentMain : Fragment() {
+
+    private val globalViewModel: MainActivity.GlobalViewModel by activityViewModels()
+    private val mainViewModel: MainViewModel by viewModels()
+
+    private lateinit var binding: FragmentMainBinding
+
+    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
+        binding = DataBindingUtil.inflate(inflater, R.layout.fragment_main, container, false)
+        binding.lifecycleOwner = this
+        binding.mainViewModel = mainViewModel
+        return binding.root
+    }
+
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        // Destination will only be joined in back stack after it's resumed.
+        // Navigate before that resume looks like redirect.
+        if (globalViewModel.isLogin.value != true) {
+            findNavController().navigate(R.id.action_main_to_login)
+            return
+        }
+
+        binding.stationLogo.setImageURI(Uri.fromFile(File(context?.filesDir, DataStore.stationLogoFile)))
+        initBanner()
+    }
+
+    private fun initBanner() {
+        binding.banner.run {
+            addBannerLifecycleObserver(this@FragmentMain)
+            scrollTime = 500
+            adapter =
+                object : BannerImageAdapter<Int>(listOf(R.mipmap.banner_1, R.mipmap.banner_2)) {
+                    override fun onBindView(holder: BannerImageHolder, data: Int, position: Int, size: Int) {
+                        holder.imageView.setImageResource(data)
+                    }
+                }
+        }
+    }
+
+    class MainViewModel : ViewModel() {
+        val stationName = MutableLiveData(DataStore.buName)
+    }
+}

+ 64 - 0
app/src/main/java/com/doverfuelingsolutions/issp/view/fragment/FragmentSearchType.kt

@@ -0,0 +1,64 @@
+package com.doverfuelingsolutions.issp.view.fragment
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.databinding.DataBindingUtil
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.activityViewModels
+import androidx.fragment.app.viewModels
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import com.doverfuelingsolutions.issp.DFSApplication
+import com.doverfuelingsolutions.issp.R
+import com.doverfuelingsolutions.issp.data.DataStore
+import com.doverfuelingsolutions.issp.databinding.FragmentSearchTypeBinding
+import com.doverfuelingsolutions.issp.utils.log.DFSLog
+import com.doverfuelingsolutions.issp.view.MainActivity
+
+class FragmentSearchType : Fragment(), View.OnClickListener, View.OnLongClickListener {
+
+    private val globalViewModel: MainActivity.GlobalViewModel by activityViewModels()
+    private val viewModel: SearchTypeViewModel by viewModels()
+
+    private lateinit var binding: FragmentSearchTypeBinding
+
+    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
+        binding = DataBindingUtil.inflate(inflater, R.layout.fragment_search_type, container, false)
+        binding.lifecycleOwner = this
+        binding.viewModel = viewModel
+        return binding.root
+    }
+
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        binding.chooseOil.setOnClickListener(this)
+        binding.chooseNozzle.setOnClickListener(this)
+        binding.versionNum.setOnLongClickListener(this)
+    }
+
+    override fun onClick(v: View?) {
+        when (v) {
+            binding.chooseNozzle -> DFSLog.i("chooseNozzle")
+            binding.chooseOil -> DFSLog.i("chooseOil")
+        }
+    }
+
+    override fun onLongClick(v: View?): Boolean {
+        when (v) {
+            binding.versionNum -> {
+            }
+            else -> return false
+        }
+        return true
+    }
+
+    class SearchTypeViewModel : ViewModel() {
+        val deviceNum = MutableLiveData(DataStore.sn)
+        val version: MutableLiveData<String> by lazy {
+            val pm = DFSApplication.instance.applicationContext.packageManager
+            val info = pm.getPackageInfo(DFSApplication.instance.applicationContext.packageName, android.content.pm.PackageManager.GET_ACTIVITIES)
+            MutableLiveData(info.versionName)
+        }
+    }
+}

+ 0 - 20
app/src/main/java/com/doverfuelingsolutions/issp/view/fragment/SearchTypeFragment.kt

@@ -1,20 +0,0 @@
-package com.doverfuelingsolutions.issp.view.fragment
-
-import android.os.Bundle
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import androidx.databinding.DataBindingUtil
-import androidx.fragment.app.Fragment
-import com.doverfuelingsolutions.issp.R
-import com.doverfuelingsolutions.issp.databinding.FragmentSearchTypeBinding
-
-class SearchTypeFragment : Fragment() {
-
-    private lateinit var binding: FragmentSearchTypeBinding
-
-    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
-        binding = DataBindingUtil.inflate(inflater, R.layout.fragment_search_type, container, false)
-        return binding.root
-    }
-}

+ 16 - 78
app/src/main/res/layout/activity_main.xml

@@ -1,81 +1,19 @@
 <?xml version="1.0" encoding="utf-8"?>
-<layout xmlns:android="http://schemas.android.com/apk/res/android"
+<androidx.constraintlayout.widget.ConstraintLayout 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">
-
-    <data>
-
-        <variable
-            name="mainViewModel"
-            type="com.doverfuelingsolutions.issp.view.MainActivity.MainViewModel" />
-    </data>
-
-    <LinearLayout
+    xmlns:tools="http://schemas.android.com/tools"
+    style="@style/match"
+    android:background="@mipmap/activity_background"
+    tools:context=".view.MainActivity">
+
+    <androidx.fragment.app.FragmentContainerView
+        android:id="@+id/navActivity"
+        android:name="androidx.navigation.fragment.NavHostFragment"
         style="@style/match"
-        android:background="@mipmap/activity_background"
-        android:orientation="vertical"
-        android:focusable="true"
-        android:focusableInTouchMode="true"
-        tools:context=".view.MainActivity">
-
-        <LinearLayout
-            style="@style/fullWidth"
-            android:layout_marginStart="30dp"
-            android:layout_marginEnd="30dp"
-            android:gravity="center_vertical"
-            android:orientation="horizontal"
-            android:weightSum="1">
-
-            <ImageView
-                android:id="@+id/stationLogo"
-                android:layout_width="100dp"
-                android:layout_height="100dp"
-                android:contentDescription="@string/app_name"
-                android:src="@mipmap/launcher" />
-
-            <TextView
-                android:layout_width="0dp"
-                android:layout_height="wrap_content"
-                android:layout_marginStart="30dp"
-                android:layout_weight="1"
-                android:text="@{ mainViewModel.stationName, default=@string/example_company_name }"
-                android:textColor="@color/color333"
-                android:textSize="32sp" />
-
-            <ImageView
-                android:layout_width="32dp"
-                android:layout_height="32dp"
-                android:background="@drawable/ic_time"
-                android:contentDescription="@string/app_name" />
-
-            <TextClock
-                android:id="@+id/textClock"
-                style="@style/wrap"
-                android:layout_marginStart="8dp"
-                android:format12Hour="@string/format_date"
-                android:format24Hour="@string/format_date"
-                android:text="@string/example_format_date"
-                android:textColor="@color/color555"
-                android:textSize="26sp" />
-        </LinearLayout>
-
-        <LinearLayout
-            style="@style/match"
-            android:orientation="vertical"
-            android:weightSum="3">
-
-            <com.youth.banner.Banner
-                android:id="@+id/banner"
-                android:layout_width="match_parent"
-                app:banner_loop_time="7000"
-                android:layout_height="0dp"
-                android:layout_weight="1" />
-
-            <RelativeLayout
-                android:id="@+id/mainFragment"
-                android:layout_width="match_parent"
-                android:layout_height="0dp"
-                android:layout_weight="2" />
-        </LinearLayout>
-    </LinearLayout>
-</layout>
+        app:defaultNavHost="true"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        app:navGraph="@navigation/nav_activity" />
+</androidx.constraintlayout.widget.ConstraintLayout>

+ 9 - 9
app/src/main/res/layout/activity_login.xml → app/src/main/res/layout/fragment_login.xml

@@ -6,8 +6,8 @@
     <data>
 
         <variable
-            name="mainViewModel"
-            type="com.doverfuelingsolutions.issp.view.LoginActivity.MainViewModel" />
+            name="viewModel"
+            type="com.doverfuelingsolutions.issp.view.fragment.FragmentLogin.LoginViewModel" />
     </data>
 
     <androidx.constraintlayout.widget.ConstraintLayout
@@ -40,9 +40,9 @@
 
                 <com.google.android.material.textfield.TextInputEditText
                     style="@style/fullWidth"
-                    android:enabled="@{ !mainViewModel.submitting }"
+                    android:enabled="@{ !viewModel.submitting }"
                     android:inputType="text"
-                    android:text="@={ mainViewModel.accountName }" />
+                    android:text="@={ viewModel.accountName }" />
 
             </com.google.android.material.textfield.TextInputLayout>
 
@@ -58,9 +58,9 @@
 
                 <com.google.android.material.textfield.TextInputEditText
                     style="@style/fullWidth"
-                    android:enabled="@{ !mainViewModel.submitting }"
+                    android:enabled="@{ !viewModel.submitting }"
                     android:inputType="textPassword"
-                    android:text="@={ mainViewModel.password }" />
+                    android:text="@={ viewModel.password }" />
 
             </com.google.android.material.textfield.TextInputLayout>
 
@@ -69,8 +69,8 @@
                 style="@style/Widget.MaterialComponents.Button"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
-                android:enabled="@{ !mainViewModel.submitting }"
-                android:text="@{ mainViewModel.submitting ? @string/in_login : @string/login }" />
+                android:enabled="@{ !viewModel.submitting }"
+                android:text="@{ viewModel.submitting ? @string/in_login : @string/login }" />
         </LinearLayout>
 
         <Button
@@ -80,7 +80,7 @@
             android:layout_height="wrap_content"
             android:layout_marginTop="40dp"
             android:layout_marginEnd="40dp"
-            android:enabled="@{!mainViewModel.submitting}"
+            android:enabled="@{!viewModel.submitting}"
             android:text="@string/preference"
             app:layout_constraintEnd_toEndOf="parent"
             app:layout_constraintTop_toTopOf="parent" />

+ 84 - 0
app/src/main/res/layout/fragment_main.xml

@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layout 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">
+
+    <data>
+
+        <variable
+            name="mainViewModel"
+            type="com.doverfuelingsolutions.issp.view.fragment.FragmentMain.MainViewModel" />
+    </data>
+
+    <LinearLayout
+        style="@style/match"
+        android:background="@mipmap/activity_background"
+        android:focusable="true"
+        android:focusableInTouchMode="true"
+        android:orientation="vertical"
+        android:paddingTop="4dp"
+        tools:context=".view.MainActivity">
+
+        <LinearLayout
+            style="@style/fullWidth"
+            android:layout_marginStart="30dp"
+            android:layout_marginEnd="30dp"
+            android:gravity="center_vertical"
+            android:orientation="horizontal"
+            android:weightSum="1">
+
+            <ImageView
+                android:id="@+id/stationLogo"
+                android:layout_width="100dp"
+                android:layout_height="100dp"
+                android:contentDescription="@string/app_name"
+                android:src="@mipmap/launcher" />
+
+            <TextView
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_marginStart="30dp"
+                android:layout_weight="1"
+                android:text="@{mainViewModel.stationName, default=@string/example_company_name}"
+                android:textColor="@color/color333"
+                android:textSize="32sp" />
+
+            <ImageView
+                android:layout_width="32dp"
+                android:layout_height="32dp"
+                android:background="@drawable/ic_time"
+                android:contentDescription="@string/app_name" />
+
+            <TextClock
+                android:id="@+id/textClock"
+                style="@style/wrap"
+                android:layout_marginStart="8dp"
+                android:format12Hour="@string/format_date"
+                android:format24Hour="@string/format_date"
+                android:text="@string/example_format_date"
+                android:textColor="@color/color555"
+                android:textSize="26sp" />
+        </LinearLayout>
+
+        <LinearLayout
+            style="@style/match"
+            android:orientation="vertical"
+            android:weightSum="3">
+
+            <com.youth.banner.Banner
+                android:id="@+id/banner"
+                android:layout_width="match_parent"
+                android:layout_height="0dp"
+                android:layout_weight="1"
+                app:banner_loop_time="7000" />
+
+            <androidx.fragment.app.FragmentContainerView
+                android:id="@+id/navMain"
+                android:name="androidx.navigation.fragment.NavHostFragment"
+                android:layout_width="match_parent"
+                android:layout_height="0dp"
+                android:layout_weight="2"
+                app:navGraph="@navigation/nav_main" />
+        </LinearLayout>
+    </LinearLayout>
+</layout>

+ 12 - 7
app/src/main/res/layout/fragment_search_type.xml

@@ -4,13 +4,16 @@
 
     <data>
 
+        <variable
+            name="viewModel"
+            type="com.doverfuelingsolutions.issp.view.fragment.FragmentSearchType.SearchTypeViewModel" />
     </data>
 
     <androidx.constraintlayout.widget.ConstraintLayout
         style="@style/match"
-        android:paddingStart="50dp"
-        android:paddingEnd="50dp"
-        android:paddingTop="40dp"
+        android:paddingStart="60dp"
+        android:paddingTop="60dp"
+        android:paddingEnd="60dp"
         android:paddingBottom="140dp">
 
         <TextView
@@ -31,12 +34,14 @@
             app:layout_constraintTop_toBottomOf="@id/mainTip">
 
             <ImageView
+                android:id="@+id/chooseNozzle"
                 android:layout_width="500dp"
                 android:layout_height="427dp"
-                android:contentDescription="@string/select_oil"
+                android:contentDescription="@string/select_nozzle"
                 android:src="@mipmap/choose_nozzle" />
 
             <ImageView
+                android:id="@+id/chooseOil"
                 android:layout_width="500dp"
                 android:layout_height="427dp"
                 android:layout_marginStart="30dp"
@@ -74,8 +79,8 @@
                 android:id="@+id/deviceNum"
                 style="@style/wrap"
                 android:layout_marginStart="30dp"
-                android:layout_marginTop="30dp"
-                android:text="@string/device_num_is"
+                android:layout_marginTop="50dp"
+                android:text="@{@string/device_num_is(viewModel.deviceNum), default=@string/device_num_is}"
                 android:textSize="28sp"
                 app:layout_constraintStart_toStartOf="@id/mainAttention"
                 app:layout_constraintTop_toBottomOf="@id/mainAttention" />
@@ -85,7 +90,7 @@
                 style="@style/wrap"
                 android:layout_marginStart="30dp"
                 android:layout_marginTop="20dp"
-                android:text="@string/version_is"
+                android:text="@{@string/version_is(viewModel.version), default=@string/version_is}"
                 android:textSize="28sp"
                 app:layout_constraintStart_toStartOf="@id/mainAttention"
                 app:layout_constraintTop_toBottomOf="@id/deviceNum" />

+ 25 - 0
app/src/main/res/navigation/nav_activity.xml

@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<navigation 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:id="@+id/nav_main"
+    app:startDestination="@id/activityMain">
+
+    <fragment
+        android:id="@+id/activityMain"
+        android:name="com.doverfuelingsolutions.issp.view.fragment.FragmentMain"
+        android:label="@string/app_name">
+        <action
+            android:id="@+id/action_main_to_login"
+            app:destination="@id/activityLogin" />
+    </fragment>
+
+    <fragment
+        android:id="@+id/activityLogin"
+        android:name="com.doverfuelingsolutions.issp.view.fragment.FragmentLogin"
+        android:label="@string/login">
+        <action
+            android:id="@+id/action_login_to_main"
+            app:destination="@id/activityMain" />
+    </fragment>
+</navigation>

+ 13 - 0
app/src/main/res/navigation/nav_main.xml

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<navigation 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:id="@+id/nav_main"
+    app:startDestination="@id/mainSelect">
+
+    <fragment
+        android:id="@+id/mainSelect"
+        android:name="com.doverfuelingsolutions.issp.view.fragment.FragmentSearchType"
+        android:label="@string/app_name">
+    </fragment>
+</navigation>